././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1693927301.7286294 webrtc-audio-processing-1.3/0000755000175000017500000000000014475643606014667 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/.gitignore0000664000175000017500000000012214475643423016651 0ustar00arunarun*.o *.pc .*.swp *~ .deps* .dirstamp .libs* build/ depcomp install/ subprojects/*/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/.gitlab-ci.yml0000664000175000017500000002406314475643423017327 0ustar00arunarun# The build has two stages. The 'container' stage is used to build a Docker # container and push it to the project's container registry on fd.o GitLab. # This step is only run when the tag for the container changes, else it is # effectively a no-op. All of this infrastructure is inherited from the # wayland/ci-templates repository which is the recommended way to set up CI # infrastructure on fd.o GitLab. # # Once the container stage is done, we move on to the 'build' stage where we # run an autotools and meson build in parallel. Currently, tests are also run # as part of the build stage as there doesn't seem to be significant value to # splitting the stages at the moment. stages: - container - build variables: # Update this tag when you want to trigger a rebuild the container in which # CI runs, for example when adding new packages to FDO_DISTRIBUTION_PACKAGES. # The tag is an arbitrary string that identifies the exact container # contents. BASE_TAG: '2023-05-25.0' FDO_DISTRIBUTION_VERSION: '22.10' FDO_UPSTREAM_REPO: 'pulseaudio/webrtc-audio-processing' include: # We pull templates from master to avoid the overhead of periodically # scanning for changes upstream. This does means builds might occasionally # break due to upstream changing things, so if you see unexpected build # failures, this might be one cause. - project: 'freedesktop/ci-templates' ref: 'master' file: '/templates/ubuntu.yml' # Common container build template .ubuntu-container-build: variables: GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image # Remember to update FDO_DISTRIBUTION_TAG when modifying this package list! # Otherwise the changes won't have effect since an old container image will # be used. FDO_DISTRIBUTION_PACKAGES: >- g++ gcc git-core cmake libabsl-dev meson ninja-build pkg-config python3-setuptools # Used to extend both container and build jobs .ubuntu-x86_64: variables: FDO_DISTRIBUTION_TAG: "x86_64-$BASE_TAG" # Used to extend both container and build jobs .ubuntu-aarch64: tags: - aarch64 variables: FDO_DISTRIBUTION_TAG: "aarch64-$BASE_TAG" build-container-x86_64: extends: - .fdo.container-build@ubuntu@x86_64 - .ubuntu-container-build - .ubuntu-x86_64 stage: container build-container-aarch64: extends: - .fdo.container-build@ubuntu@aarch64 - .ubuntu-container-build - .ubuntu-aarch64 stage: container # Common build template .build-distro-absl: stage: build extends: - .fdo.distribution-image@ubuntu script: - meson setup --wrap-mode=nofallback --prefix=/usr --libdir=lib builddir - ninja -C builddir - DESTDIR=$PWD/_install ninja install -C builddir # Test that the pc files are usable - PKG_CONFIG_PATH=$PWD/_install/usr/lib/pkgconfig pkg-config --cflags --libs webrtc-audio-processing-1 - PKG_CONFIG_PATH=$PWD/_install/usr/lib/pkgconfig pkg-config --cflags --libs webrtc-audio-coding-1 artifacts: expire_in: '5 days' when: 'always' paths: - "builddir/meson-logs/*txt" .build-vendored-absl: stage: build extends: - .fdo.distribution-image@ubuntu script: - meson setup --force-fallback-for=abseil-cpp --prefix=/usr --libdir=lib builddir - ninja -C builddir - DESTDIR=$PWD/_install ninja install -C builddir # Test that the pc files are usable - PKG_CONFIG_LIBDIR=$PWD/_install/usr/lib/pkgconfig pkg-config --cflags --libs webrtc-audio-processing-1 - PKG_CONFIG_LIBDIR=$PWD/_install/usr/lib/pkgconfig pkg-config --cflags --libs webrtc-audio-coding-1 artifacts: expire_in: '5 days' when: 'always' paths: - "builddir/meson-logs/*txt" build-distro-absl-x86_64: extends: - .build-distro-absl - .ubuntu-x86_64 build-vendored-absl-x86_64: extends: - .build-vendored-absl - .ubuntu-x86_64 build-distro-absl-aarch64: extends: - .build-distro-absl - .ubuntu-aarch64 build-vendored-absl-aarch64: extends: - .build-vendored-absl - .ubuntu-aarch64 # Update from: # https://gitlab.freedesktop.org/gstreamer/gstreamer/-/blob/main/.gitlab-ci.yml # https://gitlab.freedesktop.org/gstreamer/orc/-/blob/main/.gitlab-ci.yml vs2019 amd64: # Update from https://gitlab.freedesktop.org/gstreamer/gstreamer/container_registry image: 'registry.freedesktop.org/gstreamer/gstreamer/amd64/windows:2023-04-21.0-main' stage: 'build' tags: - 'docker' - 'windows' - '2022' artifacts: expire_in: '5 days' when: 'always' paths: - "builddir/meson-logs/*txt" variables: # Make sure any failure in PowerShell scripts is fatal ErrorActionPreference: 'Stop' WarningPreference: 'Stop' ARCH: 'amd64' PLAT: 'Desktop' before_script: # Make sure meson is up to date, so we don't need to rebuild the image with each release - pip3 install -U meson ninja script: # Gitlab executes PowerShell in docker, but VsDevCmd.bat is a batch script. # Environment variables substitutions is done by PowerShell before calling # cmd.exe, that's why we use $env:FOO instead of %FOO% - cmd.exe /C "C:\BuildTools\Common7\Tools\VsDevCmd.bat -host_arch=amd64 -arch=$env:ARCH -app_platform=$env:PLAT && meson setup builddir && meson compile --verbose -C builddir" # Update from: # https://gitlab.freedesktop.org/gstreamer/cerbero/-/blob/main/.gitlab-ci.yml # https://gitlab.freedesktop.org/gstreamer/orc/-/blob/main/.gitlab-ci.yml macos x86_64: stage: 'build' tags: - gst-macos-13 artifacts: expire_in: '5 days' when: 'always' paths: - "builddir/meson-logs/*txt" before_script: - pip3 install --upgrade pip # Need to install certificates for python - pip3 install --upgrade certifi # Anther way to install certificates - open /Applications/Python\ 3.8/Install\ Certificates.command # Make sure meson and ninja are up to date - pip3 install -U meson ninja script: - CERT_PATH=$(python3 -m certifi) && export SSL_CERT_FILE=${CERT_PATH} && export REQUESTS_CA_BUNDLE=${CERT_PATH} - meson setup builddir - meson compile --verbose -C builddir # Update from: # https://gitlab.freedesktop.org/gstreamer/cerbero/-/blob/main/.gitlab-ci.yml # https://gitlab.freedesktop.org/gstreamer/orc/-/blob/main/.gitlab-ci.yml ios arm64: stage: 'build' tags: - gst-ios-16 artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_SHA}" expire_in: '5 days' when: 'always' paths: - "builddir/meson-logs/*txt" before_script: - pip3 install --upgrade pip # Need to install certificates for python - pip3 install --upgrade certifi # Anther way to install certificates - open /Applications/Python\ 3.8/Install\ Certificates.command # Make sure meson and ninja are up to date - pip3 install -U meson ninja script: - CERT_PATH=$(python3 -m certifi) && export SSL_CERT_FILE=${CERT_PATH} && export REQUESTS_CA_BUNDLE=${CERT_PATH} - | cat > ios-cross-file.txt < android-cross-file.txt < Google Inc. # autofoo-based build system Arun Raghavan ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/COPYING0000664000175000017500000000272714475643423015731 0ustar00arunarunCopyright (c) 2011, Google Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/ChangeLog0000664000175000017500000000000014475643423016426 0ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/INSTALL0000664000175000017500000003633214475643423015726 0ustar00arunarunInstallation Instructions ************************* Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell commands `./configure; make; make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the `README' file for instructions specific to this package. Some packages provide this `INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. Running `configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 4. Type `make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the `make install' phase executed with root privileges. 5. Optionally, type `make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior `make install' required root privileges, verifies that the installation completed correctly. 6. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 7. Often, you can also type `make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide `make distcheck', which can by used by developers to test that all other targets like `make install' and `make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. This is known as a "VPATH" build. With a non-GNU `make', it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple `-arch' options to the compiler but only a single `-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the `lipo' tool if you have problems. Installation Names ================== By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option `--exec-prefix=PREFIX' to `configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of `${prefix}', so that specifying just `--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to `configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the `make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, `make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of `${prefix}'. Any directories that were specified during `configure', but not in terms of `${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the `DESTDIR' variable. For example, `make install DESTDIR=/alternate/directory' will prepend `/alternate/directory' before all installation names. The approach of `DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of `${prefix}' at `configure' time. Optional Features ================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Some packages offer the ability to configure how verbose the execution of `make' will be. For these packages, running `./configure --enable-silent-rules' sets the default to minimal output, which can be overridden with `make V=1'; while running `./configure --disable-silent-rules' sets the default to verbose, which can be overridden with `make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its `' header file. The option `-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put `/usr/ucb' early in your `PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in `/usr/bin'. So, if you need `/usr/ucb' in your `PATH', put it _after_ `/usr/bin'. On Haiku, software installed for all users goes in `/boot/common', not `/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for `CONFIG_SHELL' due to an Autoconf bug. Until the bug is fixed you can use this workaround: CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of all of the options to `configure', and exit. `--help=short' `--help=recursive' Print a summary of the options unique to this package's `configure', and exit. The `short' variant lists options used only in the top level, while the `recursive' variant lists options also present in any nested packages. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. `--no-create' `-n' Run the configure checks, but stop before creating any output files. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/NEWS0000664000175000017500000000353414475643423015372 0ustar00arunarunRelease 0.3 ----------- Minor build fixes. Release 0.2 ----------- Updated AudioProcessing code to be more current. Contains API breaking changes. Upstream changes include: * Rewritten AGC and voice activity detection * Intelligibility enhancer * Extended AEC filter * Beamformer * Transient suppressor * ARM, NEON and MIPS optimisations (MIPS optimisations are not hooked up) API changes: * We no longer include a top-level audio_processing.h. The webrtc tree format is used, so use webrtc/modules/audio_processing/include/audio_processing.h * The top-level module_common_types.h has also been moved to webrtc/modules/interface/module_common_types.h * C++11 support is now required while compiling client code * AudioProcessing::Create() does not take any arguments any more * AudioProcessing::Destroy() is gone, use standard C++ "delete" instead * Stream parameters are now configured via StreamConfig and ProcessingConfig rather than set_sample_rate(), set_num_channels(), etc. * AudioFrame field names have changed * Use config API for newer audio processing options * Use ProcessReverseStream() instead of AnalyzeReverseStream(), particularly when using the intelligibility enhancer * GainControl::set_analog_level_limits() is broken. The AGC implementation hard codes 0-255 as the volume range Other notes: * The new audio processing parameters are not all tested, and a few are not enabled upstream (in Chromium) either * The rewritten AGC appears to be less sensitive, and it might make sense to initialise the capture volume to something reasonable (33% or 50%, for example) to make sure there is sufficient energy in the stream to trigger the AGC mechanism Release 0.1 ----------- Initial release, consisting of the WebRTC AudioProcessing module with a distributor-friendly build system. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/README0000664000175000017500000000001614475643423015543 0ustar00arunarunSee README.md ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/README.md0000664000175000017500000000253614475643423016153 0ustar00arunarun# About This is meant to be a more Linux packaging friendly copy of the AudioProcessing module from the [ WebRTC ](https://webrtc.googlesource.com/src) project. The ideal case is that we make no changes to the code to make tracking upstream code easy. This package currently only includes the AudioProcessing bits, but I am very open to collaborating with other projects that wish to distribute other bits of the code and hopefully eventually have a single point of packaging all the WebRTC code to help people reuse the code and avoid keeping private copies in several different projects. # Building This project uses the [Meson build system](https://mesonbuild.com/). The quickest way to build is: ```sh # Initialise into the build/ directory, for a prefixed install into the # install/ directory meson . build -Dprefix=$PWD/install # Run the actual build ninja -C build # Install locally ninja -C build install # The libraries, headers, and pkg-config files are now in the install/ # directory ``` # Feedback Patches, suggestions welcome. You can file an issue on our Gitlab [repository](https://gitlab.freedesktop.org/pulseaudio/webrtc-audio-processing/). # Notes 1. It might be nice to try LTO on the library. We build a lot of code as part of the main AudioProcessing module deps, and it's possible that this could provide significant space savings. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/RELEASING.md0000664000175000017500000000252214475643423016522 0ustar00arunarun# Release process ## Update the code Follow the instructions in `UPDATING.md` to update the code. ## Update the package version If there is no API breakage, update the minor version (X.y -> X.y+1). If there is API breakage, update the major version (X.y -> X+1.0). ## Make sure builds are successful on all platforms There is CI for `x86_64` and `aarch64` builds, but 32-bit ARM and MIPS builds need manual verfification (or testing downstream). ## Tag the release Tag the release with: ```sh git tag -s -m 'WebRTC AudioProcessing v' v ``` ## Make a tarball ```sh # The output will be in build/meson-dist/ meson dist -C build --formats=gztar,xztar --include-subprojects ``` ## Do a test build ```sh tar xvf webrtc-audio-processing-X.y.tar.xz cd webrtc-audio-processing-X.y meson . build -Dprefix=$PWD/install ninja -C build ninja -C build install cd .. ``` ## Publish the files ```sh scp webrtc-audio-processing-*.tar.* \ annarchy.freedesktop.org:/srv/www.freedesktop.org/www/software/pulseaudio/webrtc-audio-processing/ ``` ## Push the tag ```sh git push origin master git push origin vX.y ``` ## Update the website This is currently an embarrassing manual process. ## Send out a release announcement This goes to the `pulseaudio-discuss` and `gstreamer-devel` mailing lists, and possibly `discuss-webrtc` if it seems relevant. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/UPDATING.md0000664000175000017500000000542214475643423016426 0ustar00arunarunUpdating ===== Assembling some quick notes on maintaining this tree vs. the upstream WebRTC project source code. 1. The code is currently synced agains whatever revision of the upstream webrtc git repository Chromium uses. 2. Instructions on checking out the Chromium tree are on the [WebRTC repo][get-webrtc]. As a shortcut, you can look at the DEPS file in the Chromium tree for the current webrtc version being used, and then just use that commit hash with the webrtc tree. 3. [Meld][meld] is a great tool for diffing two directories. Start by running it on ```webrtc-audio-processing/webrtc``` and ```chromium/third_party/webrtc```. * For each directory in the ```webrtc-audio-processing``` tree, go over the corresponding code in the ```chromium``` tree. * Examine changed files, and pick any new changes. A small number of files in the ```webrtc-audio-processing``` tree have been changed by hand, make sure that those are not overwritten. * unittest files have been left out since they are not built or used. * BUILD.gn files have been copied to keep track of changes to the build system upstreama. * Arch-specific files usually have special handling in the corresponding meson.build. 4. Once everything has been copied and updated, everything needs to be built. Missing dependencies (files that were not copied, or new modules that are being depended on) will first turn up here. * Copy new deps as needed, leaving out testing-only dependencies insofar as this is possible. 5. ```webrtc/modules/audio_processing/include/audio_processing.h``` is the main include file, so look for API changes here. * The current policy is that we mirror upstream API as-is. * Update soversion in meson.build with the appropriate version info based on how the code has changed. Details on how to do this are included in the [libtool documentation][libtool-version-info]. 5. Build PulseAudio (and/or any other dependent projects) against the new code. The easy way to do this is via a prefixed install. * Configure webrtc-audio-processing with ```meson build -D prefix=$(pwd)/install```, then do a ```ninja -C build/ install``` * Configure PulseAudio with ```meson build -D pkg_config_path=/path/to/webrtc-audio-processing/install/lib64/pkgconfig/```, which will cause the build to pick up the prefixed install. Then do a ```ninja -C build```, run the built PulseAudio, and load ```module-echo-cancel``` to make sure it loads fine. * Run some test streams through the canceller to make sure it is working fine. [get-webrtc]: https://webrtc.googlesource.com/src/ [meld]: http://meldmerge.org/ [libtool-version-info]: https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/meson.build0000664000175000017500000001373014475643423017034 0ustar00arunarunproject('webrtc-audio-processing', 'c', 'cpp', version : '1.3', meson_version : '>= 0.63', default_options : [ 'warning_level=1', 'buildtype=debugoptimized', 'c_std=c11', 'cpp_std=c++17', ] ) version_split = meson.project_version().split('.') # This will be incremented each time a breaking API change occurs major_version = version_split[0] # This will be incremented when there are backwards-compatible changes minor_version = version_split[1] # We maintain per-package versions to not have to break API for one if only the # other has breaking changes apm_major_version = major_version apm_minor_version = minor_version apm_project_name = 'webrtc-audio-processing-' + apm_major_version ac_major_version = major_version ac_minor_version = minor_version ac_project_name = 'webrtc-audio-coding-' + ac_major_version include_subdir = apm_project_name cc = meson.get_compiler('c') cpp = meson.get_compiler('cpp') host_system = host_machine.system() # Don't rely on the cross file setting the system properly when targeting ios if host_system == 'darwin' and meson.is_cross_build() ios_test_code = '''#include #if ! TARGET_OS_IPHONE #error "Not iOS/tvOS/watchOS/iPhoneSimulator" #endif''' if cc.compiles(ios_test_code, name : 'building for iOS') host_system = 'ios' endif endif platform_cflags = [] os_cflags = [] os_deps = [] have_posix = false have_win = false # Let's use pkg-config if available. This will also fallback to the subproject # if pkg-config is not found, which is really the most reliable way of building # abseil due to strict C++ standard match requirements. absl_dep = [ dependency('absl_base', default_options: ['cpp_std=c++17']), dependency('absl_flags'), dependency('absl_strings'), dependency('absl_synchronization'), dependency('absl_bad_optional_access'), ] if absl_dep[0].type_name() == 'internal' absl_subproj = subproject('abseil-cpp') headers = [ absl_subproj.get_variable('absl_base_headers'), absl_subproj.get_variable('absl_flags_headers'), absl_subproj.get_variable('absl_strings_headers'), absl_subproj.get_variable('absl_synchronization_headers'), absl_subproj.get_variable('absl_types_headers'), ] install_headers(headers, preserve_path: true) pc_requires = [] else pc_requires = [absl_dep[0]] endif if ['darwin', 'ios'].contains(host_system) os_cflags = ['-DWEBRTC_MAC'] if host_system == 'ios' os_cflags += ['-DWEBRTC_IOS'] endif have_posix = true elif host_system == 'android' os_cflags += ['-DWEBRTC_ANDROID', '-DWEBRTC_LINUX'] os_deps += [cc.find_library('log')] os_deps += [dependency('gnustl', required : get_option('gnustl'))] have_posix = true elif host_system == 'linux' os_cflags += ['-DWEBRTC_LINUX', '-DWEBRTC_THREAD_RR'] os_deps += [cc.find_library('rt', required : false)] os_deps += [dependency('threads')] have_posix = true elif host_system == 'windows' platform_cflags += ['-DWEBRTC_WIN', '-D_WIN32', '-U__STRICT_ANSI__'] # this one is for MinGW to get format specifiers from inttypes.h in C++ platform_cflags += ['-D__STDC_FORMAT_MACROS=1'] # Avoid min/max from windows.h which breaks std::min/max platform_cflags += ['-DNOMINMAX'] # Ensure M_PI etc are defined platform_cflags += ['-D_USE_MATH_DEFINES'] os_deps += [cc.find_library('winmm')] have_win = true endif if have_posix platform_cflags += ['-DWEBRTC_POSIX'] endif arch_cflags = [] have_arm = false have_armv7 = false have_neon = false have_mips = false have_mips64 = false have_x86 = false have_avx2 = false if host_machine.cpu_family() == 'arm' if cc.compiles('''#ifndef __ARM_ARCH_ISA_ARM #error no arm arch #endif''') have_arm = true arch_cflags += ['-DWEBRTC_ARCH_ARM'] endif if cc.compiles('''#ifndef __ARM_ARCH_7A__ #error no armv7 arch #endif''') have_armv7 = true arch_cflags += ['-DWEBRTC_ARCH_ARM_V7'] endif endif if cc.compiles('''#ifndef __aarch64__ #error no aarch64 arch #endif''') have_neon = true arch_cflags += ['-DWEBRTC_ARCH_ARM64', '-DWEBRTC_HAS_NEON'] endif if ['mips', 'mips64'].contains(host_machine.cpu_family()) have_mips = true arch_cflags += ['WEBRTC_ARCH_MIPS_FAMILY'] endif if host_machine.cpu_family() == 'mips64' have_mips64 = true endif if ['x86', 'x86_64'].contains(host_machine.cpu_family()) have_x86 = true # This is unconditionally enabled for now, actual usage is determined by # runtime CPU detection, so we're just assuming the compiler supports avx2 have_avx2 = true arch_cflags += ['-DWEBRTC_ENABLE_AVX2'] endif neon_opt = get_option('neon') if neon_opt != 'no' and not have_neon if neon_opt != 'runtime' if cc.compiles('#include ', args : '-mfpu=neon') arch_cflags += ['-mfpu=neon', '-DWEBRTC_HAS_NEON'] have_neon = true endif else arch_cflags += ['-DWEBRTC_DETECT_NEON', '-mfpu=neon'] have_neon = true endif endif common_cflags = [ '-DWEBRTC_LIBRARY_IMPL', '-DWEBRTC_ENABLE_SYMBOL_EXPORT', '-DNDEBUG' ] + platform_cflags + os_cflags + arch_cflags common_cxxflags = common_cflags common_deps = os_deps + [absl_dep] webrtc_inc = include_directories('.') subdir('webrtc') pkgconfig = import('pkgconfig') pkgconfig.generate( libwebrtc_audio_processing, description: 'WebRTC Audio Processing library', subdirs: include_subdir, requires: pc_requires, extra_cflags: [ '-DWEBRTC_LIBRARY_IMPL', ] + platform_cflags, ) audio_processing_dep = declare_dependency( link_with: libwebrtc_audio_processing, dependencies: [absl_dep], include_directories: [webrtc_inc] ) meson.override_dependency(apm_project_name, audio_processing_dep) pkgconfig.generate( libwebrtc_audio_coding, description: 'WebRTC Audio Coding library', subdirs: include_subdir, extra_cflags: [ '-DWEBRTC_LIBRARY_IMPL', ] + platform_cflags, ) audio_coding_dep = declare_dependency( link_with: libwebrtc_audio_coding, include_directories: [webrtc_inc] ) meson.override_dependency(ac_project_name, audio_coding_dep) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/meson_options.txt0000664000175000017500000000037214475643423020325 0ustar00arunarunoption('gnustl', type: 'feature', value: 'auto', description: 'Use gnustl for a c++ library implementation (only used on Android)') option('neon', type: 'combo', choices: ['no', 'yes', 'auto', 'runtime'], description: '') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/subprojects/0000775000175000017500000000000014475643423017231 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/subprojects/abseil-cpp.wrap0000664000175000017500000000656114475643423022153 0ustar00arunarun[wrap-file] directory = abseil-cpp-20230125.1 source_url = https://github.com/abseil/abseil-cpp/archive/20230125.1.tar.gz source_filename = abseil-cpp-20230125.1.tar.gz source_hash = 81311c17599b3712069ded20cca09a62ab0bf2a89dfa16993786c8782b7ed145 patch_filename = abseil-cpp_20230125.1-4_patch.zip patch_url = https://wrapdb.mesonbuild.com/v2/abseil-cpp_20230125.1-4/get_patch patch_hash = 112ee72052049d930396c2778fc1c6e184137905dd75d60a97dcfc386426610d source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/abseil-cpp_20230125.1-4/abseil-cpp-20230125.1.tar.gz wrapdb_version = 20230125.1-4 [provide] absl_base = absl_base_dep absl_container = absl_container_dep absl_debugging = absl_debugging_dep absl_log = absl_log_dep absl_flags = absl_flags_dep absl_hash = absl_hash_dep absl_crc = absl_crc_dep absl_numeric = absl_numeric_dep absl_profiling = absl_profiling_dep absl_random = absl_random_dep absl_status = absl_status_dep absl_strings = absl_strings_dep absl_synchronization = absl_synchronization_dep absl_time = absl_time_dep absl_types = absl_types_dep absl_bad_any_cast_impl = absl_types_dep absl_bad_optional_access = absl_types_dep absl_bad_variant_access = absl_types_dep absl_city = absl_hash_dep absl_civil_time = absl_time_dep absl_cord = absl_strings_dep absl_cord_internal = absl_strings_dep absl_cordz_functions = absl_strings_dep absl_cordz_handle = absl_strings_dep absl_cordz_info = absl_strings_dep absl_cordz_sample_token = absl_strings_dep absl_debugging_internal = absl_debugging_dep absl_demangle_internal = absl_debugging_dep absl_examine_stack = absl_debugging_dep absl_exponential_biased = absl_profiling_dep absl_failure_signal_handler = absl_debugging_dep absl_flags_commandlineflag = absl_flags_dep absl_flags_commandlineflag_internal = absl_flags_dep absl_flags_config = absl_flags_dep absl_flags_internal = absl_flags_dep absl_flags_marshalling = absl_flags_dep absl_flags_parse = absl_flags_dep absl_flags_private_handle_accessor = absl_flags_dep absl_flags_program_name = absl_flags_dep absl_flags_reflection = absl_flags_dep absl_flags_usage = absl_flags_dep absl_flags_usage_internal = absl_flags_dep absl_graphcycles_internal = absl_synchronization_dep absl_hashtablez_sampler = absl_container_dep absl_int128 = absl_numeric_dep absl_leak_check = absl_debugging_dep absl_log_severity = absl_base_dep absl_low_level_hash = absl_hash_dep absl_periodic_sampler = absl_profiling_dep absl_random_distributions = absl_random_dep absl_random_internal_distribution_test_util = absl_random_dep absl_random_internal_platform = absl_random_dep absl_random_internal_pool_urbg = absl_random_dep absl_random_internal_randen = absl_random_dep absl_random_internal_randen_hwaes = absl_random_dep absl_random_internal_randen_hwaes_impl = absl_random_dep absl_random_internal_randen_slow = absl_random_dep absl_random_internal_seed_material = absl_random_dep absl_random_seed_gen_exception = absl_random_dep absl_random_seed_sequences = absl_random_dep absl_raw_hash_set = absl_container_dep absl_raw_logging_internal = absl_base_dep absl_scoped_set_env = absl_base_dep absl_spinlock_wait = absl_base_dep absl_stacktrace = absl_debugging_dep absl_statusor = absl_status_dep absl_strerror = absl_base_dep absl_str_format_internal = absl_strings_dep absl_strings_internal = absl_strings_dep absl_symbolize = absl_debugging_dep absl_throw_delegate = absl_base_dep absl_time_zone = absl_time_dep ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/0000775000175000017500000000000014475643423016154 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/BUILD.gn0000664000175000017500000005051514475643423017347 0ustar00arunarun# Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. # This is the root build file for GN. GN will start processing by loading this # file, and recursively load all dependencies until all dependencies are either # resolved or known not to exist (which will cause the build to fail). So if # you add a new build file, there must be some path of dependencies from this # file to your new one or GN won't know about it. import("//build/config/linux/pkg_config.gni") import("//build/config/sanitizers/sanitizers.gni") import("webrtc.gni") if (rtc_enable_protobuf) { import("//third_party/protobuf/proto_library.gni") } if (is_android) { import("//build/config/android/config.gni") import("//build/config/android/rules.gni") } if (!build_with_chromium) { # This target should (transitively) cause everything to be built; if you run # 'ninja default' and then 'ninja all', the second build should do no work. group("default") { testonly = true deps = [ ":webrtc" ] if (rtc_build_examples) { deps += [ "examples" ] } if (rtc_build_tools) { deps += [ "rtc_tools" ] } if (rtc_include_tests) { deps += [ ":rtc_unittests", ":slow_tests", ":video_engine_tests", ":voip_unittests", ":webrtc_nonparallel_tests", ":webrtc_perf_tests", "common_audio:common_audio_unittests", "common_video:common_video_unittests", "examples:examples_unittests", "media:rtc_media_unittests", "modules:modules_tests", "modules:modules_unittests", "modules/audio_coding:audio_coding_tests", "modules/audio_processing:audio_processing_tests", "modules/remote_bitrate_estimator:rtp_to_text", "modules/rtp_rtcp:test_packet_masks_metrics", "modules/video_capture:video_capture_internal_impl", "pc:peerconnection_unittests", "pc:rtc_pc_unittests", "rtc_tools:rtp_generator", "rtc_tools:video_replay", "stats:rtc_stats_unittests", "system_wrappers:system_wrappers_unittests", "test", "video:screenshare_loopback", "video:sv_loopback", "video:video_loopback", ] if (!is_asan) { # Do not build :webrtc_lib_link_test because lld complains on some OS # (e.g. when target_os = "mac") when is_asan=true. For more details, # see bugs.webrtc.org/11027#c5. deps += [ ":webrtc_lib_link_test" ] } if (is_android) { deps += [ "examples:android_examples_junit_tests", "sdk/android:android_instrumentation_test_apk", "sdk/android:android_sdk_junit_tests", ] } else { deps += [ "modules/video_capture:video_capture_tests" ] } if (rtc_enable_protobuf) { deps += [ "audio:low_bandwidth_audio_test", "logging:rtc_event_log_rtp_dump", "tools_webrtc/perf:webrtc_dashboard_upload", ] } } } } # Abseil Flags by default doesn't register command line flags on mobile # platforms, WebRTC tests requires them (e.g. on simualtors) so this # config will be applied to testonly targets globally (see webrtc.gni). config("absl_flags_configs") { defines = [ "ABSL_FLAGS_STRIP_NAMES=0" ] } config("library_impl_config") { # Build targets that contain WebRTC implementation need this macro to # be defined in order to correctly export symbols when is_component_build # is true. # For more info see: rtc_base/build/rtc_export.h. defines = [ "WEBRTC_LIBRARY_IMPL" ] } # Contains the defines and includes in common.gypi that are duplicated both as # target_defaults and direct_dependent_settings. config("common_inherited_config") { defines = [] cflags = [] ldflags = [] if (rtc_enable_symbol_export || is_component_build) { defines = [ "WEBRTC_ENABLE_SYMBOL_EXPORT" ] } if (build_with_mozilla) { defines += [ "WEBRTC_MOZILLA_BUILD" ] } if (!rtc_builtin_ssl_root_certificates) { defines += [ "WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS" ] } if (rtc_disable_check_msg) { defines += [ "RTC_DISABLE_CHECK_MSG" ] } if (rtc_enable_avx2) { defines += [ "WEBRTC_ENABLE_AVX2" ] } # Some tests need to declare their own trace event handlers. If this define is # not set, the first time TRACE_EVENT_* is called it will store the return # value for the current handler in an static variable, so that subsequent # changes to the handler for that TRACE_EVENT_* will be ignored. # So when tests are included, we set this define, making it possible to use # different event handlers in different tests. if (rtc_include_tests) { defines += [ "WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS=1" ] } else { defines += [ "WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS=0" ] } if (build_with_chromium) { defines += [ "WEBRTC_CHROMIUM_BUILD" ] include_dirs = [ # The overrides must be included first as that is the mechanism for # selecting the override headers in Chromium. "../webrtc_overrides", # Allow includes to be prefixed with webrtc/ in case it is not an # immediate subdirectory of the top-level. ".", # Just like the root WebRTC directory is added to include path, the # corresponding directory tree with generated files needs to be added too. # Note: this path does not change depending on the current target, e.g. # it is always "//gen/third_party/webrtc" when building with Chromium. # See also: http://cs.chromium.org/?q=%5C"default_include_dirs # https://gn.googlesource.com/gn/+/master/docs/reference.md#target_gen_dir target_gen_dir, ] } if (is_posix || is_fuchsia) { defines += [ "WEBRTC_POSIX" ] } if (is_ios) { defines += [ "WEBRTC_MAC", "WEBRTC_IOS", ] } if (is_linux || is_chromeos) { defines += [ "WEBRTC_LINUX" ] } if (is_mac) { defines += [ "WEBRTC_MAC" ] } if (is_fuchsia) { defines += [ "WEBRTC_FUCHSIA" ] } if (is_win) { defines += [ "WEBRTC_WIN" ] } if (is_android) { defines += [ "WEBRTC_LINUX", "WEBRTC_ANDROID", ] if (build_with_mozilla) { defines += [ "WEBRTC_ANDROID_OPENSLES" ] } } if (is_chromeos) { defines += [ "CHROMEOS" ] } if (rtc_sanitize_coverage != "") { assert(is_clang, "sanitizer coverage requires clang") cflags += [ "-fsanitize-coverage=${rtc_sanitize_coverage}" ] ldflags += [ "-fsanitize-coverage=${rtc_sanitize_coverage}" ] } if (is_ubsan) { cflags += [ "-fsanitize=float-cast-overflow" ] } } # TODO(bugs.webrtc.org/9693): Remove the possibility to suppress this warning # as soon as WebRTC compiles without it. config("no_exit_time_destructors") { if (is_clang) { cflags = [ "-Wno-exit-time-destructors" ] } } # TODO(bugs.webrtc.org/9693): Remove the possibility to suppress this warning # as soon as WebRTC compiles without it. config("no_global_constructors") { if (is_clang) { cflags = [ "-Wno-global-constructors" ] } } config("rtc_prod_config") { # Ideally, WebRTC production code (but not test code) should have these flags. if (is_clang) { cflags = [ "-Wexit-time-destructors", "-Wglobal-constructors", ] } } config("common_config") { cflags = [] cflags_c = [] cflags_cc = [] cflags_objc = [] defines = [] if (rtc_enable_protobuf) { defines += [ "WEBRTC_ENABLE_PROTOBUF=1" ] } else { defines += [ "WEBRTC_ENABLE_PROTOBUF=0" ] } if (rtc_include_internal_audio_device) { defines += [ "WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE" ] } if (rtc_libvpx_build_vp9) { defines += [ "RTC_ENABLE_VP9" ] } if (rtc_enable_sctp) { defines += [ "HAVE_SCTP" ] } if (rtc_enable_external_auth) { defines += [ "ENABLE_EXTERNAL_AUTH" ] } if (rtc_use_h264) { defines += [ "WEBRTC_USE_H264" ] } if (rtc_use_absl_mutex) { defines += [ "WEBRTC_ABSL_MUTEX" ] } if (rtc_disable_logging) { defines += [ "RTC_DISABLE_LOGGING" ] } if (rtc_disable_trace_events) { defines += [ "RTC_DISABLE_TRACE_EVENTS" ] } if (rtc_disable_metrics) { defines += [ "RTC_DISABLE_METRICS" ] } if (rtc_exclude_transient_suppressor) { defines += [ "WEBRTC_EXCLUDE_TRANSIENT_SUPPRESSOR" ] } if (rtc_exclude_audio_processing_module) { defines += [ "WEBRTC_EXCLUDE_AUDIO_PROCESSING_MODULE" ] } cflags = [] if (build_with_chromium) { defines += [ # NOTICE: Since common_inherited_config is used in public_configs for our # targets, there's no point including the defines in that config here. # TODO(kjellander): Cleanup unused ones and move defines closer to the # source when webrtc:4256 is completed. "HAVE_WEBRTC_VIDEO", "LOGGING_INSIDE_WEBRTC", ] } else { if (is_posix || is_fuchsia) { cflags_c += [ # TODO(bugs.webrtc.org/9029): enable commented compiler flags. # Some of these flags should also be added to cflags_objc. # "-Wextra", (used when building C++ but not when building C) # "-Wmissing-prototypes", (C/Obj-C only) # "-Wmissing-declarations", (ensure this is always used C/C++, etc..) "-Wstrict-prototypes", # "-Wpointer-arith", (ensure this is always used C/C++, etc..) # "-Wbad-function-cast", (C/Obj-C only) # "-Wnested-externs", (C/Obj-C only) ] cflags_objc += [ "-Wstrict-prototypes" ] cflags_cc = [ "-Wnon-virtual-dtor", # This is enabled for clang; enable for gcc as well. "-Woverloaded-virtual", ] } if (is_clang) { cflags += [ "-Wc++11-narrowing", "-Wimplicit-fallthrough", "-Wthread-safety", "-Winconsistent-missing-override", "-Wundef", ] # use_xcode_clang only refers to the iOS toolchain, host binaries use # chromium's clang always. if (!is_nacl && (!use_xcode_clang || current_toolchain == host_toolchain)) { # Flags NaCl (Clang 3.7) and Xcode 7.3 (Clang clang-703.0.31) do not # recognize. cflags += [ "-Wunused-lambda-capture" ] } } if (is_win && !is_clang) { # MSVC warning suppressions (needed to use Abseil). # TODO(bugs.webrtc.org/9274): Remove these warnings as soon as MSVC allows # external headers warning suppression (or fix them upstream). cflags += [ "/wd4702" ] # unreachable code # MSVC 2019 warning suppressions for C++17 compiling cflags += [ "/wd5041" ] # out-of-line definition for constexpr static data # member is not needed and is deprecated in C++17 } } if (current_cpu == "arm64") { defines += [ "WEBRTC_ARCH_ARM64" ] defines += [ "WEBRTC_HAS_NEON" ] } if (current_cpu == "arm") { defines += [ "WEBRTC_ARCH_ARM" ] if (arm_version >= 7) { defines += [ "WEBRTC_ARCH_ARM_V7" ] if (arm_use_neon) { defines += [ "WEBRTC_HAS_NEON" ] } } } if (current_cpu == "mipsel") { defines += [ "MIPS32_LE" ] if (mips_float_abi == "hard") { defines += [ "MIPS_FPU_LE" ] } if (mips_arch_variant == "r2") { defines += [ "MIPS32_R2_LE" ] } if (mips_dsp_rev == 1) { defines += [ "MIPS_DSP_R1_LE" ] } else if (mips_dsp_rev == 2) { defines += [ "MIPS_DSP_R1_LE", "MIPS_DSP_R2_LE", ] } } if (is_android && !is_clang) { # The Android NDK doesn"t provide optimized versions of these # functions. Ensure they are disabled for all compilers. cflags += [ "-fno-builtin-cos", "-fno-builtin-sin", "-fno-builtin-cosf", "-fno-builtin-sinf", ] } if (use_fuzzing_engine && optimize_for_fuzzing) { # Used in Chromium's overrides to disable logging defines += [ "WEBRTC_UNSAFE_FUZZER_MODE" ] } if (!build_with_chromium && rtc_win_undef_unicode) { cflags += [ "/UUNICODE", "/U_UNICODE", ] } } config("common_objc") { frameworks = [ "Foundation.framework" ] if (rtc_use_metal_rendering) { defines = [ "RTC_SUPPORTS_METAL" ] } } if (!build_with_chromium) { # Target to build all the WebRTC production code. rtc_static_library("webrtc") { # Only the root target and the test should depend on this. visibility = [ "//:default", "//:webrtc_lib_link_test", ] sources = [] complete_static_lib = true suppressed_configs += [ "//build/config/compiler:thin_archive" ] defines = [] deps = [ "api:create_peerconnection_factory", "api:libjingle_peerconnection_api", "api:rtc_error", "api:transport_api", "api/crypto", "api/rtc_event_log:rtc_event_log_factory", "api/task_queue", "api/task_queue:default_task_queue_factory", "audio", "call", "common_audio", "common_video", "logging:rtc_event_log_api", "media", "modules", "modules/video_capture:video_capture_internal_impl", "p2p:rtc_p2p", "pc:libjingle_peerconnection", "pc:peerconnection", "pc:rtc_pc", "pc:rtc_pc_base", "rtc_base", "sdk", "video", ] if (rtc_include_builtin_audio_codecs) { deps += [ "api/audio_codecs:builtin_audio_decoder_factory", "api/audio_codecs:builtin_audio_encoder_factory", ] } if (rtc_include_builtin_video_codecs) { deps += [ "api/video_codecs:builtin_video_decoder_factory", "api/video_codecs:builtin_video_encoder_factory", ] } if (build_with_mozilla) { deps += [ "api/video:video_frame", "api/video:video_rtp_headers", ] } else { deps += [ "api", "logging", "p2p", "pc", "stats", ] } if (rtc_enable_protobuf) { deps += [ "logging:rtc_event_log_proto" ] } } if (rtc_include_tests && !is_asan) { rtc_executable("webrtc_lib_link_test") { testonly = true sources = [ "webrtc_lib_link_test.cc" ] deps = [ # NOTE: Don't add deps here. If this test fails to link, it means you # need to add stuff to the webrtc static lib target above. ":webrtc", ] } } } if (use_libfuzzer || use_afl) { # This target is only here for gn to discover fuzzer build targets under # webrtc/test/fuzzers/. group("webrtc_fuzzers_dummy") { testonly = true deps = [ "test/fuzzers:webrtc_fuzzer_main" ] } } if (rtc_include_tests) { rtc_test("rtc_unittests") { testonly = true deps = [ "api:compile_all_headers", "api:rtc_api_unittests", "api/audio/test:audio_api_unittests", "api/audio_codecs/test:audio_codecs_api_unittests", "api/numerics:numerics_unittests", "api/transport:stun_unittest", "api/video/test:rtc_api_video_unittests", "api/video_codecs/test:video_codecs_api_unittests", "call:fake_network_pipe_unittests", "p2p:libstunprober_unittests", "p2p:rtc_p2p_unittests", "rtc_base:robo_caller_unittests", "rtc_base:rtc_base_approved_unittests", "rtc_base:rtc_base_unittests", "rtc_base:rtc_json_unittests", "rtc_base:rtc_numerics_unittests", "rtc_base:rtc_operations_chain_unittests", "rtc_base:rtc_task_queue_unittests", "rtc_base:sigslot_unittest", "rtc_base:untyped_function_unittest", "rtc_base:weak_ptr_unittests", "rtc_base/experiments:experiments_unittests", "rtc_base/synchronization:sequence_checker_unittests", "rtc_base/task_utils:pending_task_safety_flag_unittests", "rtc_base/task_utils:to_queued_task_unittests", "sdk:sdk_tests", "test:rtp_test_utils", "test:test_main", "test/network:network_emulation_unittests", ] if (rtc_enable_protobuf) { deps += [ "logging:rtc_event_log_tests" ] } if (is_android) { # Do not use Chromium's launcher. native_unittests defines its own JNI_OnLoad. use_default_launcher = false deps += [ "sdk/android:native_unittests", "sdk/android:native_unittests_java", "//testing/android/native_test:native_test_support", ] shard_timeout = 900 } if (is_ios || is_mac) { deps += [ "sdk:rtc_unittests_objc" ] } } rtc_test("benchmarks") { testonly = true deps = [ "rtc_base/synchronization:mutex_benchmark", "test:benchmark_main", ] } # This runs tests that must run in real time and therefore can take some # time to execute. They are in a separate executable to avoid making the # regular unittest suite too slow to run frequently. rtc_test("slow_tests") { testonly = true deps = [ "rtc_base/task_utils:repeating_task_unittests", "test:test_main", ] } # TODO(pbos): Rename test suite, this is no longer "just" for video targets. video_engine_tests_resources = [ "resources/foreman_cif_short.yuv", "resources/voice_engine/audio_long16.pcm", ] if (is_ios) { bundle_data("video_engine_tests_bundle_data") { testonly = true sources = video_engine_tests_resources outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ] } } rtc_test("video_engine_tests") { testonly = true deps = [ "audio:audio_tests", # TODO(eladalon): call_tests aren't actually video-specific, so we # should move them to a more appropriate test suite. "call:call_tests", "call/adaptation:resource_adaptation_tests", "test:test_common", "test:test_main", "test:video_test_common", "video:video_tests", "video/adaptation:video_adaptation_tests", ] data = video_engine_tests_resources if (is_android) { deps += [ "//testing/android/native_test:native_test_native_code" ] shard_timeout = 900 } if (is_ios) { deps += [ ":video_engine_tests_bundle_data" ] } } webrtc_perf_tests_resources = [ "resources/ConferenceMotion_1280_720_50.yuv", "resources/audio_coding/speech_mono_16kHz.pcm", "resources/audio_coding/speech_mono_32_48kHz.pcm", "resources/audio_coding/testfile32kHz.pcm", "resources/difficult_photo_1850_1110.yuv", "resources/foreman_cif.yuv", "resources/paris_qcif.yuv", "resources/photo_1850_1110.yuv", "resources/presentation_1850_1110.yuv", "resources/voice_engine/audio_long16.pcm", "resources/web_screenshot_1850_1110.yuv", ] if (is_ios) { bundle_data("webrtc_perf_tests_bundle_data") { testonly = true sources = webrtc_perf_tests_resources outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ] } } rtc_test("webrtc_perf_tests") { testonly = true deps = [ "audio:audio_perf_tests", "call:call_perf_tests", "modules/audio_coding:audio_coding_perf_tests", "modules/audio_processing:audio_processing_perf_tests", "pc:peerconnection_perf_tests", "test:test_main", "video:video_full_stack_tests", "video:video_pc_full_stack_tests", ] data = webrtc_perf_tests_resources if (is_android) { deps += [ "//testing/android/native_test:native_test_native_code" ] shard_timeout = 4500 } if (is_ios) { deps += [ ":webrtc_perf_tests_bundle_data" ] } } rtc_test("webrtc_nonparallel_tests") { testonly = true deps = [ "rtc_base:rtc_base_nonparallel_tests" ] if (is_android) { deps += [ "//testing/android/native_test:native_test_support" ] shard_timeout = 900 } } rtc_test("voip_unittests") { testonly = true deps = [ "api/voip:voip_engine_factory_unittests", "audio/voip/test:audio_channel_unittests", "audio/voip/test:audio_egress_unittests", "audio/voip/test:audio_ingress_unittests", "audio/voip/test:voip_core_unittests", "test:test_main", ] } } # ---- Poisons ---- # # Here is one empty dummy target for each poison type (needed because # "being poisonous with poison type foo" is implemented as "depends on # //:poison_foo"). # # The set of poison_* targets needs to be kept in sync with the # `all_poison_types` list in webrtc.gni. # group("poison_audio_codecs") { } group("poison_default_task_queue") { } group("poison_rtc_json") { } group("poison_software_video_codecs") { } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/LICENSE0000664000175000017500000000274714475643423017173 0ustar00arunarunCopyright (c) 2011, The WebRTC project authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/PATENTS0000664000175000017500000000255414475643423017223 0ustar00arunarunAdditional IP Rights Grant (Patents) "This implementation" means the copyrightable works distributed by Google as part of the WebRTC code package. Google hereby grants to you a perpetual, worldwide, non-exclusive, no-charge, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, transfer, and otherwise run, modify and propagate the contents of this implementation of the WebRTC code package, where such license applies only to those patent claims, both currently owned by Google and acquired in the future, licensable by Google that are necessarily infringed by this implementation of the WebRTC code package. This grant does not include claims that would be infringed only as a consequence of further modification of this implementation. If you or your agent or exclusive licensee institute or order or agree to the institution of patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that this implementation of the WebRTC code package or any code incorporated within this implementation of the WebRTC code package constitutes direct or contributory patent infringement, or inducement of patent infringement, then any patent rights granted to you under this License for this implementation of the WebRTC code package shall terminate as of the date such litigation is filed. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/0000775000175000017500000000000014475643423016725 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/array_view.h0000664000175000017500000002752614475643423021262 0ustar00arunarun/* * Copyright 2015 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_ARRAY_VIEW_H_ #define API_ARRAY_VIEW_H_ #include #include #include #include "rtc_base/checks.h" #include "rtc_base/type_traits.h" namespace rtc { // tl;dr: rtc::ArrayView is the same thing as gsl::span from the Guideline // Support Library. // // Many functions read from or write to arrays. The obvious way to do this is // to use two arguments, a pointer to the first element and an element count: // // bool Contains17(const int* arr, size_t size) { // for (size_t i = 0; i < size; ++i) { // if (arr[i] == 17) // return true; // } // return false; // } // // This is flexible, since it doesn't matter how the array is stored (C array, // std::vector, rtc::Buffer, ...), but it's error-prone because the caller has // to correctly specify the array length: // // Contains17(arr, arraysize(arr)); // C array // Contains17(arr.data(), arr.size()); // std::vector // Contains17(arr, size); // pointer + size // ... // // It's also kind of messy to have two separate arguments for what is // conceptually a single thing. // // Enter rtc::ArrayView. It contains a T pointer (to an array it doesn't // own) and a count, and supports the basic things you'd expect, such as // indexing and iteration. It allows us to write our function like this: // // bool Contains17(rtc::ArrayView arr) { // for (auto e : arr) { // if (e == 17) // return true; // } // return false; // } // // And even better, because a bunch of things will implicitly convert to // ArrayView, we can call it like this: // // Contains17(arr); // C array // Contains17(arr); // std::vector // Contains17(rtc::ArrayView(arr, size)); // pointer + size // Contains17(nullptr); // nullptr -> empty ArrayView // ... // // ArrayView stores both a pointer and a size, but you may also use // ArrayView, which has a size that's fixed at compile time (which means // it only has to store the pointer). // // One important point is that ArrayView and ArrayView are // different types, which allow and don't allow mutation of the array elements, // respectively. The implicit conversions work just like you'd hope, so that // e.g. vector will convert to either ArrayView or ArrayView, but const vector will convert only to ArrayView. // (ArrayView itself can be the source type in such conversions, so // ArrayView will convert to ArrayView.) // // Note: ArrayView is tiny (just a pointer and a count if variable-sized, just // a pointer if fix-sized) and trivially copyable, so it's probably cheaper to // pass it by value than by const reference. namespace impl { // Magic constant for indicating that the size of an ArrayView is variable // instead of fixed. enum : std::ptrdiff_t { kArrayViewVarSize = -4711 }; // Base class for ArrayViews of fixed nonzero size. template class ArrayViewBase { static_assert(Size > 0, "ArrayView size must be variable or non-negative"); public: ArrayViewBase(T* data, size_t size) : data_(data) {} static constexpr size_t size() { return Size; } static constexpr bool empty() { return false; } T* data() const { return data_; } protected: static constexpr bool fixed_size() { return true; } private: T* data_; }; // Specialized base class for ArrayViews of fixed zero size. template class ArrayViewBase { public: explicit ArrayViewBase(T* data, size_t size) {} static constexpr size_t size() { return 0; } static constexpr bool empty() { return true; } T* data() const { return nullptr; } protected: static constexpr bool fixed_size() { return true; } }; // Specialized base class for ArrayViews of variable size. template class ArrayViewBase { public: ArrayViewBase(T* data, size_t size) : data_(size == 0 ? nullptr : data), size_(size) {} size_t size() const { return size_; } bool empty() const { return size_ == 0; } T* data() const { return data_; } protected: static constexpr bool fixed_size() { return false; } private: T* data_; size_t size_; }; } // namespace impl template class ArrayView final : public impl::ArrayViewBase { public: using value_type = T; using const_iterator = const T*; // Construct an ArrayView from a pointer and a length. template ArrayView(U* data, size_t size) : impl::ArrayViewBase::ArrayViewBase(data, size) { RTC_DCHECK_EQ(size == 0 ? nullptr : data, this->data()); RTC_DCHECK_EQ(size, this->size()); RTC_DCHECK_EQ(!this->data(), this->size() == 0); // data is null iff size == 0. } // Construct an empty ArrayView. Note that fixed-size ArrayViews of size > 0 // cannot be empty. ArrayView() : ArrayView(nullptr, 0) {} ArrayView(std::nullptr_t) // NOLINT : ArrayView() {} ArrayView(std::nullptr_t, size_t size) : ArrayView(static_cast(nullptr), size) { static_assert(Size == 0 || Size == impl::kArrayViewVarSize, ""); RTC_DCHECK_EQ(0, size); } // Construct an ArrayView from a C-style array. template ArrayView(U (&array)[N]) // NOLINT : ArrayView(array, N) { static_assert(Size == N || Size == impl::kArrayViewVarSize, "Array size must match ArrayView size"); } // (Only if size is fixed.) Construct a fixed size ArrayView from a // non-const std::array instance. For an ArrayView with variable size, the // used ctor is ArrayView(U& u) instead. template (N)>::type* = nullptr> ArrayView(std::array& u) // NOLINT : ArrayView(u.data(), u.size()) {} // (Only if size is fixed.) Construct a fixed size ArrayView where T is // const from a const(expr) std::array instance. For an ArrayView with // variable size, the used ctor is ArrayView(U& u) instead. template (N)>::type* = nullptr> ArrayView(const std::array& u) // NOLINT : ArrayView(u.data(), u.size()) {} // (Only if size is fixed.) Construct an ArrayView from any type U that has a // static constexpr size() method whose return value is equal to Size, and a // data() method whose return value converts implicitly to T*. In particular, // this means we allow conversion from ArrayView to ArrayView, but not the other way around. We also don't allow conversion from // ArrayView to ArrayView, or from ArrayView to ArrayView when M != N. template < typename U, typename std::enable_if::value>::type* = nullptr> ArrayView(U& u) // NOLINT : ArrayView(u.data(), u.size()) { static_assert(U::size() == Size, "Sizes must match exactly"); } template < typename U, typename std::enable_if::value>::type* = nullptr> ArrayView(const U& u) // NOLINT(runtime/explicit) : ArrayView(u.data(), u.size()) { static_assert(U::size() == Size, "Sizes must match exactly"); } // (Only if size is variable.) Construct an ArrayView from any type U that // has a size() method whose return value converts implicitly to size_t, and // a data() method whose return value converts implicitly to T*. In // particular, this means we allow conversion from ArrayView to // ArrayView, but not the other way around. Other allowed // conversions include // ArrayView to ArrayView or ArrayView, // std::vector to ArrayView or ArrayView, // const std::vector to ArrayView, // rtc::Buffer to ArrayView or ArrayView, and // const rtc::Buffer to ArrayView. template < typename U, typename std::enable_if::value>::type* = nullptr> ArrayView(U& u) // NOLINT : ArrayView(u.data(), u.size()) {} template < typename U, typename std::enable_if::value>::type* = nullptr> ArrayView(const U& u) // NOLINT(runtime/explicit) : ArrayView(u.data(), u.size()) {} // Indexing and iteration. These allow mutation even if the ArrayView is // const, because the ArrayView doesn't own the array. (To prevent mutation, // use a const element type.) T& operator[](size_t idx) const { RTC_DCHECK_LT(idx, this->size()); RTC_DCHECK(this->data()); return this->data()[idx]; } T* begin() const { return this->data(); } T* end() const { return this->data() + this->size(); } const T* cbegin() const { return this->data(); } const T* cend() const { return this->data() + this->size(); } ArrayView subview(size_t offset, size_t size) const { return offset < this->size() ? ArrayView(this->data() + offset, std::min(size, this->size() - offset)) : ArrayView(); } ArrayView subview(size_t offset) const { return subview(offset, this->size()); } }; // Comparing two ArrayViews compares their (pointer,size) pairs; it does *not* // dereference the pointers. template bool operator==(const ArrayView& a, const ArrayView& b) { return a.data() == b.data() && a.size() == b.size(); } template bool operator!=(const ArrayView& a, const ArrayView& b) { return !(a == b); } // Variable-size ArrayViews are the size of two pointers; fixed-size ArrayViews // are the size of one pointer. (And as a special case, fixed-size ArrayViews // of size 0 require no storage.) static_assert(sizeof(ArrayView) == 2 * sizeof(int*), ""); static_assert(sizeof(ArrayView) == sizeof(int*), ""); static_assert(std::is_empty>::value, ""); template inline ArrayView MakeArrayView(T* data, size_t size) { return ArrayView(data, size); } // Only for primitive types that have the same size and aligment. // Allow reinterpret cast of the array view to another primitive type of the // same size. // Template arguments order is (U, T, Size) to allow deduction of the template // arguments in client calls: reinterpret_array_view(array_view). template inline ArrayView reinterpret_array_view(ArrayView view) { static_assert(sizeof(U) == sizeof(T) && alignof(U) == alignof(T), "ArrayView reinterpret_cast is only supported for casting " "between views that represent the same chunk of memory."); static_assert( std::is_fundamental::value && std::is_fundamental::value, "ArrayView reinterpret_cast is only supported for casting between " "fundamental types."); return ArrayView(reinterpret_cast(view.data()), view.size()); } } // namespace rtc #endif // API_ARRAY_VIEW_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/audio/0000775000175000017500000000000014475643423020026 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/audio/audio_frame.cc0000664000175000017500000001167214475643423022617 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "api/audio/audio_frame.h" #include #include #include #include "rtc_base/checks.h" #include "rtc_base/time_utils.h" namespace webrtc { AudioFrame::AudioFrame() { // Visual Studio doesn't like this in the class definition. static_assert(sizeof(data_) == kMaxDataSizeBytes, "kMaxDataSizeBytes"); } void swap(AudioFrame& a, AudioFrame& b) { using std::swap; swap(a.timestamp_, b.timestamp_); swap(a.elapsed_time_ms_, b.elapsed_time_ms_); swap(a.ntp_time_ms_, b.ntp_time_ms_); swap(a.samples_per_channel_, b.samples_per_channel_); swap(a.sample_rate_hz_, b.sample_rate_hz_); swap(a.num_channels_, b.num_channels_); swap(a.channel_layout_, b.channel_layout_); swap(a.speech_type_, b.speech_type_); swap(a.vad_activity_, b.vad_activity_); swap(a.profile_timestamp_ms_, b.profile_timestamp_ms_); swap(a.packet_infos_, b.packet_infos_); const size_t length_a = a.samples_per_channel_ * a.num_channels_; const size_t length_b = b.samples_per_channel_ * b.num_channels_; RTC_DCHECK_LE(length_a, AudioFrame::kMaxDataSizeSamples); RTC_DCHECK_LE(length_b, AudioFrame::kMaxDataSizeSamples); std::swap_ranges(a.data_, a.data_ + std::max(length_a, length_b), b.data_); swap(a.muted_, b.muted_); swap(a.absolute_capture_timestamp_ms_, b.absolute_capture_timestamp_ms_); } void AudioFrame::Reset() { ResetWithoutMuting(); muted_ = true; } void AudioFrame::ResetWithoutMuting() { // TODO(wu): Zero is a valid value for |timestamp_|. We should initialize // to an invalid value, or add a new member to indicate invalidity. timestamp_ = 0; elapsed_time_ms_ = -1; ntp_time_ms_ = -1; samples_per_channel_ = 0; sample_rate_hz_ = 0; num_channels_ = 0; channel_layout_ = CHANNEL_LAYOUT_NONE; speech_type_ = kUndefined; vad_activity_ = kVadUnknown; profile_timestamp_ms_ = 0; packet_infos_ = RtpPacketInfos(); absolute_capture_timestamp_ms_ = absl::nullopt; } void AudioFrame::UpdateFrame(uint32_t timestamp, const int16_t* data, size_t samples_per_channel, int sample_rate_hz, SpeechType speech_type, VADActivity vad_activity, size_t num_channels) { timestamp_ = timestamp; samples_per_channel_ = samples_per_channel; sample_rate_hz_ = sample_rate_hz; speech_type_ = speech_type; vad_activity_ = vad_activity; num_channels_ = num_channels; channel_layout_ = GuessChannelLayout(num_channels); if (channel_layout_ != CHANNEL_LAYOUT_UNSUPPORTED) { RTC_DCHECK_EQ(num_channels, ChannelLayoutToChannelCount(channel_layout_)); } const size_t length = samples_per_channel * num_channels; RTC_CHECK_LE(length, kMaxDataSizeSamples); if (data != nullptr) { memcpy(data_, data, sizeof(int16_t) * length); muted_ = false; } else { muted_ = true; } } void AudioFrame::CopyFrom(const AudioFrame& src) { if (this == &src) return; timestamp_ = src.timestamp_; elapsed_time_ms_ = src.elapsed_time_ms_; ntp_time_ms_ = src.ntp_time_ms_; packet_infos_ = src.packet_infos_; muted_ = src.muted(); samples_per_channel_ = src.samples_per_channel_; sample_rate_hz_ = src.sample_rate_hz_; speech_type_ = src.speech_type_; vad_activity_ = src.vad_activity_; num_channels_ = src.num_channels_; channel_layout_ = src.channel_layout_; absolute_capture_timestamp_ms_ = src.absolute_capture_timestamp_ms(); const size_t length = samples_per_channel_ * num_channels_; RTC_CHECK_LE(length, kMaxDataSizeSamples); if (!src.muted()) { memcpy(data_, src.data(), sizeof(int16_t) * length); muted_ = false; } } void AudioFrame::UpdateProfileTimeStamp() { profile_timestamp_ms_ = rtc::TimeMillis(); } int64_t AudioFrame::ElapsedProfileTimeMs() const { if (profile_timestamp_ms_ == 0) { // Profiling has not been activated. return -1; } return rtc::TimeSince(profile_timestamp_ms_); } const int16_t* AudioFrame::data() const { return muted_ ? empty_data() : data_; } // TODO(henrik.lundin) Can we skip zeroing the buffer? // See https://bugs.chromium.org/p/webrtc/issues/detail?id=5647. int16_t* AudioFrame::mutable_data() { if (muted_) { memset(data_, 0, kMaxDataSizeBytes); muted_ = false; } return data_; } void AudioFrame::Mute() { muted_ = true; } bool AudioFrame::muted() const { return muted_; } // static const int16_t* AudioFrame::empty_data() { static int16_t* null_data = new int16_t[kMaxDataSizeSamples](); return &null_data[0]; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/audio/audio_frame.h0000664000175000017500000001546714475643423022467 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_AUDIO_AUDIO_FRAME_H_ #define API_AUDIO_AUDIO_FRAME_H_ #include #include #include #include "api/audio/channel_layout.h" #include "api/rtp_packet_infos.h" #include "rtc_base/constructor_magic.h" namespace webrtc { /* This class holds up to 120 ms of super-wideband (32 kHz) stereo audio. It * allows for adding and subtracting frames while keeping track of the resulting * states. * * Notes * - This is a de-facto api, not designed for external use. The AudioFrame class * is in need of overhaul or even replacement, and anyone depending on it * should be prepared for that. * - The total number of samples is samples_per_channel_ * num_channels_. * - Stereo data is interleaved starting with the left channel. */ class AudioFrame { public: // Using constexpr here causes linker errors unless the variable also has an // out-of-class definition, which is impractical in this header-only class. // (This makes no sense because it compiles as an enum value, which we most // certainly cannot take the address of, just fine.) C++17 introduces inline // variables which should allow us to switch to constexpr and keep this a // header-only class. enum : size_t { // Stereo, 32 kHz, 120 ms (2 * 32 * 120) // Stereo, 192 kHz, 20 ms (2 * 192 * 20) kMaxDataSizeSamples = 7680, kMaxDataSizeBytes = kMaxDataSizeSamples * sizeof(int16_t), }; enum VADActivity { kVadActive = 0, kVadPassive = 1, kVadUnknown = 2 }; enum SpeechType { kNormalSpeech = 0, kPLC = 1, kCNG = 2, kPLCCNG = 3, kCodecPLC = 5, kUndefined = 4 }; AudioFrame(); friend void swap(AudioFrame& a, AudioFrame& b); // Resets all members to their default state. void Reset(); // Same as Reset(), but leaves mute state unchanged. Muting a frame requires // the buffer to be zeroed on the next call to mutable_data(). Callers // intending to write to the buffer immediately after Reset() can instead use // ResetWithoutMuting() to skip this wasteful zeroing. void ResetWithoutMuting(); void UpdateFrame(uint32_t timestamp, const int16_t* data, size_t samples_per_channel, int sample_rate_hz, SpeechType speech_type, VADActivity vad_activity, size_t num_channels = 1); void CopyFrom(const AudioFrame& src); // Sets a wall-time clock timestamp in milliseconds to be used for profiling // of time between two points in the audio chain. // Example: // t0: UpdateProfileTimeStamp() // t1: ElapsedProfileTimeMs() => t1 - t0 [msec] void UpdateProfileTimeStamp(); // Returns the time difference between now and when UpdateProfileTimeStamp() // was last called. Returns -1 if UpdateProfileTimeStamp() has not yet been // called. int64_t ElapsedProfileTimeMs() const; // data() returns a zeroed static buffer if the frame is muted. // mutable_frame() always returns a non-static buffer; the first call to // mutable_frame() zeros the non-static buffer and marks the frame unmuted. const int16_t* data() const; int16_t* mutable_data(); // Prefer to mute frames using AudioFrameOperations::Mute. void Mute(); // Frame is muted by default. bool muted() const; size_t max_16bit_samples() const { return kMaxDataSizeSamples; } size_t samples_per_channel() const { return samples_per_channel_; } size_t num_channels() const { return num_channels_; } ChannelLayout channel_layout() const { return channel_layout_; } int sample_rate_hz() const { return sample_rate_hz_; } void set_absolute_capture_timestamp_ms( int64_t absolute_capture_time_stamp_ms) { absolute_capture_timestamp_ms_ = absolute_capture_time_stamp_ms; } absl::optional absolute_capture_timestamp_ms() const { return absolute_capture_timestamp_ms_; } // RTP timestamp of the first sample in the AudioFrame. uint32_t timestamp_ = 0; // Time since the first frame in milliseconds. // -1 represents an uninitialized value. int64_t elapsed_time_ms_ = -1; // NTP time of the estimated capture time in local timebase in milliseconds. // -1 represents an uninitialized value. int64_t ntp_time_ms_ = -1; size_t samples_per_channel_ = 0; int sample_rate_hz_ = 0; size_t num_channels_ = 0; ChannelLayout channel_layout_ = CHANNEL_LAYOUT_NONE; SpeechType speech_type_ = kUndefined; VADActivity vad_activity_ = kVadUnknown; // Monotonically increasing timestamp intended for profiling of audio frames. // Typically used for measuring elapsed time between two different points in // the audio path. No lock is used to save resources and we are thread safe // by design. // TODO(nisse@webrtc.org): consider using absl::optional. int64_t profile_timestamp_ms_ = 0; // Information about packets used to assemble this audio frame. This is needed // by |SourceTracker| when the frame is delivered to the RTCRtpReceiver's // MediaStreamTrack, in order to implement getContributingSources(). See: // https://w3c.github.io/webrtc-pc/#dom-rtcrtpreceiver-getcontributingsources // // TODO(bugs.webrtc.org/10757): // Note that this information might not be fully accurate since we currently // don't have a proper way to track it across the audio sync buffer. The // sync buffer is the small sample-holding buffer located after the audio // decoder and before where samples are assembled into output frames. // // |RtpPacketInfos| may also be empty if the audio samples did not come from // RTP packets. E.g. if the audio were locally generated by packet loss // concealment, comfort noise generation, etc. RtpPacketInfos packet_infos_; private: // A permanently zeroed out buffer to represent muted frames. This is a // header-only class, so the only way to avoid creating a separate empty // buffer per translation unit is to wrap a static in an inline function. static const int16_t* empty_data(); int16_t data_[kMaxDataSizeSamples]; bool muted_ = true; // Absolute capture timestamp when this audio frame was originally captured. // This is only valid for audio frames captured on this machine. The absolute // capture timestamp of a received frame is found in |packet_infos_|. // This timestamp MUST be based on the same clock as rtc::TimeMillis(). absl::optional absolute_capture_timestamp_ms_; RTC_DISALLOW_COPY_AND_ASSIGN(AudioFrame); }; } // namespace webrtc #endif // API_AUDIO_AUDIO_FRAME_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/audio/channel_layout.cc0000664000175000017500000002010514475643423023340 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "api/audio/channel_layout.h" #include #include "rtc_base/arraysize.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" namespace webrtc { static const int kLayoutToChannels[] = { 0, // CHANNEL_LAYOUT_NONE 0, // CHANNEL_LAYOUT_UNSUPPORTED 1, // CHANNEL_LAYOUT_MONO 2, // CHANNEL_LAYOUT_STEREO 3, // CHANNEL_LAYOUT_2_1 3, // CHANNEL_LAYOUT_SURROUND 4, // CHANNEL_LAYOUT_4_0 4, // CHANNEL_LAYOUT_2_2 4, // CHANNEL_LAYOUT_QUAD 5, // CHANNEL_LAYOUT_5_0 6, // CHANNEL_LAYOUT_5_1 5, // CHANNEL_LAYOUT_5_0_BACK 6, // CHANNEL_LAYOUT_5_1_BACK 7, // CHANNEL_LAYOUT_7_0 8, // CHANNEL_LAYOUT_7_1 8, // CHANNEL_LAYOUT_7_1_WIDE 2, // CHANNEL_LAYOUT_STEREO_DOWNMIX 3, // CHANNEL_LAYOUT_2POINT1 4, // CHANNEL_LAYOUT_3_1 5, // CHANNEL_LAYOUT_4_1 6, // CHANNEL_LAYOUT_6_0 6, // CHANNEL_LAYOUT_6_0_FRONT 6, // CHANNEL_LAYOUT_HEXAGONAL 7, // CHANNEL_LAYOUT_6_1 7, // CHANNEL_LAYOUT_6_1_BACK 7, // CHANNEL_LAYOUT_6_1_FRONT 7, // CHANNEL_LAYOUT_7_0_FRONT 8, // CHANNEL_LAYOUT_7_1_WIDE_BACK 8, // CHANNEL_LAYOUT_OCTAGONAL 0, // CHANNEL_LAYOUT_DISCRETE 3, // CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC 5, // CHANNEL_LAYOUT_4_1_QUAD_SIDE 0, // CHANNEL_LAYOUT_BITSTREAM }; // The channel orderings for each layout as specified by FFmpeg. Each value // represents the index of each channel in each layout. Values of -1 mean the // channel at that index is not used for that layout. For example, the left side // surround sound channel in FFmpeg's 5.1 layout is in the 5th position (because // the order is L, R, C, LFE, LS, RS), so // kChannelOrderings[CHANNEL_LAYOUT_5_1][SIDE_LEFT] = 4; static const int kChannelOrderings[CHANNEL_LAYOUT_MAX + 1][CHANNELS_MAX + 1] = { // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR // CHANNEL_LAYOUT_NONE {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_UNSUPPORTED {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_MONO {-1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_STEREO {0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_2_1 {0, 1, -1, -1, -1, -1, -1, -1, 2, -1, -1}, // CHANNEL_LAYOUT_SURROUND {0, 1, 2, -1, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_4_0 {0, 1, 2, -1, -1, -1, -1, -1, 3, -1, -1}, // CHANNEL_LAYOUT_2_2 {0, 1, -1, -1, -1, -1, -1, -1, -1, 2, 3}, // CHANNEL_LAYOUT_QUAD {0, 1, -1, -1, 2, 3, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_5_0 {0, 1, 2, -1, -1, -1, -1, -1, -1, 3, 4}, // CHANNEL_LAYOUT_5_1 {0, 1, 2, 3, -1, -1, -1, -1, -1, 4, 5}, // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR // CHANNEL_LAYOUT_5_0_BACK {0, 1, 2, -1, 3, 4, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_5_1_BACK {0, 1, 2, 3, 4, 5, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_7_0 {0, 1, 2, -1, 5, 6, -1, -1, -1, 3, 4}, // CHANNEL_LAYOUT_7_1 {0, 1, 2, 3, 6, 7, -1, -1, -1, 4, 5}, // CHANNEL_LAYOUT_7_1_WIDE {0, 1, 2, 3, -1, -1, 6, 7, -1, 4, 5}, // CHANNEL_LAYOUT_STEREO_DOWNMIX {0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_2POINT1 {0, 1, -1, 2, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_3_1 {0, 1, 2, 3, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_4_1 {0, 1, 2, 4, -1, -1, -1, -1, 3, -1, -1}, // CHANNEL_LAYOUT_6_0 {0, 1, 2, -1, -1, -1, -1, -1, 5, 3, 4}, // CHANNEL_LAYOUT_6_0_FRONT {0, 1, -1, -1, -1, -1, 4, 5, -1, 2, 3}, // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR // CHANNEL_LAYOUT_HEXAGONAL {0, 1, 2, -1, 3, 4, -1, -1, 5, -1, -1}, // CHANNEL_LAYOUT_6_1 {0, 1, 2, 3, -1, -1, -1, -1, 6, 4, 5}, // CHANNEL_LAYOUT_6_1_BACK {0, 1, 2, 3, 4, 5, -1, -1, 6, -1, -1}, // CHANNEL_LAYOUT_6_1_FRONT {0, 1, -1, 6, -1, -1, 4, 5, -1, 2, 3}, // CHANNEL_LAYOUT_7_0_FRONT {0, 1, 2, -1, -1, -1, 5, 6, -1, 3, 4}, // CHANNEL_LAYOUT_7_1_WIDE_BACK {0, 1, 2, 3, 4, 5, 6, 7, -1, -1, -1}, // CHANNEL_LAYOUT_OCTAGONAL {0, 1, 2, -1, 5, 6, -1, -1, 7, 3, 4}, // CHANNEL_LAYOUT_DISCRETE {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC {0, 1, 2, -1, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_4_1_QUAD_SIDE {0, 1, -1, 4, -1, -1, -1, -1, -1, 2, 3}, // CHANNEL_LAYOUT_BITSTREAM {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR }; int ChannelLayoutToChannelCount(ChannelLayout layout) { RTC_DCHECK_LT(static_cast(layout), arraysize(kLayoutToChannels)); RTC_DCHECK_LE(kLayoutToChannels[layout], kMaxConcurrentChannels); return kLayoutToChannels[layout]; } // Converts a channel count into a channel layout. ChannelLayout GuessChannelLayout(int channels) { switch (channels) { case 1: return CHANNEL_LAYOUT_MONO; case 2: return CHANNEL_LAYOUT_STEREO; case 3: return CHANNEL_LAYOUT_SURROUND; case 4: return CHANNEL_LAYOUT_QUAD; case 5: return CHANNEL_LAYOUT_5_0; case 6: return CHANNEL_LAYOUT_5_1; case 7: return CHANNEL_LAYOUT_6_1; case 8: return CHANNEL_LAYOUT_7_1; default: RTC_DLOG(LS_WARNING) << "Unsupported channel count: " << channels; } return CHANNEL_LAYOUT_UNSUPPORTED; } int ChannelOrder(ChannelLayout layout, Channels channel) { RTC_DCHECK_LT(static_cast(layout), arraysize(kChannelOrderings)); RTC_DCHECK_LT(static_cast(channel), arraysize(kChannelOrderings[0])); return kChannelOrderings[layout][channel]; } const char* ChannelLayoutToString(ChannelLayout layout) { switch (layout) { case CHANNEL_LAYOUT_NONE: return "NONE"; case CHANNEL_LAYOUT_UNSUPPORTED: return "UNSUPPORTED"; case CHANNEL_LAYOUT_MONO: return "MONO"; case CHANNEL_LAYOUT_STEREO: return "STEREO"; case CHANNEL_LAYOUT_2_1: return "2.1"; case CHANNEL_LAYOUT_SURROUND: return "SURROUND"; case CHANNEL_LAYOUT_4_0: return "4.0"; case CHANNEL_LAYOUT_2_2: return "QUAD_SIDE"; case CHANNEL_LAYOUT_QUAD: return "QUAD"; case CHANNEL_LAYOUT_5_0: return "5.0"; case CHANNEL_LAYOUT_5_1: return "5.1"; case CHANNEL_LAYOUT_5_0_BACK: return "5.0_BACK"; case CHANNEL_LAYOUT_5_1_BACK: return "5.1_BACK"; case CHANNEL_LAYOUT_7_0: return "7.0"; case CHANNEL_LAYOUT_7_1: return "7.1"; case CHANNEL_LAYOUT_7_1_WIDE: return "7.1_WIDE"; case CHANNEL_LAYOUT_STEREO_DOWNMIX: return "STEREO_DOWNMIX"; case CHANNEL_LAYOUT_2POINT1: return "2POINT1"; case CHANNEL_LAYOUT_3_1: return "3.1"; case CHANNEL_LAYOUT_4_1: return "4.1"; case CHANNEL_LAYOUT_6_0: return "6.0"; case CHANNEL_LAYOUT_6_0_FRONT: return "6.0_FRONT"; case CHANNEL_LAYOUT_HEXAGONAL: return "HEXAGONAL"; case CHANNEL_LAYOUT_6_1: return "6.1"; case CHANNEL_LAYOUT_6_1_BACK: return "6.1_BACK"; case CHANNEL_LAYOUT_6_1_FRONT: return "6.1_FRONT"; case CHANNEL_LAYOUT_7_0_FRONT: return "7.0_FRONT"; case CHANNEL_LAYOUT_7_1_WIDE_BACK: return "7.1_WIDE_BACK"; case CHANNEL_LAYOUT_OCTAGONAL: return "OCTAGONAL"; case CHANNEL_LAYOUT_DISCRETE: return "DISCRETE"; case CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC: return "STEREO_AND_KEYBOARD_MIC"; case CHANNEL_LAYOUT_4_1_QUAD_SIDE: return "4.1_QUAD_SIDE"; case CHANNEL_LAYOUT_BITSTREAM: return "BITSTREAM"; } RTC_NOTREACHED() << "Invalid channel layout provided: " << layout; return ""; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/audio/channel_layout.h0000664000175000017500000001200314475643423023200 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_AUDIO_CHANNEL_LAYOUT_H_ #define API_AUDIO_CHANNEL_LAYOUT_H_ namespace webrtc { // This file is derived from Chromium's base/channel_layout.h. // Enumerates the various representations of the ordering of audio channels. // Logged to UMA, so never reuse a value, always add new/greater ones! enum ChannelLayout { CHANNEL_LAYOUT_NONE = 0, CHANNEL_LAYOUT_UNSUPPORTED = 1, // Front C CHANNEL_LAYOUT_MONO = 2, // Front L, Front R CHANNEL_LAYOUT_STEREO = 3, // Front L, Front R, Back C CHANNEL_LAYOUT_2_1 = 4, // Front L, Front R, Front C CHANNEL_LAYOUT_SURROUND = 5, // Front L, Front R, Front C, Back C CHANNEL_LAYOUT_4_0 = 6, // Front L, Front R, Side L, Side R CHANNEL_LAYOUT_2_2 = 7, // Front L, Front R, Back L, Back R CHANNEL_LAYOUT_QUAD = 8, // Front L, Front R, Front C, Side L, Side R CHANNEL_LAYOUT_5_0 = 9, // Front L, Front R, Front C, LFE, Side L, Side R CHANNEL_LAYOUT_5_1 = 10, // Front L, Front R, Front C, Back L, Back R CHANNEL_LAYOUT_5_0_BACK = 11, // Front L, Front R, Front C, LFE, Back L, Back R CHANNEL_LAYOUT_5_1_BACK = 12, // Front L, Front R, Front C, Side L, Side R, Back L, Back R CHANNEL_LAYOUT_7_0 = 13, // Front L, Front R, Front C, LFE, Side L, Side R, Back L, Back R CHANNEL_LAYOUT_7_1 = 14, // Front L, Front R, Front C, LFE, Side L, Side R, Front LofC, Front RofC CHANNEL_LAYOUT_7_1_WIDE = 15, // Stereo L, Stereo R CHANNEL_LAYOUT_STEREO_DOWNMIX = 16, // Stereo L, Stereo R, LFE CHANNEL_LAYOUT_2POINT1 = 17, // Stereo L, Stereo R, Front C, LFE CHANNEL_LAYOUT_3_1 = 18, // Stereo L, Stereo R, Front C, Rear C, LFE CHANNEL_LAYOUT_4_1 = 19, // Stereo L, Stereo R, Front C, Side L, Side R, Back C CHANNEL_LAYOUT_6_0 = 20, // Stereo L, Stereo R, Side L, Side R, Front LofC, Front RofC CHANNEL_LAYOUT_6_0_FRONT = 21, // Stereo L, Stereo R, Front C, Rear L, Rear R, Rear C CHANNEL_LAYOUT_HEXAGONAL = 22, // Stereo L, Stereo R, Front C, LFE, Side L, Side R, Rear Center CHANNEL_LAYOUT_6_1 = 23, // Stereo L, Stereo R, Front C, LFE, Back L, Back R, Rear Center CHANNEL_LAYOUT_6_1_BACK = 24, // Stereo L, Stereo R, Side L, Side R, Front LofC, Front RofC, LFE CHANNEL_LAYOUT_6_1_FRONT = 25, // Front L, Front R, Front C, Side L, Side R, Front LofC, Front RofC CHANNEL_LAYOUT_7_0_FRONT = 26, // Front L, Front R, Front C, LFE, Back L, Back R, Front LofC, Front RofC CHANNEL_LAYOUT_7_1_WIDE_BACK = 27, // Front L, Front R, Front C, Side L, Side R, Rear L, Back R, Back C. CHANNEL_LAYOUT_OCTAGONAL = 28, // Channels are not explicitly mapped to speakers. CHANNEL_LAYOUT_DISCRETE = 29, // Front L, Front R, Front C. Front C contains the keyboard mic audio. This // layout is only intended for input for WebRTC. The Front C channel // is stripped away in the WebRTC audio input pipeline and never seen outside // of that. CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC = 30, // Front L, Front R, Side L, Side R, LFE CHANNEL_LAYOUT_4_1_QUAD_SIDE = 31, // Actual channel layout is specified in the bitstream and the actual channel // count is unknown at Chromium media pipeline level (useful for audio // pass-through mode). CHANNEL_LAYOUT_BITSTREAM = 32, // Max value, must always equal the largest entry ever logged. CHANNEL_LAYOUT_MAX = CHANNEL_LAYOUT_BITSTREAM }; // Note: Do not reorder or reassign these values; other code depends on their // ordering to operate correctly. E.g., CoreAudio channel layout computations. enum Channels { LEFT = 0, RIGHT, CENTER, LFE, BACK_LEFT, BACK_RIGHT, LEFT_OF_CENTER, RIGHT_OF_CENTER, BACK_CENTER, SIDE_LEFT, SIDE_RIGHT, CHANNELS_MAX = SIDE_RIGHT, // Must always equal the largest value ever logged. }; // The maximum number of concurrently active channels for all possible layouts. // ChannelLayoutToChannelCount() will never return a value higher than this. constexpr int kMaxConcurrentChannels = 8; // Returns the expected channel position in an interleaved stream. Values of -1 // mean the channel at that index is not used for that layout. Values range // from 0 to ChannelLayoutToChannelCount(layout) - 1. int ChannelOrder(ChannelLayout layout, Channels channel); // Returns the number of channels in a given ChannelLayout. int ChannelLayoutToChannelCount(ChannelLayout layout); // Given the number of channels, return the best layout, // or return CHANNEL_LAYOUT_UNSUPPORTED if there is no good match. ChannelLayout GuessChannelLayout(int channels); // Returns a string representation of the channel layout. const char* ChannelLayoutToString(ChannelLayout layout); } // namespace webrtc #endif // API_AUDIO_CHANNEL_LAYOUT_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/audio/echo_canceller3_config.cc0000664000175000017500000002674214475643423024706 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "api/audio/echo_canceller3_config.h" #include #include #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_minmax.h" namespace webrtc { namespace { bool Limit(float* value, float min, float max) { float clamped = rtc::SafeClamp(*value, min, max); clamped = std::isfinite(clamped) ? clamped : min; bool res = *value == clamped; *value = clamped; return res; } bool Limit(size_t* value, size_t min, size_t max) { size_t clamped = rtc::SafeClamp(*value, min, max); bool res = *value == clamped; *value = clamped; return res; } bool Limit(int* value, int min, int max) { int clamped = rtc::SafeClamp(*value, min, max); bool res = *value == clamped; *value = clamped; return res; } bool FloorLimit(size_t* value, size_t min) { size_t clamped = *value >= min ? *value : min; bool res = *value == clamped; *value = clamped; return res; } } // namespace EchoCanceller3Config::EchoCanceller3Config() = default; EchoCanceller3Config::EchoCanceller3Config(const EchoCanceller3Config& e) = default; EchoCanceller3Config& EchoCanceller3Config::operator=( const EchoCanceller3Config& e) = default; EchoCanceller3Config::Delay::Delay() = default; EchoCanceller3Config::Delay::Delay(const EchoCanceller3Config::Delay& e) = default; EchoCanceller3Config::Delay& EchoCanceller3Config::Delay::operator=( const Delay& e) = default; EchoCanceller3Config::EchoModel::EchoModel() = default; EchoCanceller3Config::EchoModel::EchoModel( const EchoCanceller3Config::EchoModel& e) = default; EchoCanceller3Config::EchoModel& EchoCanceller3Config::EchoModel::operator=( const EchoModel& e) = default; EchoCanceller3Config::Suppressor::Suppressor() = default; EchoCanceller3Config::Suppressor::Suppressor( const EchoCanceller3Config::Suppressor& e) = default; EchoCanceller3Config::Suppressor& EchoCanceller3Config::Suppressor::operator=( const Suppressor& e) = default; EchoCanceller3Config::Suppressor::MaskingThresholds::MaskingThresholds( float enr_transparent, float enr_suppress, float emr_transparent) : enr_transparent(enr_transparent), enr_suppress(enr_suppress), emr_transparent(emr_transparent) {} EchoCanceller3Config::Suppressor::MaskingThresholds::MaskingThresholds( const EchoCanceller3Config::Suppressor::MaskingThresholds& e) = default; EchoCanceller3Config::Suppressor::MaskingThresholds& EchoCanceller3Config::Suppressor::MaskingThresholds::operator=( const MaskingThresholds& e) = default; EchoCanceller3Config::Suppressor::Tuning::Tuning(MaskingThresholds mask_lf, MaskingThresholds mask_hf, float max_inc_factor, float max_dec_factor_lf) : mask_lf(mask_lf), mask_hf(mask_hf), max_inc_factor(max_inc_factor), max_dec_factor_lf(max_dec_factor_lf) {} EchoCanceller3Config::Suppressor::Tuning::Tuning( const EchoCanceller3Config::Suppressor::Tuning& e) = default; EchoCanceller3Config::Suppressor::Tuning& EchoCanceller3Config::Suppressor::Tuning::operator=(const Tuning& e) = default; bool EchoCanceller3Config::Validate(EchoCanceller3Config* config) { RTC_DCHECK(config); EchoCanceller3Config* c = config; bool res = true; if (c->delay.down_sampling_factor != 4 && c->delay.down_sampling_factor != 8) { c->delay.down_sampling_factor = 4; res = false; } res = res & Limit(&c->delay.default_delay, 0, 5000); res = res & Limit(&c->delay.num_filters, 0, 5000); res = res & Limit(&c->delay.delay_headroom_samples, 0, 5000); res = res & Limit(&c->delay.hysteresis_limit_blocks, 0, 5000); res = res & Limit(&c->delay.fixed_capture_delay_samples, 0, 5000); res = res & Limit(&c->delay.delay_estimate_smoothing, 0.f, 1.f); res = res & Limit(&c->delay.delay_candidate_detection_threshold, 0.f, 1.f); res = res & Limit(&c->delay.delay_selection_thresholds.initial, 1, 250); res = res & Limit(&c->delay.delay_selection_thresholds.converged, 1, 250); res = res & FloorLimit(&c->filter.refined.length_blocks, 1); res = res & Limit(&c->filter.refined.leakage_converged, 0.f, 1000.f); res = res & Limit(&c->filter.refined.leakage_diverged, 0.f, 1000.f); res = res & Limit(&c->filter.refined.error_floor, 0.f, 1000.f); res = res & Limit(&c->filter.refined.error_ceil, 0.f, 100000000.f); res = res & Limit(&c->filter.refined.noise_gate, 0.f, 100000000.f); res = res & FloorLimit(&c->filter.refined_initial.length_blocks, 1); res = res & Limit(&c->filter.refined_initial.leakage_converged, 0.f, 1000.f); res = res & Limit(&c->filter.refined_initial.leakage_diverged, 0.f, 1000.f); res = res & Limit(&c->filter.refined_initial.error_floor, 0.f, 1000.f); res = res & Limit(&c->filter.refined_initial.error_ceil, 0.f, 100000000.f); res = res & Limit(&c->filter.refined_initial.noise_gate, 0.f, 100000000.f); if (c->filter.refined.length_blocks < c->filter.refined_initial.length_blocks) { c->filter.refined_initial.length_blocks = c->filter.refined.length_blocks; res = false; } res = res & FloorLimit(&c->filter.coarse.length_blocks, 1); res = res & Limit(&c->filter.coarse.rate, 0.f, 1.f); res = res & Limit(&c->filter.coarse.noise_gate, 0.f, 100000000.f); res = res & FloorLimit(&c->filter.coarse_initial.length_blocks, 1); res = res & Limit(&c->filter.coarse_initial.rate, 0.f, 1.f); res = res & Limit(&c->filter.coarse_initial.noise_gate, 0.f, 100000000.f); if (c->filter.coarse.length_blocks < c->filter.coarse_initial.length_blocks) { c->filter.coarse_initial.length_blocks = c->filter.coarse.length_blocks; res = false; } res = res & Limit(&c->filter.config_change_duration_blocks, 0, 100000); res = res & Limit(&c->filter.initial_state_seconds, 0.f, 100.f); res = res & Limit(&c->erle.min, 1.f, 100000.f); res = res & Limit(&c->erle.max_l, 1.f, 100000.f); res = res & Limit(&c->erle.max_h, 1.f, 100000.f); if (c->erle.min > c->erle.max_l || c->erle.min > c->erle.max_h) { c->erle.min = std::min(c->erle.max_l, c->erle.max_h); res = false; } res = res & Limit(&c->erle.num_sections, 1, c->filter.refined.length_blocks); res = res & Limit(&c->ep_strength.default_gain, 0.f, 1000000.f); res = res & Limit(&c->ep_strength.default_len, -1.f, 1.f); res = res & Limit(&c->echo_audibility.low_render_limit, 0.f, 32768.f * 32768.f); res = res & Limit(&c->echo_audibility.normal_render_limit, 0.f, 32768.f * 32768.f); res = res & Limit(&c->echo_audibility.floor_power, 0.f, 32768.f * 32768.f); res = res & Limit(&c->echo_audibility.audibility_threshold_lf, 0.f, 32768.f * 32768.f); res = res & Limit(&c->echo_audibility.audibility_threshold_mf, 0.f, 32768.f * 32768.f); res = res & Limit(&c->echo_audibility.audibility_threshold_hf, 0.f, 32768.f * 32768.f); res = res & Limit(&c->render_levels.active_render_limit, 0.f, 32768.f * 32768.f); res = res & Limit(&c->render_levels.poor_excitation_render_limit, 0.f, 32768.f * 32768.f); res = res & Limit(&c->render_levels.poor_excitation_render_limit_ds8, 0.f, 32768.f * 32768.f); res = res & Limit(&c->echo_model.noise_floor_hold, 0, 1000); res = res & Limit(&c->echo_model.min_noise_floor_power, 0, 2000000.f); res = res & Limit(&c->echo_model.stationary_gate_slope, 0, 1000000.f); res = res & Limit(&c->echo_model.noise_gate_power, 0, 1000000.f); res = res & Limit(&c->echo_model.noise_gate_slope, 0, 1000000.f); res = res & Limit(&c->echo_model.render_pre_window_size, 0, 100); res = res & Limit(&c->echo_model.render_post_window_size, 0, 100); res = res & Limit(&c->comfort_noise.noise_floor_dbfs, -200.f, 0.f); res = res & Limit(&c->suppressor.nearend_average_blocks, 1, 5000); res = res & Limit(&c->suppressor.normal_tuning.mask_lf.enr_transparent, 0.f, 100.f); res = res & Limit(&c->suppressor.normal_tuning.mask_lf.enr_suppress, 0.f, 100.f); res = res & Limit(&c->suppressor.normal_tuning.mask_lf.emr_transparent, 0.f, 100.f); res = res & Limit(&c->suppressor.normal_tuning.mask_hf.enr_transparent, 0.f, 100.f); res = res & Limit(&c->suppressor.normal_tuning.mask_hf.enr_suppress, 0.f, 100.f); res = res & Limit(&c->suppressor.normal_tuning.mask_hf.emr_transparent, 0.f, 100.f); res = res & Limit(&c->suppressor.normal_tuning.max_inc_factor, 0.f, 100.f); res = res & Limit(&c->suppressor.normal_tuning.max_dec_factor_lf, 0.f, 100.f); res = res & Limit(&c->suppressor.nearend_tuning.mask_lf.enr_transparent, 0.f, 100.f); res = res & Limit(&c->suppressor.nearend_tuning.mask_lf.enr_suppress, 0.f, 100.f); res = res & Limit(&c->suppressor.nearend_tuning.mask_lf.emr_transparent, 0.f, 100.f); res = res & Limit(&c->suppressor.nearend_tuning.mask_hf.enr_transparent, 0.f, 100.f); res = res & Limit(&c->suppressor.nearend_tuning.mask_hf.enr_suppress, 0.f, 100.f); res = res & Limit(&c->suppressor.nearend_tuning.mask_hf.emr_transparent, 0.f, 100.f); res = res & Limit(&c->suppressor.nearend_tuning.max_inc_factor, 0.f, 100.f); res = res & Limit(&c->suppressor.nearend_tuning.max_dec_factor_lf, 0.f, 100.f); res = res & Limit(&c->suppressor.dominant_nearend_detection.enr_threshold, 0.f, 1000000.f); res = res & Limit(&c->suppressor.dominant_nearend_detection.snr_threshold, 0.f, 1000000.f); res = res & Limit(&c->suppressor.dominant_nearend_detection.hold_duration, 0, 10000); res = res & Limit(&c->suppressor.dominant_nearend_detection.trigger_threshold, 0, 10000); res = res & Limit(&c->suppressor.subband_nearend_detection.nearend_average_blocks, 1, 1024); res = res & Limit(&c->suppressor.subband_nearend_detection.subband1.low, 0, 65); res = res & Limit(&c->suppressor.subband_nearend_detection.subband1.high, c->suppressor.subband_nearend_detection.subband1.low, 65); res = res & Limit(&c->suppressor.subband_nearend_detection.subband2.low, 0, 65); res = res & Limit(&c->suppressor.subband_nearend_detection.subband2.high, c->suppressor.subband_nearend_detection.subband2.low, 65); res = res & Limit(&c->suppressor.subband_nearend_detection.nearend_threshold, 0.f, 1.e24f); res = res & Limit(&c->suppressor.subband_nearend_detection.snr_threshold, 0.f, 1.e24f); res = res & Limit(&c->suppressor.high_bands_suppression.enr_threshold, 0.f, 1000000.f); res = res & Limit(&c->suppressor.high_bands_suppression.max_gain_during_echo, 0.f, 1.f); res = res & Limit(&c->suppressor.high_bands_suppression .anti_howling_activation_threshold, 0.f, 32768.f * 32768.f); res = res & Limit(&c->suppressor.high_bands_suppression.anti_howling_gain, 0.f, 1.f); res = res & Limit(&c->suppressor.floor_first_increase, 0.f, 1000000.f); return res; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/audio/echo_canceller3_config.h0000664000175000017500000001612314475643423024540 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_AUDIO_ECHO_CANCELLER3_CONFIG_H_ #define API_AUDIO_ECHO_CANCELLER3_CONFIG_H_ #include // size_t #include "rtc_base/system/rtc_export.h" namespace webrtc { // Configuration struct for EchoCanceller3 struct RTC_EXPORT EchoCanceller3Config { // Checks and updates the config parameters to lie within (mostly) reasonable // ranges. Returns true if and only of the config did not need to be changed. static bool Validate(EchoCanceller3Config* config); EchoCanceller3Config(); EchoCanceller3Config(const EchoCanceller3Config& e); EchoCanceller3Config& operator=(const EchoCanceller3Config& other); struct Buffering { size_t excess_render_detection_interval_blocks = 250; size_t max_allowed_excess_render_blocks = 8; } buffering; struct Delay { Delay(); Delay(const Delay& e); Delay& operator=(const Delay& e); size_t default_delay = 5; size_t down_sampling_factor = 4; size_t num_filters = 5; size_t delay_headroom_samples = 32; size_t hysteresis_limit_blocks = 1; size_t fixed_capture_delay_samples = 0; float delay_estimate_smoothing = 0.7f; float delay_candidate_detection_threshold = 0.2f; struct DelaySelectionThresholds { int initial; int converged; } delay_selection_thresholds = {5, 20}; bool use_external_delay_estimator = false; bool log_warning_on_delay_changes = false; struct AlignmentMixing { bool downmix; bool adaptive_selection; float activity_power_threshold; bool prefer_first_two_channels; }; AlignmentMixing render_alignment_mixing = {false, true, 10000.f, true}; AlignmentMixing capture_alignment_mixing = {false, true, 10000.f, false}; } delay; struct Filter { struct RefinedConfiguration { size_t length_blocks; float leakage_converged; float leakage_diverged; float error_floor; float error_ceil; float noise_gate; }; struct CoarseConfiguration { size_t length_blocks; float rate; float noise_gate; }; RefinedConfiguration refined = {13, 0.00005f, 0.05f, 0.001f, 2.f, 20075344.f}; CoarseConfiguration coarse = {13, 0.7f, 20075344.f}; RefinedConfiguration refined_initial = {12, 0.005f, 0.5f, 0.001f, 2.f, 20075344.f}; CoarseConfiguration coarse_initial = {12, 0.9f, 20075344.f}; size_t config_change_duration_blocks = 250; float initial_state_seconds = 2.5f; bool conservative_initial_phase = false; bool enable_coarse_filter_output_usage = true; bool use_linear_filter = true; bool export_linear_aec_output = false; } filter; struct Erle { float min = 1.f; float max_l = 4.f; float max_h = 1.5f; bool onset_detection = true; size_t num_sections = 1; bool clamp_quality_estimate_to_zero = true; bool clamp_quality_estimate_to_one = true; } erle; struct EpStrength { float default_gain = 1.f; float default_len = 0.83f; bool echo_can_saturate = true; bool bounded_erl = false; } ep_strength; struct EchoAudibility { float low_render_limit = 4 * 64.f; float normal_render_limit = 64.f; float floor_power = 2 * 64.f; float audibility_threshold_lf = 10; float audibility_threshold_mf = 10; float audibility_threshold_hf = 10; bool use_stationarity_properties = false; bool use_stationarity_properties_at_init = false; } echo_audibility; struct RenderLevels { float active_render_limit = 100.f; float poor_excitation_render_limit = 150.f; float poor_excitation_render_limit_ds8 = 20.f; float render_power_gain_db = 0.f; } render_levels; struct EchoRemovalControl { bool has_clock_drift = false; bool linear_and_stable_echo_path = false; } echo_removal_control; struct EchoModel { EchoModel(); EchoModel(const EchoModel& e); EchoModel& operator=(const EchoModel& e); size_t noise_floor_hold = 50; float min_noise_floor_power = 1638400.f; float stationary_gate_slope = 10.f; float noise_gate_power = 27509.42f; float noise_gate_slope = 0.3f; size_t render_pre_window_size = 1; size_t render_post_window_size = 1; bool model_reverb_in_nonlinear_mode = true; } echo_model; struct ComfortNoise { float noise_floor_dbfs = -96.03406f; } comfort_noise; struct Suppressor { Suppressor(); Suppressor(const Suppressor& e); Suppressor& operator=(const Suppressor& e); size_t nearend_average_blocks = 4; struct MaskingThresholds { MaskingThresholds(float enr_transparent, float enr_suppress, float emr_transparent); MaskingThresholds(const MaskingThresholds& e); MaskingThresholds& operator=(const MaskingThresholds& e); float enr_transparent; float enr_suppress; float emr_transparent; }; struct Tuning { Tuning(MaskingThresholds mask_lf, MaskingThresholds mask_hf, float max_inc_factor, float max_dec_factor_lf); Tuning(const Tuning& e); Tuning& operator=(const Tuning& e); MaskingThresholds mask_lf; MaskingThresholds mask_hf; float max_inc_factor; float max_dec_factor_lf; }; Tuning normal_tuning = Tuning(MaskingThresholds(.3f, .4f, .3f), MaskingThresholds(.07f, .1f, .3f), 2.0f, 0.25f); Tuning nearend_tuning = Tuning(MaskingThresholds(1.09f, 1.1f, .3f), MaskingThresholds(.1f, .3f, .3f), 2.0f, 0.25f); struct DominantNearendDetection { float enr_threshold = .25f; float enr_exit_threshold = 10.f; float snr_threshold = 30.f; int hold_duration = 50; int trigger_threshold = 12; bool use_during_initial_phase = true; } dominant_nearend_detection; struct SubbandNearendDetection { size_t nearend_average_blocks = 1; struct SubbandRegion { size_t low; size_t high; }; SubbandRegion subband1 = {1, 1}; SubbandRegion subband2 = {1, 1}; float nearend_threshold = 1.f; float snr_threshold = 1.f; } subband_nearend_detection; bool use_subband_nearend_detection = false; struct HighBandsSuppression { float enr_threshold = 1.f; float max_gain_during_echo = 1.f; float anti_howling_activation_threshold = 400.f; float anti_howling_gain = 1.f; } high_bands_suppression; float floor_first_increase = 0.00001f; } suppressor; }; } // namespace webrtc #endif // API_AUDIO_ECHO_CANCELLER3_CONFIG_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/audio/echo_control.h0000664000175000017500000000410614475643423022656 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_AUDIO_ECHO_CONTROL_H_ #define API_AUDIO_ECHO_CONTROL_H_ #include #include "rtc_base/checks.h" namespace webrtc { class AudioBuffer; // Interface for an acoustic echo cancellation (AEC) submodule. class EchoControl { public: // Analysis (not changing) of the render signal. virtual void AnalyzeRender(AudioBuffer* render) = 0; // Analysis (not changing) of the capture signal. virtual void AnalyzeCapture(AudioBuffer* capture) = 0; // Processes the capture signal in order to remove the echo. virtual void ProcessCapture(AudioBuffer* capture, bool level_change) = 0; // As above, but also returns the linear filter output. virtual void ProcessCapture(AudioBuffer* capture, AudioBuffer* linear_output, bool level_change) = 0; struct Metrics { double echo_return_loss; double echo_return_loss_enhancement; int delay_ms; }; // Collect current metrics from the echo controller. virtual Metrics GetMetrics() const = 0; // Provides an optional external estimate of the audio buffer delay. virtual void SetAudioBufferDelay(int delay_ms) = 0; // Returns wheter the signal is altered. virtual bool ActiveProcessing() const = 0; virtual ~EchoControl() {} }; // Interface for a factory that creates EchoControllers. class EchoControlFactory { public: virtual std::unique_ptr Create(int sample_rate_hz, int num_render_channels, int num_capture_channels) = 0; virtual ~EchoControlFactory() = default; }; } // namespace webrtc #endif // API_AUDIO_ECHO_CONTROL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/audio_codecs/0000775000175000017500000000000014475643423021346 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/audio_codecs/audio_decoder.cc0000664000175000017500000001306614475643423024451 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "api/audio_codecs/audio_decoder.h" #include #include #include #include "api/array_view.h" #include "rtc_base/checks.h" #include "rtc_base/sanitizer.h" #include "rtc_base/trace_event.h" namespace webrtc { namespace { class OldStyleEncodedFrame final : public AudioDecoder::EncodedAudioFrame { public: OldStyleEncodedFrame(AudioDecoder* decoder, rtc::Buffer&& payload) : decoder_(decoder), payload_(std::move(payload)) {} size_t Duration() const override { const int ret = decoder_->PacketDuration(payload_.data(), payload_.size()); return ret < 0 ? 0 : static_cast(ret); } absl::optional Decode( rtc::ArrayView decoded) const override { auto speech_type = AudioDecoder::kSpeech; const int ret = decoder_->Decode( payload_.data(), payload_.size(), decoder_->SampleRateHz(), decoded.size() * sizeof(int16_t), decoded.data(), &speech_type); return ret < 0 ? absl::nullopt : absl::optional( {static_cast(ret), speech_type}); } private: AudioDecoder* const decoder_; const rtc::Buffer payload_; }; } // namespace bool AudioDecoder::EncodedAudioFrame::IsDtxPacket() const { return false; } AudioDecoder::ParseResult::ParseResult() = default; AudioDecoder::ParseResult::ParseResult(ParseResult&& b) = default; AudioDecoder::ParseResult::ParseResult(uint32_t timestamp, int priority, std::unique_ptr frame) : timestamp(timestamp), priority(priority), frame(std::move(frame)) { RTC_DCHECK_GE(priority, 0); } AudioDecoder::ParseResult::~ParseResult() = default; AudioDecoder::ParseResult& AudioDecoder::ParseResult::operator=( ParseResult&& b) = default; std::vector AudioDecoder::ParsePayload( rtc::Buffer&& payload, uint32_t timestamp) { std::vector results; std::unique_ptr frame( new OldStyleEncodedFrame(this, std::move(payload))); results.emplace_back(timestamp, 0, std::move(frame)); return results; } int AudioDecoder::Decode(const uint8_t* encoded, size_t encoded_len, int sample_rate_hz, size_t max_decoded_bytes, int16_t* decoded, SpeechType* speech_type) { TRACE_EVENT0("webrtc", "AudioDecoder::Decode"); rtc::MsanCheckInitialized(rtc::MakeArrayView(encoded, encoded_len)); int duration = PacketDuration(encoded, encoded_len); if (duration >= 0 && duration * Channels() * sizeof(int16_t) > max_decoded_bytes) { return -1; } return DecodeInternal(encoded, encoded_len, sample_rate_hz, decoded, speech_type); } int AudioDecoder::DecodeRedundant(const uint8_t* encoded, size_t encoded_len, int sample_rate_hz, size_t max_decoded_bytes, int16_t* decoded, SpeechType* speech_type) { TRACE_EVENT0("webrtc", "AudioDecoder::DecodeRedundant"); rtc::MsanCheckInitialized(rtc::MakeArrayView(encoded, encoded_len)); int duration = PacketDurationRedundant(encoded, encoded_len); if (duration >= 0 && duration * Channels() * sizeof(int16_t) > max_decoded_bytes) { return -1; } return DecodeRedundantInternal(encoded, encoded_len, sample_rate_hz, decoded, speech_type); } int AudioDecoder::DecodeRedundantInternal(const uint8_t* encoded, size_t encoded_len, int sample_rate_hz, int16_t* decoded, SpeechType* speech_type) { return DecodeInternal(encoded, encoded_len, sample_rate_hz, decoded, speech_type); } bool AudioDecoder::HasDecodePlc() const { return false; } size_t AudioDecoder::DecodePlc(size_t num_frames, int16_t* decoded) { return 0; } // TODO(bugs.webrtc.org/9676): Remove default implementation. void AudioDecoder::GeneratePlc(size_t /*requested_samples_per_channel*/, rtc::BufferT* /*concealment_audio*/) {} int AudioDecoder::ErrorCode() { return 0; } int AudioDecoder::PacketDuration(const uint8_t* encoded, size_t encoded_len) const { return kNotImplemented; } int AudioDecoder::PacketDurationRedundant(const uint8_t* encoded, size_t encoded_len) const { return kNotImplemented; } bool AudioDecoder::PacketHasFec(const uint8_t* encoded, size_t encoded_len) const { return false; } AudioDecoder::SpeechType AudioDecoder::ConvertSpeechType(int16_t type) { switch (type) { case 0: // TODO(hlundin): Both iSAC and Opus return 0 for speech. case 1: return kSpeech; case 2: return kComfortNoise; default: assert(false); return kSpeech; } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/audio_codecs/audio_decoder.h0000664000175000017500000001751414475643423024315 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_AUDIO_CODECS_AUDIO_DECODER_H_ #define API_AUDIO_CODECS_AUDIO_DECODER_H_ #include #include #include #include #include "absl/types/optional.h" #include "api/array_view.h" #include "rtc_base/buffer.h" #include "rtc_base/constructor_magic.h" namespace webrtc { class AudioDecoder { public: enum SpeechType { kSpeech = 1, kComfortNoise = 2, }; // Used by PacketDuration below. Save the value -1 for errors. enum { kNotImplemented = -2 }; AudioDecoder() = default; virtual ~AudioDecoder() = default; class EncodedAudioFrame { public: struct DecodeResult { size_t num_decoded_samples; SpeechType speech_type; }; virtual ~EncodedAudioFrame() = default; // Returns the duration in samples-per-channel of this audio frame. // If no duration can be ascertained, returns zero. virtual size_t Duration() const = 0; // Returns true if this packet contains DTX. virtual bool IsDtxPacket() const; // Decodes this frame of audio and writes the result in |decoded|. // |decoded| must be large enough to store as many samples as indicated by a // call to Duration() . On success, returns an absl::optional containing the // total number of samples across all channels, as well as whether the // decoder produced comfort noise or speech. On failure, returns an empty // absl::optional. Decode may be called at most once per frame object. virtual absl::optional Decode( rtc::ArrayView decoded) const = 0; }; struct ParseResult { ParseResult(); ParseResult(uint32_t timestamp, int priority, std::unique_ptr frame); ParseResult(ParseResult&& b); ~ParseResult(); ParseResult& operator=(ParseResult&& b); // The timestamp of the frame is in samples per channel. uint32_t timestamp; // The relative priority of the frame compared to other frames of the same // payload and the same timeframe. A higher value means a lower priority. // The highest priority is zero - negative values are not allowed. int priority; std::unique_ptr frame; }; // Let the decoder parse this payload and prepare zero or more decodable // frames. Each frame must be between 10 ms and 120 ms long. The caller must // ensure that the AudioDecoder object outlives any frame objects returned by // this call. The decoder is free to swap or move the data from the |payload| // buffer. |timestamp| is the input timestamp, in samples, corresponding to // the start of the payload. virtual std::vector ParsePayload(rtc::Buffer&& payload, uint32_t timestamp); // TODO(bugs.webrtc.org/10098): The Decode and DecodeRedundant methods are // obsolete; callers should call ParsePayload instead. For now, subclasses // must still implement DecodeInternal. // Decodes |encode_len| bytes from |encoded| and writes the result in // |decoded|. The maximum bytes allowed to be written into |decoded| is // |max_decoded_bytes|. Returns the total number of samples across all // channels. If the decoder produced comfort noise, |speech_type| // is set to kComfortNoise, otherwise it is kSpeech. The desired output // sample rate is provided in |sample_rate_hz|, which must be valid for the // codec at hand. int Decode(const uint8_t* encoded, size_t encoded_len, int sample_rate_hz, size_t max_decoded_bytes, int16_t* decoded, SpeechType* speech_type); // Same as Decode(), but interfaces to the decoders redundant decode function. // The default implementation simply calls the regular Decode() method. int DecodeRedundant(const uint8_t* encoded, size_t encoded_len, int sample_rate_hz, size_t max_decoded_bytes, int16_t* decoded, SpeechType* speech_type); // Indicates if the decoder implements the DecodePlc method. virtual bool HasDecodePlc() const; // Calls the packet-loss concealment of the decoder to update the state after // one or several lost packets. The caller has to make sure that the // memory allocated in |decoded| should accommodate |num_frames| frames. virtual size_t DecodePlc(size_t num_frames, int16_t* decoded); // Asks the decoder to generate packet-loss concealment and append it to the // end of |concealment_audio|. The concealment audio should be in // channel-interleaved format, with as many channels as the last decoded // packet produced. The implementation must produce at least // requested_samples_per_channel, or nothing at all. This is a signal to the // caller to conceal the loss with other means. If the implementation provides // concealment samples, it is also responsible for "stitching" it together // with the decoded audio on either side of the concealment. // Note: The default implementation of GeneratePlc will be deleted soon. All // implementations must provide their own, which can be a simple as a no-op. // TODO(bugs.webrtc.org/9676): Remove default impementation. virtual void GeneratePlc(size_t requested_samples_per_channel, rtc::BufferT* concealment_audio); // Resets the decoder state (empty buffers etc.). virtual void Reset() = 0; // Returns the last error code from the decoder. virtual int ErrorCode(); // Returns the duration in samples-per-channel of the payload in |encoded| // which is |encoded_len| bytes long. Returns kNotImplemented if no duration // estimate is available, or -1 in case of an error. virtual int PacketDuration(const uint8_t* encoded, size_t encoded_len) const; // Returns the duration in samples-per-channel of the redandant payload in // |encoded| which is |encoded_len| bytes long. Returns kNotImplemented if no // duration estimate is available, or -1 in case of an error. virtual int PacketDurationRedundant(const uint8_t* encoded, size_t encoded_len) const; // Detects whether a packet has forward error correction. The packet is // comprised of the samples in |encoded| which is |encoded_len| bytes long. // Returns true if the packet has FEC and false otherwise. virtual bool PacketHasFec(const uint8_t* encoded, size_t encoded_len) const; // Returns the actual sample rate of the decoder's output. This value may not // change during the lifetime of the decoder. virtual int SampleRateHz() const = 0; // The number of channels in the decoder's output. This value may not change // during the lifetime of the decoder. virtual size_t Channels() const = 0; protected: static SpeechType ConvertSpeechType(int16_t type); virtual int DecodeInternal(const uint8_t* encoded, size_t encoded_len, int sample_rate_hz, int16_t* decoded, SpeechType* speech_type) = 0; virtual int DecodeRedundantInternal(const uint8_t* encoded, size_t encoded_len, int sample_rate_hz, int16_t* decoded, SpeechType* speech_type); private: RTC_DISALLOW_COPY_AND_ASSIGN(AudioDecoder); }; } // namespace webrtc #endif // API_AUDIO_CODECS_AUDIO_DECODER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/audio_codecs/audio_encoder.cc0000664000175000017500000000655714475643423024472 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "api/audio_codecs/audio_encoder.h" #include "rtc_base/checks.h" #include "rtc_base/trace_event.h" namespace webrtc { ANAStats::ANAStats() = default; ANAStats::~ANAStats() = default; ANAStats::ANAStats(const ANAStats&) = default; AudioEncoder::EncodedInfo::EncodedInfo() = default; AudioEncoder::EncodedInfo::EncodedInfo(const EncodedInfo&) = default; AudioEncoder::EncodedInfo::EncodedInfo(EncodedInfo&&) = default; AudioEncoder::EncodedInfo::~EncodedInfo() = default; AudioEncoder::EncodedInfo& AudioEncoder::EncodedInfo::operator=( const EncodedInfo&) = default; AudioEncoder::EncodedInfo& AudioEncoder::EncodedInfo::operator=(EncodedInfo&&) = default; int AudioEncoder::RtpTimestampRateHz() const { return SampleRateHz(); } AudioEncoder::EncodedInfo AudioEncoder::Encode( uint32_t rtp_timestamp, rtc::ArrayView audio, rtc::Buffer* encoded) { TRACE_EVENT0("webrtc", "AudioEncoder::Encode"); RTC_CHECK_EQ(audio.size(), static_cast(NumChannels() * SampleRateHz() / 100)); const size_t old_size = encoded->size(); EncodedInfo info = EncodeImpl(rtp_timestamp, audio, encoded); RTC_CHECK_EQ(encoded->size() - old_size, info.encoded_bytes); return info; } bool AudioEncoder::SetFec(bool enable) { return !enable; } bool AudioEncoder::SetDtx(bool enable) { return !enable; } bool AudioEncoder::GetDtx() const { return false; } bool AudioEncoder::SetApplication(Application application) { return false; } void AudioEncoder::SetMaxPlaybackRate(int frequency_hz) {} void AudioEncoder::SetTargetBitrate(int target_bps) {} rtc::ArrayView> AudioEncoder::ReclaimContainedEncoders() { return nullptr; } bool AudioEncoder::EnableAudioNetworkAdaptor(const std::string& config_string, RtcEventLog* event_log) { return false; } void AudioEncoder::DisableAudioNetworkAdaptor() {} void AudioEncoder::OnReceivedUplinkPacketLossFraction( float uplink_packet_loss_fraction) {} void AudioEncoder::OnReceivedUplinkRecoverablePacketLossFraction( float uplink_recoverable_packet_loss_fraction) { RTC_NOTREACHED(); } void AudioEncoder::OnReceivedTargetAudioBitrate(int target_audio_bitrate_bps) { OnReceivedUplinkBandwidth(target_audio_bitrate_bps, absl::nullopt); } void AudioEncoder::OnReceivedUplinkBandwidth( int target_audio_bitrate_bps, absl::optional bwe_period_ms) {} void AudioEncoder::OnReceivedUplinkAllocation(BitrateAllocationUpdate update) { OnReceivedUplinkBandwidth(update.target_bitrate.bps(), update.bwe_period.ms()); } void AudioEncoder::OnReceivedRtt(int rtt_ms) {} void AudioEncoder::OnReceivedOverhead(size_t overhead_bytes_per_packet) {} void AudioEncoder::SetReceiverFrameLengthRange(int min_frame_length_ms, int max_frame_length_ms) {} ANAStats AudioEncoder::GetANAStats() const { return ANAStats(); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/audio_codecs/audio_encoder.h0000664000175000017500000002567314475643423024334 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_AUDIO_CODECS_AUDIO_ENCODER_H_ #define API_AUDIO_CODECS_AUDIO_ENCODER_H_ #include #include #include #include #include "absl/types/optional.h" #include "api/array_view.h" #include "api/call/bitrate_allocation.h" #include "api/units/time_delta.h" #include "rtc_base/buffer.h" #include "rtc_base/deprecation.h" namespace webrtc { class RtcEventLog; // Statistics related to Audio Network Adaptation. struct ANAStats { ANAStats(); ANAStats(const ANAStats&); ~ANAStats(); // Number of actions taken by the ANA bitrate controller since the start of // the call. If this value is not set, it indicates that the bitrate // controller is disabled. absl::optional bitrate_action_counter; // Number of actions taken by the ANA channel controller since the start of // the call. If this value is not set, it indicates that the channel // controller is disabled. absl::optional channel_action_counter; // Number of actions taken by the ANA DTX controller since the start of the // call. If this value is not set, it indicates that the DTX controller is // disabled. absl::optional dtx_action_counter; // Number of actions taken by the ANA FEC controller since the start of the // call. If this value is not set, it indicates that the FEC controller is // disabled. absl::optional fec_action_counter; // Number of times the ANA frame length controller decided to increase the // frame length since the start of the call. If this value is not set, it // indicates that the frame length controller is disabled. absl::optional frame_length_increase_counter; // Number of times the ANA frame length controller decided to decrease the // frame length since the start of the call. If this value is not set, it // indicates that the frame length controller is disabled. absl::optional frame_length_decrease_counter; // The uplink packet loss fractions as set by the ANA FEC controller. If this // value is not set, it indicates that the ANA FEC controller is not active. absl::optional uplink_packet_loss_fraction; }; // This is the interface class for encoders in AudioCoding module. Each codec // type must have an implementation of this class. class AudioEncoder { public: // Used for UMA logging of codec usage. The same codecs, with the // same values, must be listed in // src/tools/metrics/histograms/histograms.xml in chromium to log // correct values. enum class CodecType { kOther = 0, // Codec not specified, and/or not listed in this enum kOpus = 1, kIsac = 2, kPcmA = 3, kPcmU = 4, kG722 = 5, kIlbc = 6, // Number of histogram bins in the UMA logging of codec types. The // total number of different codecs that are logged cannot exceed this // number. kMaxLoggedAudioCodecTypes }; struct EncodedInfoLeaf { size_t encoded_bytes = 0; uint32_t encoded_timestamp = 0; int payload_type = 0; bool send_even_if_empty = false; bool speech = true; CodecType encoder_type = CodecType::kOther; }; // This is the main struct for auxiliary encoding information. Each encoded // packet should be accompanied by one EncodedInfo struct, containing the // total number of |encoded_bytes|, the |encoded_timestamp| and the // |payload_type|. If the packet contains redundant encodings, the |redundant| // vector will be populated with EncodedInfoLeaf structs. Each struct in the // vector represents one encoding; the order of structs in the vector is the // same as the order in which the actual payloads are written to the byte // stream. When EncoderInfoLeaf structs are present in the vector, the main // struct's |encoded_bytes| will be the sum of all the |encoded_bytes| in the // vector. struct EncodedInfo : public EncodedInfoLeaf { EncodedInfo(); EncodedInfo(const EncodedInfo&); EncodedInfo(EncodedInfo&&); ~EncodedInfo(); EncodedInfo& operator=(const EncodedInfo&); EncodedInfo& operator=(EncodedInfo&&); std::vector redundant; }; virtual ~AudioEncoder() = default; // Returns the input sample rate in Hz and the number of input channels. // These are constants set at instantiation time. virtual int SampleRateHz() const = 0; virtual size_t NumChannels() const = 0; // Returns the rate at which the RTP timestamps are updated. The default // implementation returns SampleRateHz(). virtual int RtpTimestampRateHz() const; // Returns the number of 10 ms frames the encoder will put in the next // packet. This value may only change when Encode() outputs a packet; i.e., // the encoder may vary the number of 10 ms frames from packet to packet, but // it must decide the length of the next packet no later than when outputting // the preceding packet. virtual size_t Num10MsFramesInNextPacket() const = 0; // Returns the maximum value that can be returned by // Num10MsFramesInNextPacket(). virtual size_t Max10MsFramesInAPacket() const = 0; // Returns the current target bitrate in bits/s. The value -1 means that the // codec adapts the target automatically, and a current target cannot be // provided. virtual int GetTargetBitrate() const = 0; // Accepts one 10 ms block of input audio (i.e., SampleRateHz() / 100 * // NumChannels() samples). Multi-channel audio must be sample-interleaved. // The encoder appends zero or more bytes of output to |encoded| and returns // additional encoding information. Encode() checks some preconditions, calls // EncodeImpl() which does the actual work, and then checks some // postconditions. EncodedInfo Encode(uint32_t rtp_timestamp, rtc::ArrayView audio, rtc::Buffer* encoded); // Resets the encoder to its starting state, discarding any input that has // been fed to the encoder but not yet emitted in a packet. virtual void Reset() = 0; // Enables or disables codec-internal FEC (forward error correction). Returns // true if the codec was able to comply. The default implementation returns // true when asked to disable FEC and false when asked to enable it (meaning // that FEC isn't supported). virtual bool SetFec(bool enable); // Enables or disables codec-internal VAD/DTX. Returns true if the codec was // able to comply. The default implementation returns true when asked to // disable DTX and false when asked to enable it (meaning that DTX isn't // supported). virtual bool SetDtx(bool enable); // Returns the status of codec-internal DTX. The default implementation always // returns false. virtual bool GetDtx() const; // Sets the application mode. Returns true if the codec was able to comply. // The default implementation just returns false. enum class Application { kSpeech, kAudio }; virtual bool SetApplication(Application application); // Tells the encoder about the highest sample rate the decoder is expected to // use when decoding the bitstream. The encoder would typically use this // information to adjust the quality of the encoding. The default // implementation does nothing. virtual void SetMaxPlaybackRate(int frequency_hz); // This is to be deprecated. Please use |OnReceivedTargetAudioBitrate| // instead. // Tells the encoder what average bitrate we'd like it to produce. The // encoder is free to adjust or disregard the given bitrate (the default // implementation does the latter). RTC_DEPRECATED virtual void SetTargetBitrate(int target_bps); // Causes this encoder to let go of any other encoders it contains, and // returns a pointer to an array where they are stored (which is required to // live as long as this encoder). Unless the returned array is empty, you may // not call any methods on this encoder afterwards, except for the // destructor. The default implementation just returns an empty array. // NOTE: This method is subject to change. Do not call or override it. virtual rtc::ArrayView> ReclaimContainedEncoders(); // Enables audio network adaptor. Returns true if successful. virtual bool EnableAudioNetworkAdaptor(const std::string& config_string, RtcEventLog* event_log); // Disables audio network adaptor. virtual void DisableAudioNetworkAdaptor(); // Provides uplink packet loss fraction to this encoder to allow it to adapt. // |uplink_packet_loss_fraction| is in the range [0.0, 1.0]. virtual void OnReceivedUplinkPacketLossFraction( float uplink_packet_loss_fraction); RTC_DEPRECATED virtual void OnReceivedUplinkRecoverablePacketLossFraction( float uplink_recoverable_packet_loss_fraction); // Provides target audio bitrate to this encoder to allow it to adapt. virtual void OnReceivedTargetAudioBitrate(int target_bps); // Provides target audio bitrate and corresponding probing interval of // the bandwidth estimator to this encoder to allow it to adapt. virtual void OnReceivedUplinkBandwidth(int target_audio_bitrate_bps, absl::optional bwe_period_ms); // Provides target audio bitrate and corresponding probing interval of // the bandwidth estimator to this encoder to allow it to adapt. virtual void OnReceivedUplinkAllocation(BitrateAllocationUpdate update); // Provides RTT to this encoder to allow it to adapt. virtual void OnReceivedRtt(int rtt_ms); // Provides overhead to this encoder to adapt. The overhead is the number of // bytes that will be added to each packet the encoder generates. virtual void OnReceivedOverhead(size_t overhead_bytes_per_packet); // To allow encoder to adapt its frame length, it must be provided the frame // length range that receivers can accept. virtual void SetReceiverFrameLengthRange(int min_frame_length_ms, int max_frame_length_ms); // Get statistics related to audio network adaptation. virtual ANAStats GetANAStats() const; // The range of frame lengths that are supported or nullopt if there's no sch // information. This is used to calculated the full bitrate range, including // overhead. virtual absl::optional> GetFrameLengthRange() const = 0; protected: // Subclasses implement this to perform the actual encoding. Called by // Encode(). virtual EncodedInfo EncodeImpl(uint32_t rtp_timestamp, rtc::ArrayView audio, rtc::Buffer* encoded) = 0; }; } // namespace webrtc #endif // API_AUDIO_CODECS_AUDIO_ENCODER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/call/0000775000175000017500000000000014475643423017640 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/call/bitrate_allocation.h0000664000175000017500000000350314475643423023651 0ustar00arunarun/* * Copyright 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_CALL_BITRATE_ALLOCATION_H_ #define API_CALL_BITRATE_ALLOCATION_H_ #include "api/units/data_rate.h" #include "api/units/time_delta.h" namespace webrtc { // BitrateAllocationUpdate provides information to allocated streams about their // bitrate allocation. It originates from the BitrateAllocater class and is // propagated from there. struct BitrateAllocationUpdate { // The allocated target bitrate. Media streams should produce this amount of // data. (Note that this may include packet overhead depending on // configuration.) DataRate target_bitrate = DataRate::Zero(); // The allocated part of the estimated link capacity. This is more stable than // the target as it is based on the underlying link capacity estimate. This // should be used to change encoder configuration when the cost of change is // high. DataRate stable_target_bitrate = DataRate::Zero(); // Predicted packet loss ratio. double packet_loss_ratio = 0; // Predicted round trip time. TimeDelta round_trip_time = TimeDelta::PlusInfinity(); // |bwe_period| is deprecated, use |stable_target_bitrate| allocation instead. TimeDelta bwe_period = TimeDelta::PlusInfinity(); // Congestion window pushback bitrate reduction fraction. Used in // VideoStreamEncoder to reduce the bitrate by the given fraction // by dropping frames. double cwnd_reduce_ratio = 0; }; } // namespace webrtc #endif // API_CALL_BITRATE_ALLOCATION_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/function_view.h0000664000175000017500000001116714475643423021763 0ustar00arunarun/* * Copyright 2016 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_FUNCTION_VIEW_H_ #define API_FUNCTION_VIEW_H_ #include #include #include "rtc_base/checks.h" // Just like std::function, FunctionView will wrap any callable and hide its // actual type, exposing only its signature. But unlike std::function, // FunctionView doesn't own its callable---it just points to it. Thus, it's a // good choice mainly as a function argument when the callable argument will // not be called again once the function has returned. // // Its constructors are implicit, so that callers won't have to convert lambdas // and other callables to FunctionView explicitly. This is // safe because FunctionView is only a reference to the real callable. // // Example use: // // void SomeFunction(rtc::FunctionView index_transform); // ... // SomeFunction([](int i) { return 2 * i + 1; }); // // Note: FunctionView is tiny (essentially just two pointers) and trivially // copyable, so it's probably cheaper to pass it by value than by const // reference. namespace rtc { template class FunctionView; // Undefined. template class FunctionView final { public: // Constructor for lambdas and other callables; it accepts every type of // argument except those noted in its enable_if call. template < typename F, typename std::enable_if< // Not for function pointers; we have another constructor for that // below. !std::is_function::type>::type>::value && // Not for nullptr; we have another constructor for that below. !std::is_same::type>::value && // Not for FunctionView objects; we have another constructor for that // (the implicitly declared copy constructor). !std::is_same::type>::type>::value>::type* = nullptr> FunctionView(F&& f) : call_(CallVoidPtr::type>) { f_.void_ptr = &f; } // Constructor that accepts function pointers. If the argument is null, the // result is an empty FunctionView. template < typename F, typename std::enable_if::type>::type>::value>::type* = nullptr> FunctionView(F&& f) : call_(f ? CallFunPtr::type> : nullptr) { f_.fun_ptr = reinterpret_cast(f); } // Constructor that accepts nullptr. It creates an empty FunctionView. template ::type>::value>::type* = nullptr> FunctionView(F&& f) : call_(nullptr) {} // Default constructor. Creates an empty FunctionView. FunctionView() : call_(nullptr) {} RetT operator()(ArgT... args) const { RTC_DCHECK(call_); return call_(f_, std::forward(args)...); } // Returns true if we have a function, false if we don't (i.e., we're null). explicit operator bool() const { return !!call_; } private: union VoidUnion { void* void_ptr; void (*fun_ptr)(); }; template static RetT CallVoidPtr(VoidUnion vu, ArgT... args) { return (*static_cast(vu.void_ptr))(std::forward(args)...); } template static RetT CallFunPtr(VoidUnion vu, ArgT... args) { return (reinterpret_cast::type>(vu.fun_ptr))( std::forward(args)...); } // A pointer to the callable thing, with type information erased. It's a // union because we have to use separate types depending on if the callable // thing is a function pointer or something else. VoidUnion f_; // Pointer to a dispatch function that knows the type of the callable thing // that's stored in f_, and how to call it. A FunctionView object is empty // (null) iff call_ is null. RetT (*call_)(VoidUnion, ArgT...); }; } // namespace rtc #endif // API_FUNCTION_VIEW_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/meson.build0000664000175000017500000000173014475643423021070 0ustar00arunarunapi_sources = [ 'audio/audio_frame.cc', 'audio/channel_layout.cc', 'audio/echo_canceller3_config.cc', 'audio_codecs/audio_decoder.cc', 'audio_codecs/audio_encoder.cc', 'rtp_headers.cc', 'rtp_packet_info.cc', 'task_queue/task_queue_base.cc', 'units/data_rate.cc', 'units/data_size.cc', 'units/frequency.cc', 'units/time_delta.cc', 'units/timestamp.cc', 'video/color_space.cc', 'video/hdr_metadata.cc', 'video/video_content_type.cc', 'video/video_timing.cc', ] api_headers = [ ['', 'array_view.h'], ['', 'scoped_refptr.h'], ['audio', 'echo_canceller3_config.h'], ['audio', 'echo_control.h'], ] foreach h : api_headers install_headers( join_paths(h[0], h[1]), subdir: join_paths(include_subdir, 'api', h[0]) ) endforeach libapi = static_library('libapi', api_sources, dependencies: common_deps, include_directories: webrtc_inc, cpp_args : common_cxxflags ) api_dep = declare_dependency( link_with: libapi ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/ref_counted_base.h0000664000175000017500000000215414475643423022367 0ustar00arunarun/* * Copyright 2017 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_REF_COUNTED_BASE_H_ #define API_REF_COUNTED_BASE_H_ #include "rtc_base/constructor_magic.h" #include "rtc_base/ref_count.h" #include "rtc_base/ref_counter.h" namespace rtc { class RefCountedBase { public: RefCountedBase() = default; void AddRef() const { ref_count_.IncRef(); } RefCountReleaseStatus Release() const { const auto status = ref_count_.DecRef(); if (status == RefCountReleaseStatus::kDroppedLastRef) { delete this; } return status; } protected: virtual ~RefCountedBase() = default; private: mutable webrtc::webrtc_impl::RefCounter ref_count_{0}; RTC_DISALLOW_COPY_AND_ASSIGN(RefCountedBase); }; } // namespace rtc #endif // API_REF_COUNTED_BASE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/rtp_headers.cc0000664000175000017500000000306614475643423021541 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "api/rtp_headers.h" namespace webrtc { RTPHeaderExtension::RTPHeaderExtension() : hasTransmissionTimeOffset(false), transmissionTimeOffset(0), hasAbsoluteSendTime(false), absoluteSendTime(0), hasTransportSequenceNumber(false), transportSequenceNumber(0), hasAudioLevel(false), voiceActivity(false), audioLevel(0), hasVideoRotation(false), videoRotation(kVideoRotation_0), hasVideoContentType(false), videoContentType(VideoContentType::UNSPECIFIED), has_video_timing(false) {} RTPHeaderExtension::RTPHeaderExtension(const RTPHeaderExtension& other) = default; RTPHeaderExtension& RTPHeaderExtension::operator=( const RTPHeaderExtension& other) = default; RTPHeader::RTPHeader() : markerBit(false), payloadType(0), sequenceNumber(0), timestamp(0), ssrc(0), numCSRCs(0), arrOfCSRCs(), paddingLength(0), headerLength(0), payload_type_frequency(0), extension() {} RTPHeader::RTPHeader(const RTPHeader& other) = default; RTPHeader& RTPHeader::operator=(const RTPHeader& other) = default; } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/rtp_headers.h0000664000175000017500000001554714475643423021412 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_RTP_HEADERS_H_ #define API_RTP_HEADERS_H_ #include #include #include #include "absl/types/optional.h" #include "api/array_view.h" #include "api/units/timestamp.h" #include "api/video/color_space.h" #include "api/video/video_content_type.h" #include "api/video/video_rotation.h" #include "api/video/video_timing.h" namespace webrtc { struct FeedbackRequest { // Determines whether the recv delta as specified in // https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01 // should be included. bool include_timestamps; // Include feedback of received packets in the range [sequence_number - // sequence_count + 1, sequence_number]. That is, no feedback will be sent if // sequence_count is zero. int sequence_count; }; // The Absolute Capture Time extension is used to stamp RTP packets with a NTP // timestamp showing when the first audio or video frame in a packet was // originally captured. The intent of this extension is to provide a way to // accomplish audio-to-video synchronization when RTCP-terminating intermediate // systems (e.g. mixers) are involved. See: // http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time struct AbsoluteCaptureTime { // Absolute capture timestamp is the NTP timestamp of when the first frame in // a packet was originally captured. This timestamp MUST be based on the same // clock as the clock used to generate NTP timestamps for RTCP sender reports // on the capture system. // // It’s not always possible to do an NTP clock readout at the exact moment of // when a media frame is captured. A capture system MAY postpone the readout // until a more convenient time. A capture system SHOULD have known delays // (e.g. from hardware buffers) subtracted from the readout to make the final // timestamp as close to the actual capture time as possible. // // This field is encoded as a 64-bit unsigned fixed-point number with the high // 32 bits for the timestamp in seconds and low 32 bits for the fractional // part. This is also known as the UQ32.32 format and is what the RTP // specification defines as the canonical format to represent NTP timestamps. uint64_t absolute_capture_timestamp; // Estimated capture clock offset is the sender’s estimate of the offset // between its own NTP clock and the capture system’s NTP clock. The sender is // here defined as the system that owns the NTP clock used to generate the NTP // timestamps for the RTCP sender reports on this stream. The sender system is // typically either the capture system or a mixer. // // This field is encoded as a 64-bit two’s complement signed fixed-point // number with the high 32 bits for the seconds and low 32 bits for the // fractional part. It’s intended to make it easy for a receiver, that knows // how to estimate the sender system’s NTP clock, to also estimate the capture // system’s NTP clock: // // Capture NTP Clock = Sender NTP Clock + Capture Clock Offset absl::optional estimated_capture_clock_offset; }; inline bool operator==(const AbsoluteCaptureTime& lhs, const AbsoluteCaptureTime& rhs) { return (lhs.absolute_capture_timestamp == rhs.absolute_capture_timestamp) && (lhs.estimated_capture_clock_offset == rhs.estimated_capture_clock_offset); } inline bool operator!=(const AbsoluteCaptureTime& lhs, const AbsoluteCaptureTime& rhs) { return !(lhs == rhs); } struct RTPHeaderExtension { RTPHeaderExtension(); RTPHeaderExtension(const RTPHeaderExtension& other); RTPHeaderExtension& operator=(const RTPHeaderExtension& other); static constexpr int kAbsSendTimeFraction = 18; Timestamp GetAbsoluteSendTimestamp() const { RTC_DCHECK(hasAbsoluteSendTime); RTC_DCHECK(absoluteSendTime < (1ul << 24)); return Timestamp::Micros((absoluteSendTime * 1000000ll) / (1 << kAbsSendTimeFraction)); } TimeDelta GetAbsoluteSendTimeDelta(uint32_t previous_sendtime) const { RTC_DCHECK(hasAbsoluteSendTime); RTC_DCHECK(absoluteSendTime < (1ul << 24)); RTC_DCHECK(previous_sendtime < (1ul << 24)); int32_t delta = static_cast((absoluteSendTime - previous_sendtime) << 8) >> 8; return TimeDelta::Micros((delta * 1000000ll) / (1 << kAbsSendTimeFraction)); } bool hasTransmissionTimeOffset; int32_t transmissionTimeOffset; bool hasAbsoluteSendTime; uint32_t absoluteSendTime; absl::optional absolute_capture_time; bool hasTransportSequenceNumber; uint16_t transportSequenceNumber; absl::optional feedback_request; // Audio Level includes both level in dBov and voiced/unvoiced bit. See: // https://tools.ietf.org/html/rfc6464#section-3 bool hasAudioLevel; bool voiceActivity; uint8_t audioLevel; // For Coordination of Video Orientation. See // http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/12.07.00_60/ // ts_126114v120700p.pdf bool hasVideoRotation; VideoRotation videoRotation; // TODO(ilnik): Refactor this and one above to be absl::optional() and remove // a corresponding bool flag. bool hasVideoContentType; VideoContentType videoContentType; bool has_video_timing; VideoSendTiming video_timing; VideoPlayoutDelay playout_delay; // For identification of a stream when ssrc is not signaled. See // https://tools.ietf.org/html/draft-ietf-avtext-rid-09 // TODO(danilchap): Update url from draft to release version. std::string stream_id; std::string repaired_stream_id; // For identifying the media section used to interpret this RTP packet. See // https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-38 std::string mid; absl::optional color_space; }; enum { kRtpCsrcSize = 15 }; // RFC 3550 page 13 struct RTPHeader { RTPHeader(); RTPHeader(const RTPHeader& other); RTPHeader& operator=(const RTPHeader& other); bool markerBit; uint8_t payloadType; uint16_t sequenceNumber; uint32_t timestamp; uint32_t ssrc; uint8_t numCSRCs; uint32_t arrOfCSRCs[kRtpCsrcSize]; size_t paddingLength; size_t headerLength; int payload_type_frequency; RTPHeaderExtension extension; }; // RTCP mode to use. Compound mode is described by RFC 4585 and reduced-size // RTCP mode is described by RFC 5506. enum class RtcpMode { kOff, kCompound, kReducedSize }; enum NetworkState { kNetworkUp, kNetworkDown, }; } // namespace webrtc #endif // API_RTP_HEADERS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/rtp_packet_info.cc0000664000175000017500000000400314475643423022400 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "api/rtp_packet_info.h" #include #include namespace webrtc { RtpPacketInfo::RtpPacketInfo() : ssrc_(0), rtp_timestamp_(0), receive_time_ms_(-1) {} RtpPacketInfo::RtpPacketInfo( uint32_t ssrc, std::vector csrcs, uint32_t rtp_timestamp, absl::optional audio_level, absl::optional absolute_capture_time, int64_t receive_time_ms) : ssrc_(ssrc), csrcs_(std::move(csrcs)), rtp_timestamp_(rtp_timestamp), audio_level_(audio_level), absolute_capture_time_(absolute_capture_time), receive_time_ms_(receive_time_ms) {} RtpPacketInfo::RtpPacketInfo(const RTPHeader& rtp_header, int64_t receive_time_ms) : ssrc_(rtp_header.ssrc), rtp_timestamp_(rtp_header.timestamp), receive_time_ms_(receive_time_ms) { const auto& extension = rtp_header.extension; const auto csrcs_count = std::min(rtp_header.numCSRCs, kRtpCsrcSize); csrcs_.assign(&rtp_header.arrOfCSRCs[0], &rtp_header.arrOfCSRCs[csrcs_count]); if (extension.hasAudioLevel) { audio_level_ = extension.audioLevel; } absolute_capture_time_ = extension.absolute_capture_time; } bool operator==(const RtpPacketInfo& lhs, const RtpPacketInfo& rhs) { return (lhs.ssrc() == rhs.ssrc()) && (lhs.csrcs() == rhs.csrcs()) && (lhs.rtp_timestamp() == rhs.rtp_timestamp()) && (lhs.audio_level() == rhs.audio_level()) && (lhs.absolute_capture_time() == rhs.absolute_capture_time()) && (lhs.receive_time_ms() == rhs.receive_time_ms()); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/rtp_packet_info.h0000664000175000017500000000631114475643423022246 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_RTP_PACKET_INFO_H_ #define API_RTP_PACKET_INFO_H_ #include #include #include #include "absl/types/optional.h" #include "api/rtp_headers.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { // // Structure to hold information about a received |RtpPacket|. It is primarily // used to carry per-packet information from when a packet is received until // the information is passed to |SourceTracker|. // class RTC_EXPORT RtpPacketInfo { public: RtpPacketInfo(); RtpPacketInfo(uint32_t ssrc, std::vector csrcs, uint32_t rtp_timestamp, absl::optional audio_level, absl::optional absolute_capture_time, int64_t receive_time_ms); RtpPacketInfo(const RTPHeader& rtp_header, int64_t receive_time_ms); RtpPacketInfo(const RtpPacketInfo& other) = default; RtpPacketInfo(RtpPacketInfo&& other) = default; RtpPacketInfo& operator=(const RtpPacketInfo& other) = default; RtpPacketInfo& operator=(RtpPacketInfo&& other) = default; uint32_t ssrc() const { return ssrc_; } void set_ssrc(uint32_t value) { ssrc_ = value; } const std::vector& csrcs() const { return csrcs_; } void set_csrcs(std::vector value) { csrcs_ = std::move(value); } uint32_t rtp_timestamp() const { return rtp_timestamp_; } void set_rtp_timestamp(uint32_t value) { rtp_timestamp_ = value; } absl::optional audio_level() const { return audio_level_; } void set_audio_level(absl::optional value) { audio_level_ = value; } const absl::optional& absolute_capture_time() const { return absolute_capture_time_; } void set_absolute_capture_time( const absl::optional& value) { absolute_capture_time_ = value; } int64_t receive_time_ms() const { return receive_time_ms_; } void set_receive_time_ms(int64_t value) { receive_time_ms_ = value; } private: // Fields from the RTP header: // https://tools.ietf.org/html/rfc3550#section-5.1 uint32_t ssrc_; std::vector csrcs_; uint32_t rtp_timestamp_; // Fields from the Audio Level header extension: // https://tools.ietf.org/html/rfc6464#section-3 absl::optional audio_level_; // Fields from the Absolute Capture Time header extension: // http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time absl::optional absolute_capture_time_; // Local |webrtc::Clock|-based timestamp of when the packet was received. int64_t receive_time_ms_; }; bool operator==(const RtpPacketInfo& lhs, const RtpPacketInfo& rhs); inline bool operator!=(const RtpPacketInfo& lhs, const RtpPacketInfo& rhs) { return !(lhs == rhs); } } // namespace webrtc #endif // API_RTP_PACKET_INFO_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/rtp_packet_infos.h0000664000175000017500000001032214475643423022426 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_RTP_PACKET_INFOS_H_ #define API_RTP_PACKET_INFOS_H_ #include #include #include #include "api/ref_counted_base.h" #include "api/rtp_packet_info.h" #include "api/scoped_refptr.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { // Semi-immutable structure to hold information about packets used to assemble // an audio or video frame. Uses internal reference counting to make it very // cheap to copy. // // We should ideally just use |std::vector| and have it // |std::move()|-ed as the per-packet information is transferred from one object // to another. But moving the info, instead of copying it, is not easily done // for the current video code. class RTC_EXPORT RtpPacketInfos { public: using vector_type = std::vector; using value_type = vector_type::value_type; using size_type = vector_type::size_type; using difference_type = vector_type::difference_type; using const_reference = vector_type::const_reference; using const_pointer = vector_type::const_pointer; using const_iterator = vector_type::const_iterator; using const_reverse_iterator = vector_type::const_reverse_iterator; using reference = const_reference; using pointer = const_pointer; using iterator = const_iterator; using reverse_iterator = const_reverse_iterator; RtpPacketInfos() {} explicit RtpPacketInfos(const vector_type& entries) : data_(Data::Create(entries)) {} explicit RtpPacketInfos(vector_type&& entries) : data_(Data::Create(std::move(entries))) {} RtpPacketInfos(const RtpPacketInfos& other) = default; RtpPacketInfos(RtpPacketInfos&& other) = default; RtpPacketInfos& operator=(const RtpPacketInfos& other) = default; RtpPacketInfos& operator=(RtpPacketInfos&& other) = default; const_reference operator[](size_type pos) const { return entries()[pos]; } const_reference at(size_type pos) const { return entries().at(pos); } const_reference front() const { return entries().front(); } const_reference back() const { return entries().back(); } const_iterator begin() const { return entries().begin(); } const_iterator end() const { return entries().end(); } const_reverse_iterator rbegin() const { return entries().rbegin(); } const_reverse_iterator rend() const { return entries().rend(); } const_iterator cbegin() const { return entries().cbegin(); } const_iterator cend() const { return entries().cend(); } const_reverse_iterator crbegin() const { return entries().crbegin(); } const_reverse_iterator crend() const { return entries().crend(); } bool empty() const { return entries().empty(); } size_type size() const { return entries().size(); } private: class Data : public rtc::RefCountedBase { public: static rtc::scoped_refptr Create(const vector_type& entries) { // Performance optimization for the empty case. if (entries.empty()) { return nullptr; } return new Data(entries); } static rtc::scoped_refptr Create(vector_type&& entries) { // Performance optimization for the empty case. if (entries.empty()) { return nullptr; } return new Data(std::move(entries)); } const vector_type& entries() const { return entries_; } private: explicit Data(const vector_type& entries) : entries_(entries) {} explicit Data(vector_type&& entries) : entries_(std::move(entries)) {} ~Data() override {} const vector_type entries_; }; static const vector_type& empty_entries() { static const vector_type& value = *new vector_type(); return value; } const vector_type& entries() const { if (data_ != nullptr) { return data_->entries(); } else { return empty_entries(); } } rtc::scoped_refptr data_; }; } // namespace webrtc #endif // API_RTP_PACKET_INFOS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/scoped_refptr.h0000664000175000017500000001025014475643423021733 0ustar00arunarun/* * Copyright 2011 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Originally these classes are from Chromium. // http://src.chromium.org/viewvc/chrome/trunk/src/base/memory/ref_counted.h?view=markup // // A smart pointer class for reference counted objects. Use this class instead // of calling AddRef and Release manually on a reference counted object to // avoid common memory leaks caused by forgetting to Release an object // reference. Sample usage: // // class MyFoo : public RefCounted { // ... // }; // // void some_function() { // scoped_refptr foo = new MyFoo(); // foo->Method(param); // // |foo| is released when this function returns // } // // void some_other_function() { // scoped_refptr foo = new MyFoo(); // ... // foo = nullptr; // explicitly releases |foo| // ... // if (foo) // foo->Method(param); // } // // The above examples show how scoped_refptr acts like a pointer to T. // Given two scoped_refptr classes, it is also possible to exchange // references between the two objects, like so: // // { // scoped_refptr a = new MyFoo(); // scoped_refptr b; // // b.swap(a); // // now, |b| references the MyFoo object, and |a| references null. // } // // To make both |a| and |b| in the above example reference the same MyFoo // object, simply use the assignment operator: // // { // scoped_refptr a = new MyFoo(); // scoped_refptr b; // // b = a; // // now, |a| and |b| each own a reference to the same MyFoo object. // } // #ifndef API_SCOPED_REFPTR_H_ #define API_SCOPED_REFPTR_H_ #include #include namespace rtc { template class scoped_refptr { public: typedef T element_type; scoped_refptr() : ptr_(nullptr) {} scoped_refptr(T* p) : ptr_(p) { // NOLINT(runtime/explicit) if (ptr_) ptr_->AddRef(); } scoped_refptr(const scoped_refptr& r) : ptr_(r.ptr_) { if (ptr_) ptr_->AddRef(); } template scoped_refptr(const scoped_refptr& r) : ptr_(r.get()) { if (ptr_) ptr_->AddRef(); } // Move constructors. scoped_refptr(scoped_refptr&& r) noexcept : ptr_(r.release()) {} template scoped_refptr(scoped_refptr&& r) noexcept : ptr_(r.release()) {} ~scoped_refptr() { if (ptr_) ptr_->Release(); } T* get() const { return ptr_; } operator T*() const { return ptr_; } T* operator->() const { return ptr_; } // Returns the (possibly null) raw pointer, and makes the scoped_refptr hold a // null pointer, all without touching the reference count of the underlying // pointed-to object. The object is still reference counted, and the caller of // release() is now the proud owner of one reference, so it is responsible for // calling Release() once on the object when no longer using it. T* release() { T* retVal = ptr_; ptr_ = nullptr; return retVal; } scoped_refptr& operator=(T* p) { // AddRef first so that self assignment should work if (p) p->AddRef(); if (ptr_) ptr_->Release(); ptr_ = p; return *this; } scoped_refptr& operator=(const scoped_refptr& r) { return *this = r.ptr_; } template scoped_refptr& operator=(const scoped_refptr& r) { return *this = r.get(); } scoped_refptr& operator=(scoped_refptr&& r) noexcept { scoped_refptr(std::move(r)).swap(*this); return *this; } template scoped_refptr& operator=(scoped_refptr&& r) noexcept { scoped_refptr(std::move(r)).swap(*this); return *this; } void swap(T** pp) noexcept { T* p = ptr_; ptr_ = *pp; *pp = p; } void swap(scoped_refptr& r) noexcept { swap(&r.ptr_); } protected: T* ptr_; }; } // namespace rtc #endif // API_SCOPED_REFPTR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/task_queue/0000775000175000017500000000000014475643423021073 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/task_queue/queued_task.h0000664000175000017500000000235414475643423023562 0ustar00arunarun/* * Copyright 2018 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_TASK_QUEUE_QUEUED_TASK_H_ #define API_TASK_QUEUE_QUEUED_TASK_H_ namespace webrtc { // Base interface for asynchronously executed tasks. // The interface basically consists of a single function, Run(), that executes // on the target queue. For more details see the Run() method and TaskQueue. class QueuedTask { public: virtual ~QueuedTask() = default; // Main routine that will run when the task is executed on the desired queue. // The task should return |true| to indicate that it should be deleted or // |false| to indicate that the queue should consider ownership of the task // having been transferred. Returning |false| can be useful if a task has // re-posted itself to a different queue or is otherwise being re-used. virtual bool Run() = 0; }; } // namespace webrtc #endif // API_TASK_QUEUE_QUEUED_TASK_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/task_queue/task_queue_base.cc0000664000175000017500000000363414475643423024550 0ustar00arunarun/* * Copyright 2019 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "api/task_queue/task_queue_base.h" #include "absl/base/attributes.h" #include "absl/base/config.h" #include "rtc_base/checks.h" #if defined(ABSL_HAVE_THREAD_LOCAL) namespace webrtc { namespace { ABSL_CONST_INIT thread_local TaskQueueBase* current = nullptr; } // namespace TaskQueueBase* TaskQueueBase::Current() { return current; } TaskQueueBase::CurrentTaskQueueSetter::CurrentTaskQueueSetter( TaskQueueBase* task_queue) : previous_(current) { current = task_queue; } TaskQueueBase::CurrentTaskQueueSetter::~CurrentTaskQueueSetter() { current = previous_; } } // namespace webrtc #elif defined(WEBRTC_POSIX) #include namespace webrtc { namespace { ABSL_CONST_INIT pthread_key_t g_queue_ptr_tls = 0; void InitializeTls() { RTC_CHECK(pthread_key_create(&g_queue_ptr_tls, nullptr) == 0); } pthread_key_t GetQueuePtrTls() { static pthread_once_t init_once = PTHREAD_ONCE_INIT; RTC_CHECK(pthread_once(&init_once, &InitializeTls) == 0); return g_queue_ptr_tls; } } // namespace TaskQueueBase* TaskQueueBase::Current() { return static_cast(pthread_getspecific(GetQueuePtrTls())); } TaskQueueBase::CurrentTaskQueueSetter::CurrentTaskQueueSetter( TaskQueueBase* task_queue) : previous_(TaskQueueBase::Current()) { pthread_setspecific(GetQueuePtrTls(), task_queue); } TaskQueueBase::CurrentTaskQueueSetter::~CurrentTaskQueueSetter() { pthread_setspecific(GetQueuePtrTls(), previous_); } } // namespace webrtc #else #error Unsupported platform #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/task_queue/task_queue_base.h0000664000175000017500000000667114475643423024416 0ustar00arunarun/* * Copyright 2019 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_TASK_QUEUE_TASK_QUEUE_BASE_H_ #define API_TASK_QUEUE_TASK_QUEUE_BASE_H_ #include #include "api/task_queue/queued_task.h" #include "rtc_base/system/rtc_export.h" #include "rtc_base/thread_annotations.h" namespace webrtc { // Asynchronously executes tasks in a way that guarantees that they're executed // in FIFO order and that tasks never overlap. Tasks may always execute on the // same worker thread and they may not. To DCHECK that tasks are executing on a // known task queue, use IsCurrent(). class RTC_LOCKABLE RTC_EXPORT TaskQueueBase { public: // Starts destruction of the task queue. // On return ensures no task are running and no new tasks are able to start // on the task queue. // Responsible for deallocation. Deallocation may happen syncrhoniously during // Delete or asynchronously after Delete returns. // Code not running on the TaskQueue should not make any assumption when // TaskQueue is deallocated and thus should not call any methods after Delete. // Code running on the TaskQueue should not call Delete, but can assume // TaskQueue still exists and may call other methods, e.g. PostTask. virtual void Delete() = 0; // Schedules a task to execute. Tasks are executed in FIFO order. // If |task->Run()| returns true, task is deleted on the task queue // before next QueuedTask starts executing. // When a TaskQueue is deleted, pending tasks will not be executed but they // will be deleted. The deletion of tasks may happen synchronously on the // TaskQueue or it may happen asynchronously after TaskQueue is deleted. // This may vary from one implementation to the next so assumptions about // lifetimes of pending tasks should not be made. virtual void PostTask(std::unique_ptr task) = 0; // Schedules a task to execute a specified number of milliseconds from when // the call is made. The precision should be considered as "best effort" // and in some cases, such as on Windows when all high precision timers have // been used up, can be off by as much as 15 millseconds. virtual void PostDelayedTask(std::unique_ptr task, uint32_t milliseconds) = 0; // Returns the task queue that is running the current thread. // Returns nullptr if this thread is not associated with any task queue. static TaskQueueBase* Current(); bool IsCurrent() const { return Current() == this; } protected: class CurrentTaskQueueSetter { public: explicit CurrentTaskQueueSetter(TaskQueueBase* task_queue); CurrentTaskQueueSetter(const CurrentTaskQueueSetter&) = delete; CurrentTaskQueueSetter& operator=(const CurrentTaskQueueSetter&) = delete; ~CurrentTaskQueueSetter(); private: TaskQueueBase* const previous_; }; // Users of the TaskQueue should call Delete instead of directly deleting // this object. virtual ~TaskQueueBase() = default; }; struct TaskQueueDeleter { void operator()(TaskQueueBase* task_queue) const { task_queue->Delete(); } }; } // namespace webrtc #endif // API_TASK_QUEUE_TASK_QUEUE_BASE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/units/0000775000175000017500000000000014475643423020067 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/units/data_rate.cc0000664000175000017500000000167214475643423022330 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "api/units/data_rate.h" #include "api/array_view.h" #include "rtc_base/strings/string_builder.h" namespace webrtc { std::string ToString(DataRate value) { char buf[64]; rtc::SimpleStringBuilder sb(buf); if (value.IsPlusInfinity()) { sb << "+inf bps"; } else if (value.IsMinusInfinity()) { sb << "-inf bps"; } else { if (value.bps() == 0 || value.bps() % 1000 != 0) { sb << value.bps() << " bps"; } else { sb << value.kbps() << " kbps"; } } return sb.str(); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/units/data_rate.h0000664000175000017500000001256414475643423022174 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_UNITS_DATA_RATE_H_ #define API_UNITS_DATA_RATE_H_ #ifdef UNIT_TEST #include // no-presubmit-check TODO(webrtc:8982) #endif // UNIT_TEST #include #include #include #include "api/units/data_size.h" #include "api/units/frequency.h" #include "api/units/time_delta.h" #include "rtc_base/checks.h" #include "rtc_base/units/unit_base.h" namespace webrtc { // DataRate is a class that represents a given data rate. This can be used to // represent bandwidth, encoding bitrate, etc. The internal storage is bits per // second (bps). class DataRate final : public rtc_units_impl::RelativeUnit { public: template static constexpr DataRate BitsPerSec(T value) { static_assert(std::is_arithmetic::value, ""); return FromValue(value); } template static constexpr DataRate BytesPerSec(T value) { static_assert(std::is_arithmetic::value, ""); return FromFraction(8, value); } template static constexpr DataRate KilobitsPerSec(T value) { static_assert(std::is_arithmetic::value, ""); return FromFraction(1000, value); } static constexpr DataRate Infinity() { return PlusInfinity(); } DataRate() = delete; template constexpr T bps() const { return ToValue(); } template constexpr T bytes_per_sec() const { return ToFraction<8, T>(); } template constexpr T kbps() const { return ToFraction<1000, T>(); } constexpr int64_t bps_or(int64_t fallback_value) const { return ToValueOr(fallback_value); } constexpr int64_t kbps_or(int64_t fallback_value) const { return ToFractionOr<1000>(fallback_value); } private: // Bits per second used internally to simplify debugging by making the value // more recognizable. friend class rtc_units_impl::UnitBase; using RelativeUnit::RelativeUnit; static constexpr bool one_sided = true; }; namespace data_rate_impl { inline constexpr int64_t Microbits(const DataSize& size) { constexpr int64_t kMaxBeforeConversion = std::numeric_limits::max() / 8000000; RTC_DCHECK_LE(size.bytes(), kMaxBeforeConversion) << "size is too large to be expressed in microbits"; return size.bytes() * 8000000; } inline constexpr int64_t MillibytePerSec(const DataRate& size) { constexpr int64_t kMaxBeforeConversion = std::numeric_limits::max() / (1000 / 8); RTC_DCHECK_LE(size.bps(), kMaxBeforeConversion) << "rate is too large to be expressed in microbytes per second"; return size.bps() * (1000 / 8); } } // namespace data_rate_impl inline constexpr DataRate operator/(const DataSize size, const TimeDelta duration) { return DataRate::BitsPerSec(data_rate_impl::Microbits(size) / duration.us()); } inline constexpr TimeDelta operator/(const DataSize size, const DataRate rate) { return TimeDelta::Micros(data_rate_impl::Microbits(size) / rate.bps()); } inline constexpr DataSize operator*(const DataRate rate, const TimeDelta duration) { int64_t microbits = rate.bps() * duration.us(); return DataSize::Bytes((microbits + 4000000) / 8000000); } inline constexpr DataSize operator*(const TimeDelta duration, const DataRate rate) { return rate * duration; } inline constexpr DataSize operator/(const DataRate rate, const Frequency frequency) { int64_t millihertz = frequency.millihertz(); // Note that the value is truncated here reather than rounded, potentially // introducing an error of .5 bytes if rounding were expected. return DataSize::Bytes(data_rate_impl::MillibytePerSec(rate) / millihertz); } inline constexpr Frequency operator/(const DataRate rate, const DataSize size) { return Frequency::MilliHertz(data_rate_impl::MillibytePerSec(rate) / size.bytes()); } inline constexpr DataRate operator*(const DataSize size, const Frequency frequency) { RTC_DCHECK(frequency.IsZero() || size.bytes() <= std::numeric_limits::max() / 8 / frequency.millihertz()); int64_t millibits_per_second = size.bytes() * 8 * frequency.millihertz(); return DataRate::BitsPerSec((millibits_per_second + 500) / 1000); } inline constexpr DataRate operator*(const Frequency frequency, const DataSize size) { return size * frequency; } std::string ToString(DataRate value); inline std::string ToLogString(DataRate value) { return ToString(value); } #ifdef UNIT_TEST inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982) std::ostream& stream, // no-presubmit-check TODO(webrtc:8982) DataRate value) { return stream << ToString(value); } #endif // UNIT_TEST } // namespace webrtc #endif // API_UNITS_DATA_RATE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/units/data_size.cc0000664000175000017500000000152114475643423022340 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "api/units/data_size.h" #include "api/array_view.h" #include "rtc_base/strings/string_builder.h" namespace webrtc { std::string ToString(DataSize value) { char buf[64]; rtc::SimpleStringBuilder sb(buf); if (value.IsPlusInfinity()) { sb << "+inf bytes"; } else if (value.IsMinusInfinity()) { sb << "-inf bytes"; } else { sb << value.bytes() << " bytes"; } return sb.str(); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/units/data_size.h0000664000175000017500000000344514475643423022211 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_UNITS_DATA_SIZE_H_ #define API_UNITS_DATA_SIZE_H_ #ifdef UNIT_TEST #include // no-presubmit-check TODO(webrtc:8982) #endif // UNIT_TEST #include #include #include "rtc_base/units/unit_base.h" namespace webrtc { // DataSize is a class represeting a count of bytes. class DataSize final : public rtc_units_impl::RelativeUnit { public: template static constexpr DataSize Bytes(T value) { static_assert(std::is_arithmetic::value, ""); return FromValue(value); } static constexpr DataSize Infinity() { return PlusInfinity(); } DataSize() = delete; template constexpr T bytes() const { return ToValue(); } constexpr int64_t bytes_or(int64_t fallback_value) const { return ToValueOr(fallback_value); } private: friend class rtc_units_impl::UnitBase; using RelativeUnit::RelativeUnit; static constexpr bool one_sided = true; }; std::string ToString(DataSize value); inline std::string ToLogString(DataSize value) { return ToString(value); } #ifdef UNIT_TEST inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982) std::ostream& stream, // no-presubmit-check TODO(webrtc:8982) DataSize value) { return stream << ToString(value); } #endif // UNIT_TEST } // namespace webrtc #endif // API_UNITS_DATA_SIZE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/units/frequency.cc0000664000175000017500000000164314475643423022403 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "api/units/frequency.h" #include "rtc_base/strings/string_builder.h" namespace webrtc { std::string ToString(Frequency value) { char buf[64]; rtc::SimpleStringBuilder sb(buf); if (value.IsPlusInfinity()) { sb << "+inf Hz"; } else if (value.IsMinusInfinity()) { sb << "-inf Hz"; } else if (value.millihertz() % 1000 != 0) { sb.AppendFormat("%.3f Hz", value.hertz()); } else { sb << value.hertz() << " Hz"; } return sb.str(); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/units/frequency.h0000664000175000017500000000620714475643423022246 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_UNITS_FREQUENCY_H_ #define API_UNITS_FREQUENCY_H_ #ifdef UNIT_TEST #include // no-presubmit-check TODO(webrtc:8982) #endif // UNIT_TEST #include #include #include #include #include "api/units/time_delta.h" #include "rtc_base/units/unit_base.h" namespace webrtc { class Frequency final : public rtc_units_impl::RelativeUnit { public: template static constexpr Frequency MilliHertz(T value) { static_assert(std::is_arithmetic::value, ""); return FromValue(value); } template static constexpr Frequency Hertz(T value) { static_assert(std::is_arithmetic::value, ""); return FromFraction(1'000, value); } template static constexpr Frequency KiloHertz(T value) { static_assert(std::is_arithmetic::value, ""); return FromFraction(1'000'000, value); } Frequency() = delete; template constexpr T hertz() const { return ToFraction<1000, T>(); } template constexpr T millihertz() const { return ToValue(); } private: friend class rtc_units_impl::UnitBase; using RelativeUnit::RelativeUnit; static constexpr bool one_sided = true; }; inline constexpr Frequency operator/(int64_t nominator, const TimeDelta& interval) { constexpr int64_t kKiloPerMicro = 1000 * 1000000; RTC_DCHECK_LE(nominator, std::numeric_limits::max() / kKiloPerMicro); RTC_CHECK(interval.IsFinite()); RTC_CHECK(!interval.IsZero()); return Frequency::MilliHertz(nominator * kKiloPerMicro / interval.us()); } inline constexpr TimeDelta operator/(int64_t nominator, const Frequency& frequency) { constexpr int64_t kMegaPerMilli = 1000000 * 1000; RTC_DCHECK_LE(nominator, std::numeric_limits::max() / kMegaPerMilli); RTC_CHECK(frequency.IsFinite()); RTC_CHECK(!frequency.IsZero()); return TimeDelta::Micros(nominator * kMegaPerMilli / frequency.millihertz()); } inline constexpr double operator*(Frequency frequency, TimeDelta time_delta) { return frequency.hertz() * time_delta.seconds(); } inline constexpr double operator*(TimeDelta time_delta, Frequency frequency) { return frequency * time_delta; } std::string ToString(Frequency value); inline std::string ToLogString(Frequency value) { return ToString(value); } #ifdef UNIT_TEST inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982) std::ostream& stream, // no-presubmit-check TODO(webrtc:8982) Frequency value) { return stream << ToString(value); } #endif // UNIT_TEST } // namespace webrtc #endif // API_UNITS_FREQUENCY_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/units/time_delta.cc0000664000175000017500000000176314475643423022514 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "api/units/time_delta.h" #include "api/array_view.h" #include "rtc_base/strings/string_builder.h" namespace webrtc { std::string ToString(TimeDelta value) { char buf[64]; rtc::SimpleStringBuilder sb(buf); if (value.IsPlusInfinity()) { sb << "+inf ms"; } else if (value.IsMinusInfinity()) { sb << "-inf ms"; } else { if (value.us() == 0 || (value.us() % 1000) != 0) sb << value.us() << " us"; else if (value.ms() % 1000 != 0) sb << value.ms() << " ms"; else sb << value.seconds() << " s"; } return sb.str(); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/units/time_delta.h0000664000175000017500000000614214475643423022352 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_UNITS_TIME_DELTA_H_ #define API_UNITS_TIME_DELTA_H_ #ifdef UNIT_TEST #include // no-presubmit-check TODO(webrtc:8982) #endif // UNIT_TEST #include #include #include #include "rtc_base/units/unit_base.h" namespace webrtc { // TimeDelta represents the difference between two timestamps. Commonly this can // be a duration. However since two Timestamps are not guaranteed to have the // same epoch (they might come from different computers, making exact // synchronisation infeasible), the duration covered by a TimeDelta can be // undefined. To simplify usage, it can be constructed and converted to // different units, specifically seconds (s), milliseconds (ms) and // microseconds (us). class TimeDelta final : public rtc_units_impl::RelativeUnit { public: template static constexpr TimeDelta Seconds(T value) { static_assert(std::is_arithmetic::value, ""); return FromFraction(1'000'000, value); } template static constexpr TimeDelta Millis(T value) { static_assert(std::is_arithmetic::value, ""); return FromFraction(1'000, value); } template static constexpr TimeDelta Micros(T value) { static_assert(std::is_arithmetic::value, ""); return FromValue(value); } TimeDelta() = delete; template constexpr T seconds() const { return ToFraction<1000000, T>(); } template constexpr T ms() const { return ToFraction<1000, T>(); } template constexpr T us() const { return ToValue(); } template constexpr T ns() const { return ToMultiple<1000, T>(); } constexpr int64_t seconds_or(int64_t fallback_value) const { return ToFractionOr<1000000>(fallback_value); } constexpr int64_t ms_or(int64_t fallback_value) const { return ToFractionOr<1000>(fallback_value); } constexpr int64_t us_or(int64_t fallback_value) const { return ToValueOr(fallback_value); } constexpr TimeDelta Abs() const { return us() < 0 ? TimeDelta::Micros(-us()) : *this; } private: friend class rtc_units_impl::UnitBase; using RelativeUnit::RelativeUnit; static constexpr bool one_sided = false; }; std::string ToString(TimeDelta value); inline std::string ToLogString(TimeDelta value) { return ToString(value); } #ifdef UNIT_TEST inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982) std::ostream& stream, // no-presubmit-check TODO(webrtc:8982) TimeDelta value) { return stream << ToString(value); } #endif // UNIT_TEST } // namespace webrtc #endif // API_UNITS_TIME_DELTA_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/units/timestamp.cc0000664000175000017500000000176014475643423022405 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "api/units/timestamp.h" #include "api/array_view.h" #include "rtc_base/strings/string_builder.h" namespace webrtc { std::string ToString(Timestamp value) { char buf[64]; rtc::SimpleStringBuilder sb(buf); if (value.IsPlusInfinity()) { sb << "+inf ms"; } else if (value.IsMinusInfinity()) { sb << "-inf ms"; } else { if (value.us() == 0 || (value.us() % 1000) != 0) sb << value.us() << " us"; else if (value.ms() % 1000 != 0) sb << value.ms() << " ms"; else sb << value.seconds() << " s"; } return sb.str(); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/units/timestamp.h0000664000175000017500000001046314475643423022247 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_UNITS_TIMESTAMP_H_ #define API_UNITS_TIMESTAMP_H_ #ifdef UNIT_TEST #include // no-presubmit-check TODO(webrtc:8982) #endif // UNIT_TEST #include #include #include "api/units/time_delta.h" #include "rtc_base/checks.h" namespace webrtc { // Timestamp represents the time that has passed since some unspecified epoch. // The epoch is assumed to be before any represented timestamps, this means that // negative values are not valid. The most notable feature is that the // difference of two Timestamps results in a TimeDelta. class Timestamp final : public rtc_units_impl::UnitBase { public: template static constexpr Timestamp Seconds(T value) { static_assert(std::is_arithmetic::value, ""); return FromFraction(1'000'000, value); } template static constexpr Timestamp Millis(T value) { static_assert(std::is_arithmetic::value, ""); return FromFraction(1'000, value); } template static constexpr Timestamp Micros(T value) { static_assert(std::is_arithmetic::value, ""); return FromValue(value); } Timestamp() = delete; template constexpr T seconds() const { return ToFraction<1000000, T>(); } template constexpr T ms() const { return ToFraction<1000, T>(); } template constexpr T us() const { return ToValue(); } constexpr int64_t seconds_or(int64_t fallback_value) const { return ToFractionOr<1000000>(fallback_value); } constexpr int64_t ms_or(int64_t fallback_value) const { return ToFractionOr<1000>(fallback_value); } constexpr int64_t us_or(int64_t fallback_value) const { return ToValueOr(fallback_value); } constexpr Timestamp operator+(const TimeDelta delta) const { if (IsPlusInfinity() || delta.IsPlusInfinity()) { RTC_DCHECK(!IsMinusInfinity()); RTC_DCHECK(!delta.IsMinusInfinity()); return PlusInfinity(); } else if (IsMinusInfinity() || delta.IsMinusInfinity()) { RTC_DCHECK(!IsPlusInfinity()); RTC_DCHECK(!delta.IsPlusInfinity()); return MinusInfinity(); } return Timestamp::Micros(us() + delta.us()); } constexpr Timestamp operator-(const TimeDelta delta) const { if (IsPlusInfinity() || delta.IsMinusInfinity()) { RTC_DCHECK(!IsMinusInfinity()); RTC_DCHECK(!delta.IsPlusInfinity()); return PlusInfinity(); } else if (IsMinusInfinity() || delta.IsPlusInfinity()) { RTC_DCHECK(!IsPlusInfinity()); RTC_DCHECK(!delta.IsMinusInfinity()); return MinusInfinity(); } return Timestamp::Micros(us() - delta.us()); } constexpr TimeDelta operator-(const Timestamp other) const { if (IsPlusInfinity() || other.IsMinusInfinity()) { RTC_DCHECK(!IsMinusInfinity()); RTC_DCHECK(!other.IsPlusInfinity()); return TimeDelta::PlusInfinity(); } else if (IsMinusInfinity() || other.IsPlusInfinity()) { RTC_DCHECK(!IsPlusInfinity()); RTC_DCHECK(!other.IsMinusInfinity()); return TimeDelta::MinusInfinity(); } return TimeDelta::Micros(us() - other.us()); } constexpr Timestamp& operator-=(const TimeDelta delta) { *this = *this - delta; return *this; } constexpr Timestamp& operator+=(const TimeDelta delta) { *this = *this + delta; return *this; } private: friend class rtc_units_impl::UnitBase; using UnitBase::UnitBase; static constexpr bool one_sided = true; }; std::string ToString(Timestamp value); inline std::string ToLogString(Timestamp value) { return ToString(value); } #ifdef UNIT_TEST inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982) std::ostream& stream, // no-presubmit-check TODO(webrtc:8982) Timestamp value) { return stream << ToString(value); } #endif // UNIT_TEST } // namespace webrtc #endif // API_UNITS_TIMESTAMP_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/video/0000775000175000017500000000000014475643423020033 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/video/color_space.cc0000664000175000017500000001563314475643423022643 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "api/video/color_space.h" namespace webrtc { namespace { // Try to convert |enum_value| into the enum class T. |enum_bitmask| is created // by the funciton below. Returns true if conversion was successful, false // otherwise. template bool SetFromUint8(uint8_t enum_value, uint64_t enum_bitmask, T* out) { if ((enum_value < 64) && ((enum_bitmask >> enum_value) & 1)) { *out = static_cast(enum_value); return true; } return false; } // This function serves as an assert for the constexpr function below. It's on // purpose not declared as constexpr so that it causes a build problem if enum // values of 64 or above are used. The bitmask and the code generating it would // have to be extended if the standard is updated to include enum values >= 64. int EnumMustBeLessThan64() { return -1; } template constexpr int MakeMask(const int index, const int length, T (&values)[N]) { return length > 1 ? (MakeMask(index, 1, values) + MakeMask(index + 1, length - 1, values)) : (static_cast(values[index]) < 64 ? (uint64_t{1} << static_cast(values[index])) : EnumMustBeLessThan64()); } // Create a bitmask where each bit corresponds to one potential enum value. // |values| should be an array listing all possible enum values. The bit is set // to one if the corresponding enum exists. Only works for enums with values // less than 64. template constexpr uint64_t CreateEnumBitmask(T (&values)[N]) { return MakeMask(0, N, values); } bool SetChromaSitingFromUint8(uint8_t enum_value, ColorSpace::ChromaSiting* chroma_siting) { constexpr ColorSpace::ChromaSiting kChromaSitings[] = { ColorSpace::ChromaSiting::kUnspecified, ColorSpace::ChromaSiting::kCollocated, ColorSpace::ChromaSiting::kHalf}; constexpr uint64_t enum_bitmask = CreateEnumBitmask(kChromaSitings); return SetFromUint8(enum_value, enum_bitmask, chroma_siting); } } // namespace ColorSpace::ColorSpace() = default; ColorSpace::ColorSpace(const ColorSpace& other) = default; ColorSpace::ColorSpace(ColorSpace&& other) = default; ColorSpace& ColorSpace::operator=(const ColorSpace& other) = default; ColorSpace::ColorSpace(PrimaryID primaries, TransferID transfer, MatrixID matrix, RangeID range) : ColorSpace(primaries, transfer, matrix, range, ChromaSiting::kUnspecified, ChromaSiting::kUnspecified, nullptr) {} ColorSpace::ColorSpace(PrimaryID primaries, TransferID transfer, MatrixID matrix, RangeID range, ChromaSiting chroma_siting_horz, ChromaSiting chroma_siting_vert, const HdrMetadata* hdr_metadata) : primaries_(primaries), transfer_(transfer), matrix_(matrix), range_(range), chroma_siting_horizontal_(chroma_siting_horz), chroma_siting_vertical_(chroma_siting_vert), hdr_metadata_(hdr_metadata ? absl::make_optional(*hdr_metadata) : absl::nullopt) {} ColorSpace::PrimaryID ColorSpace::primaries() const { return primaries_; } ColorSpace::TransferID ColorSpace::transfer() const { return transfer_; } ColorSpace::MatrixID ColorSpace::matrix() const { return matrix_; } ColorSpace::RangeID ColorSpace::range() const { return range_; } ColorSpace::ChromaSiting ColorSpace::chroma_siting_horizontal() const { return chroma_siting_horizontal_; } ColorSpace::ChromaSiting ColorSpace::chroma_siting_vertical() const { return chroma_siting_vertical_; } const HdrMetadata* ColorSpace::hdr_metadata() const { return hdr_metadata_ ? &*hdr_metadata_ : nullptr; } bool ColorSpace::set_primaries_from_uint8(uint8_t enum_value) { constexpr PrimaryID kPrimaryIds[] = { PrimaryID::kBT709, PrimaryID::kUnspecified, PrimaryID::kBT470M, PrimaryID::kBT470BG, PrimaryID::kSMPTE170M, PrimaryID::kSMPTE240M, PrimaryID::kFILM, PrimaryID::kBT2020, PrimaryID::kSMPTEST428, PrimaryID::kSMPTEST431, PrimaryID::kSMPTEST432, PrimaryID::kJEDECP22}; constexpr uint64_t enum_bitmask = CreateEnumBitmask(kPrimaryIds); return SetFromUint8(enum_value, enum_bitmask, &primaries_); } bool ColorSpace::set_transfer_from_uint8(uint8_t enum_value) { constexpr TransferID kTransferIds[] = { TransferID::kBT709, TransferID::kUnspecified, TransferID::kGAMMA22, TransferID::kGAMMA28, TransferID::kSMPTE170M, TransferID::kSMPTE240M, TransferID::kLINEAR, TransferID::kLOG, TransferID::kLOG_SQRT, TransferID::kIEC61966_2_4, TransferID::kBT1361_ECG, TransferID::kIEC61966_2_1, TransferID::kBT2020_10, TransferID::kBT2020_12, TransferID::kSMPTEST2084, TransferID::kSMPTEST428, TransferID::kARIB_STD_B67}; constexpr uint64_t enum_bitmask = CreateEnumBitmask(kTransferIds); return SetFromUint8(enum_value, enum_bitmask, &transfer_); } bool ColorSpace::set_matrix_from_uint8(uint8_t enum_value) { constexpr MatrixID kMatrixIds[] = { MatrixID::kRGB, MatrixID::kBT709, MatrixID::kUnspecified, MatrixID::kFCC, MatrixID::kBT470BG, MatrixID::kSMPTE170M, MatrixID::kSMPTE240M, MatrixID::kYCOCG, MatrixID::kBT2020_NCL, MatrixID::kBT2020_CL, MatrixID::kSMPTE2085, MatrixID::kCDNCLS, MatrixID::kCDCLS, MatrixID::kBT2100_ICTCP}; constexpr uint64_t enum_bitmask = CreateEnumBitmask(kMatrixIds); return SetFromUint8(enum_value, enum_bitmask, &matrix_); } bool ColorSpace::set_range_from_uint8(uint8_t enum_value) { constexpr RangeID kRangeIds[] = {RangeID::kInvalid, RangeID::kLimited, RangeID::kFull, RangeID::kDerived}; constexpr uint64_t enum_bitmask = CreateEnumBitmask(kRangeIds); return SetFromUint8(enum_value, enum_bitmask, &range_); } bool ColorSpace::set_chroma_siting_horizontal_from_uint8(uint8_t enum_value) { return SetChromaSitingFromUint8(enum_value, &chroma_siting_horizontal_); } bool ColorSpace::set_chroma_siting_vertical_from_uint8(uint8_t enum_value) { return SetChromaSitingFromUint8(enum_value, &chroma_siting_vertical_); } void ColorSpace::set_hdr_metadata(const HdrMetadata* hdr_metadata) { hdr_metadata_ = hdr_metadata ? absl::make_optional(*hdr_metadata) : absl::nullopt; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/video/color_space.h0000664000175000017500000001367014475643423022504 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_VIDEO_COLOR_SPACE_H_ #define API_VIDEO_COLOR_SPACE_H_ #include #include "absl/types/optional.h" #include "api/video/hdr_metadata.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { // This class represents color information as specified in T-REC H.273, // available from https://www.itu.int/rec/T-REC-H.273. // // WebRTC's supported codecs: // - VP9 supports color profiles, see VP9 Bitstream & Decoding Process // Specification Version 0.6 Section 7.2.2 "Color config semantics" available // from https://www.webmproject.org. // - VP8 only supports BT.601, see // https://tools.ietf.org/html/rfc6386#section-9.2 // - H264 uses the exact same representation as T-REC H.273. See T-REC-H.264 // E.2.1, "VUI parameters semantics", available from // https://www.itu.int/rec/T-REC-H.264. class RTC_EXPORT ColorSpace { public: enum class PrimaryID : uint8_t { // The indices are equal to the values specified in T-REC H.273 Table 2. kBT709 = 1, kUnspecified = 2, kBT470M = 4, kBT470BG = 5, kSMPTE170M = 6, // Identical to BT601 kSMPTE240M = 7, kFILM = 8, kBT2020 = 9, kSMPTEST428 = 10, kSMPTEST431 = 11, kSMPTEST432 = 12, kJEDECP22 = 22, // Identical to EBU3213-E // When adding/removing entries here, please make sure to do the // corresponding change to kPrimaryIds. }; enum class TransferID : uint8_t { // The indices are equal to the values specified in T-REC H.273 Table 3. kBT709 = 1, kUnspecified = 2, kGAMMA22 = 4, kGAMMA28 = 5, kSMPTE170M = 6, kSMPTE240M = 7, kLINEAR = 8, kLOG = 9, kLOG_SQRT = 10, kIEC61966_2_4 = 11, kBT1361_ECG = 12, kIEC61966_2_1 = 13, kBT2020_10 = 14, kBT2020_12 = 15, kSMPTEST2084 = 16, kSMPTEST428 = 17, kARIB_STD_B67 = 18, // When adding/removing entries here, please make sure to do the // corresponding change to kTransferIds. }; enum class MatrixID : uint8_t { // The indices are equal to the values specified in T-REC H.273 Table 4. kRGB = 0, kBT709 = 1, kUnspecified = 2, kFCC = 4, kBT470BG = 5, kSMPTE170M = 6, kSMPTE240M = 7, kYCOCG = 8, kBT2020_NCL = 9, kBT2020_CL = 10, kSMPTE2085 = 11, kCDNCLS = 12, kCDCLS = 13, kBT2100_ICTCP = 14, // When adding/removing entries here, please make sure to do the // corresponding change to kMatrixIds. }; enum class RangeID { // The indices are equal to the values specified at // https://www.webmproject.org/docs/container/#colour for the element Range. kInvalid = 0, // Limited Rec. 709 color range with RGB values ranging from 16 to 235. kLimited = 1, // Full RGB color range with RGB valees from 0 to 255. kFull = 2, // Range is defined by MatrixCoefficients/TransferCharacteristics. kDerived = 3, // When adding/removing entries here, please make sure to do the // corresponding change to kRangeIds. }; enum class ChromaSiting { // Chroma siting specifies how chroma is subsampled relative to the luma // samples in a YUV video frame. // The indices are equal to the values specified at // https://www.webmproject.org/docs/container/#colour for the element // ChromaSitingVert and ChromaSitingHorz. kUnspecified = 0, kCollocated = 1, kHalf = 2, // When adding/removing entries here, please make sure to do the // corresponding change to kChromaSitings. }; ColorSpace(); ColorSpace(const ColorSpace& other); ColorSpace(ColorSpace&& other); ColorSpace& operator=(const ColorSpace& other); ColorSpace(PrimaryID primaries, TransferID transfer, MatrixID matrix, RangeID range); ColorSpace(PrimaryID primaries, TransferID transfer, MatrixID matrix, RangeID range, ChromaSiting chroma_siting_horizontal, ChromaSiting chroma_siting_vertical, const HdrMetadata* hdr_metadata); friend bool operator==(const ColorSpace& lhs, const ColorSpace& rhs) { return lhs.primaries_ == rhs.primaries_ && lhs.transfer_ == rhs.transfer_ && lhs.matrix_ == rhs.matrix_ && lhs.range_ == rhs.range_ && lhs.chroma_siting_horizontal_ == rhs.chroma_siting_horizontal_ && lhs.chroma_siting_vertical_ == rhs.chroma_siting_vertical_ && lhs.hdr_metadata_ == rhs.hdr_metadata_; } friend bool operator!=(const ColorSpace& lhs, const ColorSpace& rhs) { return !(lhs == rhs); } PrimaryID primaries() const; TransferID transfer() const; MatrixID matrix() const; RangeID range() const; ChromaSiting chroma_siting_horizontal() const; ChromaSiting chroma_siting_vertical() const; const HdrMetadata* hdr_metadata() const; bool set_primaries_from_uint8(uint8_t enum_value); bool set_transfer_from_uint8(uint8_t enum_value); bool set_matrix_from_uint8(uint8_t enum_value); bool set_range_from_uint8(uint8_t enum_value); bool set_chroma_siting_horizontal_from_uint8(uint8_t enum_value); bool set_chroma_siting_vertical_from_uint8(uint8_t enum_value); void set_hdr_metadata(const HdrMetadata* hdr_metadata); private: PrimaryID primaries_ = PrimaryID::kUnspecified; TransferID transfer_ = TransferID::kUnspecified; MatrixID matrix_ = MatrixID::kUnspecified; RangeID range_ = RangeID::kInvalid; ChromaSiting chroma_siting_horizontal_ = ChromaSiting::kUnspecified; ChromaSiting chroma_siting_vertical_ = ChromaSiting::kUnspecified; absl::optional hdr_metadata_; }; } // namespace webrtc #endif // API_VIDEO_COLOR_SPACE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/video/hdr_metadata.cc0000664000175000017500000000121514475643423022756 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "api/video/hdr_metadata.h" namespace webrtc { HdrMasteringMetadata::Chromaticity::Chromaticity() = default; HdrMasteringMetadata::HdrMasteringMetadata() = default; HdrMetadata::HdrMetadata() = default; } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/video/hdr_metadata.h0000664000175000017500000000740014475643423022622 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_VIDEO_HDR_METADATA_H_ #define API_VIDEO_HDR_METADATA_H_ namespace webrtc { // SMPTE ST 2086 mastering metadata, // see https://ieeexplore.ieee.org/document/8353899. struct HdrMasteringMetadata { struct Chromaticity { Chromaticity(); bool operator==(const Chromaticity& rhs) const { return x == rhs.x && y == rhs.y; } bool Validate() const { return x >= 0.0 && x <= 1.0 && y >= 0.0 && y <= 1.0; } // xy chromaticity coordinates must be calculated as specified in ISO // 11664-3:2012 Section 7, and must be specified with four decimal places. // The x coordinate should be in the range [0.0001, 0.7400] and the y // coordinate should be in the range [0.0001, 0.8400]. Valid range [0.0000, // 1.0000]. float x = 0.0f; float y = 0.0f; }; HdrMasteringMetadata(); bool operator==(const HdrMasteringMetadata& rhs) const { return ((primary_r == rhs.primary_r) && (primary_g == rhs.primary_g) && (primary_b == rhs.primary_b) && (white_point == rhs.white_point) && (luminance_max == rhs.luminance_max) && (luminance_min == rhs.luminance_min)); } bool Validate() const { return luminance_max >= 0.0 && luminance_max <= 20000.0 && luminance_min >= 0.0 && luminance_min <= 5.0 && primary_r.Validate() && primary_g.Validate() && primary_b.Validate() && white_point.Validate(); } // The nominal primaries of the mastering display. Chromaticity primary_r; Chromaticity primary_g; Chromaticity primary_b; // The nominal chromaticity of the white point of the mastering display. Chromaticity white_point; // The nominal maximum display luminance of the mastering display. Specified // in the unit candela/m2. The value should be in the range [5, 10000] with // zero decimal places. Valid range [0, 20000]. float luminance_max = 0.0f; // The nominal minimum display luminance of the mastering display. Specified // in the unit candela/m2. The value should be in the range [0.0001, 5.0000] // with four decimal places. Valid range [0.0000, 5.0000]. float luminance_min = 0.0f; }; // High dynamic range (HDR) metadata common for HDR10 and WebM/VP9-based HDR // formats. This struct replicates the HDRMetadata struct defined in // https://cs.chromium.org/chromium/src/media/base/hdr_metadata.h struct HdrMetadata { HdrMetadata(); bool operator==(const HdrMetadata& rhs) const { return ( (max_content_light_level == rhs.max_content_light_level) && (max_frame_average_light_level == rhs.max_frame_average_light_level) && (mastering_metadata == rhs.mastering_metadata)); } bool Validate() const { return max_content_light_level >= 0 && max_content_light_level <= 20000 && max_frame_average_light_level >= 0 && max_frame_average_light_level <= 20000 && mastering_metadata.Validate(); } HdrMasteringMetadata mastering_metadata; // Max content light level (CLL), i.e. maximum brightness level present in the // stream, in nits. 1 nit = 1 candela/m2. Valid range [0, 20000]. int max_content_light_level = 0; // Max frame-average light level (FALL), i.e. maximum average brightness of // the brightest frame in the stream, in nits. Valid range [0, 20000]. int max_frame_average_light_level = 0; }; } // namespace webrtc #endif // API_VIDEO_HDR_METADATA_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/video/video_content_type.cc0000664000175000017500000000626614475643423024255 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "api/video/video_content_type.h" // VideoContentType stored as a single byte, which is sent over the network. // Structure: // // 0 1 2 3 4 5 6 7 // +---------------+ // |r r e e e s s c| // // where: // r - reserved bits. // e - 3-bit number of an experiment group counted from 1. 0 means there's no // experiment ongoing. // s - 2-bit simulcast stream id or spatial layer, counted from 1. 0 means that // no simulcast information is set. // c - content type. 0 means real-time video, 1 means screenshare. // namespace webrtc { namespace videocontenttypehelpers { namespace { static constexpr uint8_t kScreenshareBitsSize = 1; static constexpr uint8_t kScreenshareBitsMask = (1u << kScreenshareBitsSize) - 1; static constexpr uint8_t kSimulcastShift = 1; static constexpr uint8_t kSimulcastBitsSize = 2; static constexpr uint8_t kSimulcastBitsMask = ((1u << kSimulcastBitsSize) - 1) << kSimulcastShift; // 0b00000110 static constexpr uint8_t kExperimentShift = 3; static constexpr uint8_t kExperimentBitsSize = 3; static constexpr uint8_t kExperimentBitsMask = ((1u << kExperimentBitsSize) - 1) << kExperimentShift; // 0b00111000 static constexpr uint8_t kTotalBitsSize = kScreenshareBitsSize + kSimulcastBitsSize + kExperimentBitsSize; } // namespace bool SetExperimentId(VideoContentType* content_type, uint8_t experiment_id) { // Store in bits 2-4. if (experiment_id >= (1 << kExperimentBitsSize)) return false; *content_type = static_cast( (static_cast(*content_type) & ~kExperimentBitsMask) | ((experiment_id << kExperimentShift) & kExperimentBitsMask)); return true; } bool SetSimulcastId(VideoContentType* content_type, uint8_t simulcast_id) { // Store in bits 5-6. if (simulcast_id >= (1 << kSimulcastBitsSize)) return false; *content_type = static_cast( (static_cast(*content_type) & ~kSimulcastBitsMask) | ((simulcast_id << kSimulcastShift) & kSimulcastBitsMask)); return true; } uint8_t GetExperimentId(const VideoContentType& content_type) { return (static_cast(content_type) & kExperimentBitsMask) >> kExperimentShift; } uint8_t GetSimulcastId(const VideoContentType& content_type) { return (static_cast(content_type) & kSimulcastBitsMask) >> kSimulcastShift; } bool IsScreenshare(const VideoContentType& content_type) { return (static_cast(content_type) & kScreenshareBitsMask) > 0; } bool IsValidContentType(uint8_t value) { // Any 6-bit value is allowed. return value < (1 << kTotalBitsSize); } const char* ToString(const VideoContentType& content_type) { return IsScreenshare(content_type) ? "screen" : "realtime"; } } // namespace videocontenttypehelpers } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/video/video_content_type.h0000664000175000017500000000226114475643423024106 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_VIDEO_VIDEO_CONTENT_TYPE_H_ #define API_VIDEO_VIDEO_CONTENT_TYPE_H_ #include namespace webrtc { enum class VideoContentType : uint8_t { UNSPECIFIED = 0, SCREENSHARE = 1, }; namespace videocontenttypehelpers { bool SetExperimentId(VideoContentType* content_type, uint8_t experiment_id); bool SetSimulcastId(VideoContentType* content_type, uint8_t simulcast_id); uint8_t GetExperimentId(const VideoContentType& content_type); uint8_t GetSimulcastId(const VideoContentType& content_type); bool IsScreenshare(const VideoContentType& content_type); bool IsValidContentType(uint8_t value); const char* ToString(const VideoContentType& content_type); } // namespace videocontenttypehelpers } // namespace webrtc #endif // API_VIDEO_VIDEO_CONTENT_TYPE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/video/video_rotation.h0000664000175000017500000000133414475643423023232 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_VIDEO_VIDEO_ROTATION_H_ #define API_VIDEO_VIDEO_ROTATION_H_ namespace webrtc { // enum for clockwise rotation. enum VideoRotation { kVideoRotation_0 = 0, kVideoRotation_90 = 90, kVideoRotation_180 = 180, kVideoRotation_270 = 270 }; } // namespace webrtc #endif // API_VIDEO_VIDEO_ROTATION_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/video/video_timing.cc0000664000175000017500000000542714475643423023027 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "api/video/video_timing.h" #include "api/array_view.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/strings/string_builder.h" namespace webrtc { uint16_t VideoSendTiming::GetDeltaCappedMs(int64_t base_ms, int64_t time_ms) { if (time_ms < base_ms) { RTC_DLOG(LS_ERROR) << "Delta " << (time_ms - base_ms) << "ms expected to be positive"; } return rtc::saturated_cast(time_ms - base_ms); } TimingFrameInfo::TimingFrameInfo() : rtp_timestamp(0), capture_time_ms(-1), encode_start_ms(-1), encode_finish_ms(-1), packetization_finish_ms(-1), pacer_exit_ms(-1), network_timestamp_ms(-1), network2_timestamp_ms(-1), receive_start_ms(-1), receive_finish_ms(-1), decode_start_ms(-1), decode_finish_ms(-1), render_time_ms(-1), flags(VideoSendTiming::kNotTriggered) {} int64_t TimingFrameInfo::EndToEndDelay() const { return capture_time_ms >= 0 ? decode_finish_ms - capture_time_ms : -1; } bool TimingFrameInfo::IsLongerThan(const TimingFrameInfo& other) const { int64_t other_delay = other.EndToEndDelay(); return other_delay == -1 || EndToEndDelay() > other_delay; } bool TimingFrameInfo::operator<(const TimingFrameInfo& other) const { return other.IsLongerThan(*this); } bool TimingFrameInfo::operator<=(const TimingFrameInfo& other) const { return !IsLongerThan(other); } bool TimingFrameInfo::IsOutlier() const { return !IsInvalid() && (flags & VideoSendTiming::kTriggeredBySize); } bool TimingFrameInfo::IsTimerTriggered() const { return !IsInvalid() && (flags & VideoSendTiming::kTriggeredByTimer); } bool TimingFrameInfo::IsInvalid() const { return flags == VideoSendTiming::kInvalid; } std::string TimingFrameInfo::ToString() const { if (IsInvalid()) { return ""; } char buf[1024]; rtc::SimpleStringBuilder sb(buf); sb << rtp_timestamp << ',' << capture_time_ms << ',' << encode_start_ms << ',' << encode_finish_ms << ',' << packetization_finish_ms << ',' << pacer_exit_ms << ',' << network_timestamp_ms << ',' << network2_timestamp_ms << ',' << receive_start_ms << ',' << receive_finish_ms << ',' << decode_start_ms << ',' << decode_finish_ms << ',' << render_time_ms << ',' << IsOutlier() << ',' << IsTimerTriggered(); return sb.str(); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/api/video/video_timing.h0000664000175000017500000001152014475643423022660 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef API_VIDEO_VIDEO_TIMING_H_ #define API_VIDEO_VIDEO_TIMING_H_ #include #include #include namespace webrtc { // Video timing timestamps in ms counted from capture_time_ms of a frame. // This structure represents data sent in video-timing RTP header extension. struct VideoSendTiming { enum TimingFrameFlags : uint8_t { kNotTriggered = 0, // Timing info valid, but not to be transmitted. // Used on send-side only. kTriggeredByTimer = 1 << 0, // Frame marked for tracing by periodic timer. kTriggeredBySize = 1 << 1, // Frame marked for tracing due to size. kInvalid = std::numeric_limits::max() // Invalid, ignore! }; // Returns |time_ms - base_ms| capped at max 16-bit value. // Used to fill this data structure as per // https://webrtc.org/experiments/rtp-hdrext/video-timing/ extension stores // 16-bit deltas of timestamps from packet capture time. static uint16_t GetDeltaCappedMs(int64_t base_ms, int64_t time_ms); uint16_t encode_start_delta_ms; uint16_t encode_finish_delta_ms; uint16_t packetization_finish_delta_ms; uint16_t pacer_exit_delta_ms; uint16_t network_timestamp_delta_ms; uint16_t network2_timestamp_delta_ms; uint8_t flags; }; // Used to report precise timings of a 'timing frames'. Contains all important // timestamps for a lifetime of that specific frame. Reported as a string via // GetStats(). Only frame which took the longest between two GetStats calls is // reported. struct TimingFrameInfo { TimingFrameInfo(); // Returns end-to-end delay of a frame, if sender and receiver timestamps are // synchronized, -1 otherwise. int64_t EndToEndDelay() const; // Returns true if current frame took longer to process than |other| frame. // If other frame's clocks are not synchronized, current frame is always // preferred. bool IsLongerThan(const TimingFrameInfo& other) const; // Returns true if flags are set to indicate this frame was marked for tracing // due to the size being outside some limit. bool IsOutlier() const; // Returns true if flags are set to indicate this frame was marked fro tracing // due to cyclic timer. bool IsTimerTriggered() const; // Returns true if the timing data is marked as invalid, in which case it // should be ignored. bool IsInvalid() const; std::string ToString() const; bool operator<(const TimingFrameInfo& other) const; bool operator<=(const TimingFrameInfo& other) const; uint32_t rtp_timestamp; // Identifier of a frame. // All timestamps below are in local monotonous clock of a receiver. // If sender clock is not yet estimated, sender timestamps // (capture_time_ms ... pacer_exit_ms) are negative values, still // relatively correct. int64_t capture_time_ms; // Captrue time of a frame. int64_t encode_start_ms; // Encode start time. int64_t encode_finish_ms; // Encode completion time. int64_t packetization_finish_ms; // Time when frame was passed to pacer. int64_t pacer_exit_ms; // Time when last packet was pushed out of pacer. // Two in-network RTP processor timestamps: meaning is application specific. int64_t network_timestamp_ms; int64_t network2_timestamp_ms; int64_t receive_start_ms; // First received packet time. int64_t receive_finish_ms; // Last received packet time. int64_t decode_start_ms; // Decode start time. int64_t decode_finish_ms; // Decode completion time. int64_t render_time_ms; // Proposed render time to insure smooth playback. uint8_t flags; // Flags indicating validity and/or why tracing was triggered. }; // Minimum and maximum playout delay values from capture to render. // These are best effort values. // // A value < 0 indicates no change from previous valid value. // // min = max = 0 indicates that the receiver should try and render // frame as soon as possible. // // min = x, max = y indicates that the receiver is free to adapt // in the range (x, y) based on network jitter. struct VideoPlayoutDelay { VideoPlayoutDelay() = default; VideoPlayoutDelay(int min_ms, int max_ms) : min_ms(min_ms), max_ms(max_ms) {} int min_ms = -1; int max_ms = -1; bool operator==(const VideoPlayoutDelay& rhs) const { return min_ms == rhs.min_ms && max_ms == rhs.max_ms; } }; // TODO(bugs.webrtc.org/7660): Old name, delete after downstream use is updated. using PlayoutDelay = VideoPlayoutDelay; } // namespace webrtc #endif // API_VIDEO_VIDEO_TIMING_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/audio/0000775000175000017500000000000014475643423017255 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/audio/utility/0000775000175000017500000000000014475643423020760 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/audio/utility/BUILD.gn0000664000175000017500000000265214475643423022152 0ustar00arunarun# Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../../webrtc.gni") group("utility") { deps = [ ":audio_frame_operations" ] } rtc_library("audio_frame_operations") { visibility = [ "*" ] sources = [ "audio_frame_operations.cc", "audio_frame_operations.h", "channel_mixer.cc", "channel_mixer.h", "channel_mixing_matrix.cc", "channel_mixing_matrix.h", ] deps = [ "../../api/audio:audio_frame_api", "../../common_audio", "../../rtc_base:checks", "../../rtc_base:deprecation", "../../rtc_base:rtc_base_approved", "../../system_wrappers:field_trial", ] } if (rtc_include_tests) { rtc_library("utility_tests") { testonly = true sources = [ "audio_frame_operations_unittest.cc", "channel_mixer_unittest.cc", "channel_mixing_matrix_unittest.cc", ] deps = [ ":audio_frame_operations", "../../api/audio:audio_frame_api", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../../test:field_trial", "../../test:test_support", "//testing/gtest", ] } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/audio/utility/audio_frame_operations.cc0000664000175000017500000002253414475643423026013 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "audio/utility/audio_frame_operations.h" #include #include #include #include #include "common_audio/include/audio_util.h" #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_conversions.h" namespace webrtc { namespace { // 2.7ms @ 48kHz, 4ms @ 32kHz, 8ms @ 16kHz. const size_t kMuteFadeFrames = 128; const float kMuteFadeInc = 1.0f / kMuteFadeFrames; } // namespace void AudioFrameOperations::Add(const AudioFrame& frame_to_add, AudioFrame* result_frame) { // Sanity check. RTC_DCHECK(result_frame); RTC_DCHECK_GT(result_frame->num_channels_, 0); RTC_DCHECK_EQ(result_frame->num_channels_, frame_to_add.num_channels_); bool no_previous_data = result_frame->muted(); if (result_frame->samples_per_channel_ != frame_to_add.samples_per_channel_) { // Special case we have no data to start with. RTC_DCHECK_EQ(result_frame->samples_per_channel_, 0); result_frame->samples_per_channel_ = frame_to_add.samples_per_channel_; no_previous_data = true; } if (result_frame->vad_activity_ == AudioFrame::kVadActive || frame_to_add.vad_activity_ == AudioFrame::kVadActive) { result_frame->vad_activity_ = AudioFrame::kVadActive; } else if (result_frame->vad_activity_ == AudioFrame::kVadUnknown || frame_to_add.vad_activity_ == AudioFrame::kVadUnknown) { result_frame->vad_activity_ = AudioFrame::kVadUnknown; } if (result_frame->speech_type_ != frame_to_add.speech_type_) result_frame->speech_type_ = AudioFrame::kUndefined; if (!frame_to_add.muted()) { const int16_t* in_data = frame_to_add.data(); int16_t* out_data = result_frame->mutable_data(); size_t length = frame_to_add.samples_per_channel_ * frame_to_add.num_channels_; if (no_previous_data) { std::copy(in_data, in_data + length, out_data); } else { for (size_t i = 0; i < length; i++) { const int32_t wrap_guard = static_cast(out_data[i]) + static_cast(in_data[i]); out_data[i] = rtc::saturated_cast(wrap_guard); } } } } int AudioFrameOperations::MonoToStereo(AudioFrame* frame) { if (frame->num_channels_ != 1) { return -1; } UpmixChannels(2, frame); return 0; } int AudioFrameOperations::StereoToMono(AudioFrame* frame) { if (frame->num_channels_ != 2) { return -1; } DownmixChannels(1, frame); return frame->num_channels_ == 1 ? 0 : -1; } void AudioFrameOperations::QuadToStereo(const int16_t* src_audio, size_t samples_per_channel, int16_t* dst_audio) { for (size_t i = 0; i < samples_per_channel; i++) { dst_audio[i * 2] = (static_cast(src_audio[4 * i]) + src_audio[4 * i + 1]) >> 1; dst_audio[i * 2 + 1] = (static_cast(src_audio[4 * i + 2]) + src_audio[4 * i + 3]) >> 1; } } int AudioFrameOperations::QuadToStereo(AudioFrame* frame) { if (frame->num_channels_ != 4) { return -1; } RTC_DCHECK_LE(frame->samples_per_channel_ * 4, AudioFrame::kMaxDataSizeSamples); if (!frame->muted()) { QuadToStereo(frame->data(), frame->samples_per_channel_, frame->mutable_data()); } frame->num_channels_ = 2; return 0; } void AudioFrameOperations::DownmixChannels(const int16_t* src_audio, size_t src_channels, size_t samples_per_channel, size_t dst_channels, int16_t* dst_audio) { if (src_channels > 1 && dst_channels == 1) { DownmixInterleavedToMono(src_audio, samples_per_channel, src_channels, dst_audio); return; } else if (src_channels == 4 && dst_channels == 2) { QuadToStereo(src_audio, samples_per_channel, dst_audio); return; } RTC_NOTREACHED() << "src_channels: " << src_channels << ", dst_channels: " << dst_channels; } void AudioFrameOperations::DownmixChannels(size_t dst_channels, AudioFrame* frame) { RTC_DCHECK_LE(frame->samples_per_channel_ * frame->num_channels_, AudioFrame::kMaxDataSizeSamples); if (frame->num_channels_ > 1 && dst_channels == 1) { if (!frame->muted()) { DownmixInterleavedToMono(frame->data(), frame->samples_per_channel_, frame->num_channels_, frame->mutable_data()); } frame->num_channels_ = 1; } else if (frame->num_channels_ == 4 && dst_channels == 2) { int err = QuadToStereo(frame); RTC_DCHECK_EQ(err, 0); } else { RTC_NOTREACHED() << "src_channels: " << frame->num_channels_ << ", dst_channels: " << dst_channels; } } void AudioFrameOperations::UpmixChannels(size_t target_number_of_channels, AudioFrame* frame) { RTC_DCHECK_EQ(frame->num_channels_, 1); RTC_DCHECK_LE(frame->samples_per_channel_ * target_number_of_channels, AudioFrame::kMaxDataSizeSamples); if (frame->num_channels_ != 1 || frame->samples_per_channel_ * target_number_of_channels > AudioFrame::kMaxDataSizeSamples) { return; } if (!frame->muted()) { // Up-mixing done in place. Going backwards through the frame ensure nothing // is irrevocably overwritten. for (int i = frame->samples_per_channel_ - 1; i >= 0; i--) { for (size_t j = 0; j < target_number_of_channels; ++j) { frame->mutable_data()[target_number_of_channels * i + j] = frame->data()[i]; } } } frame->num_channels_ = target_number_of_channels; } void AudioFrameOperations::SwapStereoChannels(AudioFrame* frame) { RTC_DCHECK(frame); if (frame->num_channels_ != 2 || frame->muted()) { return; } int16_t* frame_data = frame->mutable_data(); for (size_t i = 0; i < frame->samples_per_channel_ * 2; i += 2) { std::swap(frame_data[i], frame_data[i + 1]); } } void AudioFrameOperations::Mute(AudioFrame* frame, bool previous_frame_muted, bool current_frame_muted) { RTC_DCHECK(frame); if (!previous_frame_muted && !current_frame_muted) { // Not muted, don't touch. } else if (previous_frame_muted && current_frame_muted) { // Frame fully muted. size_t total_samples = frame->samples_per_channel_ * frame->num_channels_; RTC_DCHECK_GE(AudioFrame::kMaxDataSizeSamples, total_samples); frame->Mute(); } else { // Fade is a no-op on a muted frame. if (frame->muted()) { return; } // Limit number of samples to fade, if frame isn't long enough. size_t count = kMuteFadeFrames; float inc = kMuteFadeInc; if (frame->samples_per_channel_ < kMuteFadeFrames) { count = frame->samples_per_channel_; if (count > 0) { inc = 1.0f / count; } } size_t start = 0; size_t end = count; float start_g = 0.0f; if (current_frame_muted) { // Fade out the last |count| samples of frame. RTC_DCHECK(!previous_frame_muted); start = frame->samples_per_channel_ - count; end = frame->samples_per_channel_; start_g = 1.0f; inc = -inc; } else { // Fade in the first |count| samples of frame. RTC_DCHECK(previous_frame_muted); } // Perform fade. int16_t* frame_data = frame->mutable_data(); size_t channels = frame->num_channels_; for (size_t j = 0; j < channels; ++j) { float g = start_g; for (size_t i = start * channels; i < end * channels; i += channels) { g += inc; frame_data[i + j] *= g; } } } } void AudioFrameOperations::Mute(AudioFrame* frame) { Mute(frame, true, true); } void AudioFrameOperations::ApplyHalfGain(AudioFrame* frame) { RTC_DCHECK(frame); RTC_DCHECK_GT(frame->num_channels_, 0); if (frame->num_channels_ < 1 || frame->muted()) { return; } int16_t* frame_data = frame->mutable_data(); for (size_t i = 0; i < frame->samples_per_channel_ * frame->num_channels_; i++) { frame_data[i] = frame_data[i] >> 1; } } int AudioFrameOperations::Scale(float left, float right, AudioFrame* frame) { if (frame->num_channels_ != 2) { return -1; } else if (frame->muted()) { return 0; } int16_t* frame_data = frame->mutable_data(); for (size_t i = 0; i < frame->samples_per_channel_; i++) { frame_data[2 * i] = static_cast(left * frame_data[2 * i]); frame_data[2 * i + 1] = static_cast(right * frame_data[2 * i + 1]); } return 0; } int AudioFrameOperations::ScaleWithSat(float scale, AudioFrame* frame) { if (frame->muted()) { return 0; } int16_t* frame_data = frame->mutable_data(); for (size_t i = 0; i < frame->samples_per_channel_ * frame->num_channels_; i++) { frame_data[i] = rtc::saturated_cast(scale * frame_data[i]); } return 0; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/audio/utility/audio_frame_operations.h0000664000175000017500000001072214475643423025651 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef AUDIO_UTILITY_AUDIO_FRAME_OPERATIONS_H_ #define AUDIO_UTILITY_AUDIO_FRAME_OPERATIONS_H_ #include #include #include "api/audio/audio_frame.h" #include "rtc_base/deprecation.h" namespace webrtc { // TODO(andrew): consolidate this with utility.h and audio_frame_manipulator.h. // Change reference parameters to pointers. Consider using a namespace rather // than a class. class AudioFrameOperations { public: // Add samples in |frame_to_add| with samples in |result_frame| // putting the results in |results_frame|. The fields // |vad_activity_| and |speech_type_| of the result frame are // updated. If |result_frame| is empty (|samples_per_channel_|==0), // the samples in |frame_to_add| are added to it. The number of // channels and number of samples per channel must match except when // |result_frame| is empty. static void Add(const AudioFrame& frame_to_add, AudioFrame* result_frame); // |frame.num_channels_| will be updated. This version checks for sufficient // buffer size and that |num_channels_| is mono. Use UpmixChannels // instead. TODO(bugs.webrtc.org/8649): remove. RTC_DEPRECATED static int MonoToStereo(AudioFrame* frame); // |frame.num_channels_| will be updated. This version checks that // |num_channels_| is stereo. Use DownmixChannels // instead. TODO(bugs.webrtc.org/8649): remove. RTC_DEPRECATED static int StereoToMono(AudioFrame* frame); // Downmixes 4 channels |src_audio| to stereo |dst_audio|. This is an in-place // operation, meaning |src_audio| and |dst_audio| may point to the same // buffer. static void QuadToStereo(const int16_t* src_audio, size_t samples_per_channel, int16_t* dst_audio); // |frame.num_channels_| will be updated. This version checks that // |num_channels_| is 4 channels. static int QuadToStereo(AudioFrame* frame); // Downmixes |src_channels| |src_audio| to |dst_channels| |dst_audio|. // This is an in-place operation, meaning |src_audio| and |dst_audio| // may point to the same buffer. Supported channel combinations are // Stereo to Mono, Quad to Mono, and Quad to Stereo. static void DownmixChannels(const int16_t* src_audio, size_t src_channels, size_t samples_per_channel, size_t dst_channels, int16_t* dst_audio); // |frame.num_channels_| will be updated. This version checks that // |num_channels_| and |dst_channels| are valid and performs relevant downmix. // Supported channel combinations are N channels to Mono, and Quad to Stereo. static void DownmixChannels(size_t dst_channels, AudioFrame* frame); // |frame.num_channels_| will be updated. This version checks that // |num_channels_| and |dst_channels| are valid and performs relevant // downmix. Supported channel combinations are Mono to N // channels. The single channel is replicated. static void UpmixChannels(size_t target_number_of_channels, AudioFrame* frame); // Swap the left and right channels of |frame|. Fails silently if |frame| is // not stereo. static void SwapStereoChannels(AudioFrame* frame); // Conditionally zero out contents of |frame| for implementing audio mute: // |previous_frame_muted| && |current_frame_muted| - Zero out whole frame. // |previous_frame_muted| && !|current_frame_muted| - Fade-in at frame start. // !|previous_frame_muted| && |current_frame_muted| - Fade-out at frame end. // !|previous_frame_muted| && !|current_frame_muted| - Leave frame untouched. static void Mute(AudioFrame* frame, bool previous_frame_muted, bool current_frame_muted); // Zero out contents of frame. static void Mute(AudioFrame* frame); // Halve samples in |frame|. static void ApplyHalfGain(AudioFrame* frame); static int Scale(float left, float right, AudioFrame* frame); static int ScaleWithSat(float scale, AudioFrame* frame); }; } // namespace webrtc #endif // AUDIO_UTILITY_AUDIO_FRAME_OPERATIONS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/0000775000175000017500000000000014475643423020625 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/BUILD.gn0000664000175000017500000002477314475643423022027 0ustar00arunarun# Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../webrtc.gni") visibility = [ ":*" ] rtc_library("common_audio") { visibility += [ "*" ] sources = [ "audio_converter.cc", "audio_converter.h", "audio_util.cc", "channel_buffer.cc", "channel_buffer.h", "include/audio_util.h", "real_fourier.cc", "real_fourier.h", "real_fourier_ooura.cc", "real_fourier_ooura.h", "resampler/include/push_resampler.h", "resampler/include/resampler.h", "resampler/push_resampler.cc", "resampler/push_sinc_resampler.cc", "resampler/push_sinc_resampler.h", "resampler/resampler.cc", "resampler/sinc_resampler.cc", "smoothing_filter.cc", "smoothing_filter.h", "vad/include/vad.h", "vad/vad.cc", "wav_file.cc", "wav_file.h", "wav_header.cc", "wav_header.h", "window_generator.cc", "window_generator.h", ] deps = [ ":common_audio_c", ":sinc_resampler", "../api:array_view", "../rtc_base:checks", "../rtc_base:gtest_prod", "../rtc_base:rtc_base_approved", "../rtc_base:sanitizer", "../rtc_base/memory:aligned_malloc", "../rtc_base/system:arch", "../rtc_base/system:file_wrapper", "../system_wrappers", "third_party/ooura:fft_size_256", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] defines = [] if (rtc_build_with_neon) { deps += [ ":common_audio_neon" ] } if (current_cpu == "x86" || current_cpu == "x64") { deps += [ ":common_audio_sse2" ] deps += [ ":common_audio_avx2" ] } } rtc_source_set("mock_common_audio") { visibility += webrtc_default_visibility testonly = true sources = [ "mocks/mock_smoothing_filter.h", "vad/mock/mock_vad.h", ] deps = [ ":common_audio", "../test:test_support", ] } rtc_source_set("common_audio_c_arm_asm") { sources = [] deps = [] if (current_cpu == "arm") { sources += [ "signal_processing/complex_bit_reverse_arm.S" ] if (arm_version >= 7) { sources += [ "signal_processing/filter_ar_fast_q12_armv7.S" ] } else { sources += [ "signal_processing/filter_ar_fast_q12.c" ] } deps += [ "../rtc_base/system:asm_defines" ] } } rtc_library("common_audio_c") { visibility += webrtc_default_visibility sources = [ "ring_buffer.c", "ring_buffer.h", "signal_processing/auto_corr_to_refl_coef.c", "signal_processing/auto_correlation.c", "signal_processing/complex_fft_tables.h", "signal_processing/copy_set_operations.c", "signal_processing/cross_correlation.c", "signal_processing/division_operations.c", "signal_processing/downsample_fast.c", "signal_processing/energy.c", "signal_processing/filter_ar.c", "signal_processing/filter_ma_fast_q12.c", "signal_processing/get_hanning_window.c", "signal_processing/get_scaling_square.c", "signal_processing/ilbc_specific_functions.c", "signal_processing/include/real_fft.h", "signal_processing/include/signal_processing_library.h", "signal_processing/include/spl_inl.h", "signal_processing/include/spl_inl_armv7.h", "signal_processing/levinson_durbin.c", "signal_processing/lpc_to_refl_coef.c", "signal_processing/min_max_operations.c", "signal_processing/randomization_functions.c", "signal_processing/real_fft.c", "signal_processing/refl_coef_to_lpc.c", "signal_processing/resample.c", "signal_processing/resample_48khz.c", "signal_processing/resample_by_2.c", "signal_processing/resample_by_2_internal.c", "signal_processing/resample_by_2_internal.h", "signal_processing/resample_fractional.c", "signal_processing/spl_init.c", "signal_processing/spl_inl.c", "signal_processing/spl_sqrt.c", "signal_processing/splitting_filter.c", "signal_processing/sqrt_of_one_minus_x_squared.c", "signal_processing/vector_scaling_operations.c", "vad/include/webrtc_vad.h", "vad/vad_core.c", "vad/vad_core.h", "vad/vad_filterbank.c", "vad/vad_filterbank.h", "vad/vad_gmm.c", "vad/vad_gmm.h", "vad/vad_sp.c", "vad/vad_sp.h", "vad/webrtc_vad.c", ] if (current_cpu == "mipsel") { sources += [ "signal_processing/complex_bit_reverse_mips.c", "signal_processing/complex_fft_mips.c", "signal_processing/cross_correlation_mips.c", "signal_processing/downsample_fast_mips.c", "signal_processing/filter_ar_fast_q12_mips.c", "signal_processing/include/spl_inl_mips.h", "signal_processing/min_max_operations_mips.c", "signal_processing/resample_by_2_mips.c", ] if (mips_dsp_rev > 0) { sources += [ "signal_processing/vector_scaling_operations_mips.c" ] } } else { sources += [ "signal_processing/complex_fft.c" ] } if (current_cpu != "arm" && current_cpu != "mipsel") { sources += [ "signal_processing/complex_bit_reverse.c", "signal_processing/filter_ar_fast_q12.c", ] } deps = [ ":common_audio_c_arm_asm", ":common_audio_cc", "../rtc_base:checks", "../rtc_base:compile_assert_c", "../rtc_base:rtc_base_approved", "../rtc_base:sanitizer", "../rtc_base/system:arch", "../system_wrappers", "third_party/ooura:fft_size_256", "third_party/spl_sqrt_floor", ] } rtc_library("common_audio_cc") { sources = [ "signal_processing/dot_product_with_scale.cc", "signal_processing/dot_product_with_scale.h", ] deps = [ "../rtc_base:rtc_base_approved", "../system_wrappers", ] } rtc_source_set("sinc_resampler") { sources = [ "resampler/sinc_resampler.h" ] deps = [ "../rtc_base:gtest_prod", "../rtc_base:rtc_base_approved", "../rtc_base/memory:aligned_malloc", "../rtc_base/system:arch", "../system_wrappers", ] } rtc_source_set("fir_filter") { visibility += webrtc_default_visibility sources = [ "fir_filter.h" ] } rtc_library("fir_filter_factory") { visibility += webrtc_default_visibility sources = [ "fir_filter_c.cc", "fir_filter_c.h", "fir_filter_factory.cc", "fir_filter_factory.h", ] deps = [ ":fir_filter", "../rtc_base:checks", "../rtc_base:rtc_base_approved", "../rtc_base/system:arch", "../system_wrappers", ] if (current_cpu == "x86" || current_cpu == "x64") { deps += [ ":common_audio_sse2" ] deps += [ ":common_audio_avx2" ] } if (rtc_build_with_neon) { deps += [ ":common_audio_neon" ] } } if (current_cpu == "x86" || current_cpu == "x64") { rtc_library("common_audio_sse2") { sources = [ "fir_filter_sse.cc", "fir_filter_sse.h", "resampler/sinc_resampler_sse.cc", ] if (is_posix || is_fuchsia) { cflags = [ "-msse2" ] } deps = [ ":fir_filter", ":sinc_resampler", "../rtc_base:checks", "../rtc_base:rtc_base_approved", "../rtc_base/memory:aligned_malloc", ] } rtc_library("common_audio_avx2") { sources = [ "fir_filter_avx2.cc", "fir_filter_avx2.h", "resampler/sinc_resampler_avx2.cc", ] if (is_win) { cflags = [ "/arch:AVX2" ] } else { cflags = [ "-mavx2", "-mfma", ] } deps = [ ":fir_filter", ":sinc_resampler", "../rtc_base:checks", "../rtc_base:rtc_base_approved", "../rtc_base/memory:aligned_malloc", ] } } if (rtc_build_with_neon) { rtc_library("common_audio_neon") { sources = [ "fir_filter_neon.cc", "fir_filter_neon.h", "resampler/sinc_resampler_neon.cc", ] if (current_cpu != "arm64") { # Enable compilation for the NEON instruction set. suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ] cflags = [ "-mfpu=neon" ] } deps = [ ":common_audio_neon_c", ":fir_filter", ":sinc_resampler", "../rtc_base:checks", "../rtc_base:rtc_base_approved", "../rtc_base/memory:aligned_malloc", ] } rtc_library("common_audio_neon_c") { visibility += webrtc_default_visibility sources = [ "signal_processing/cross_correlation_neon.c", "signal_processing/downsample_fast_neon.c", "signal_processing/min_max_operations_neon.c", ] if (current_cpu != "arm64") { # Enable compilation for the NEON instruction set. suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ] cflags = [ "-mfpu=neon" ] } deps = [ ":common_audio_c", "../rtc_base:checks", "../rtc_base:rtc_base_approved", "../rtc_base/system:arch", ] } } if (rtc_include_tests) { rtc_test("common_audio_unittests") { visibility += webrtc_default_visibility testonly = true sources = [ "audio_converter_unittest.cc", "audio_util_unittest.cc", "channel_buffer_unittest.cc", "fir_filter_unittest.cc", "real_fourier_unittest.cc", "resampler/push_resampler_unittest.cc", "resampler/push_sinc_resampler_unittest.cc", "resampler/resampler_unittest.cc", "resampler/sinusoidal_linear_chirp_source.cc", "resampler/sinusoidal_linear_chirp_source.h", "ring_buffer_unittest.cc", "signal_processing/real_fft_unittest.cc", "signal_processing/signal_processing_unittest.cc", "smoothing_filter_unittest.cc", "vad/vad_core_unittest.cc", "vad/vad_filterbank_unittest.cc", "vad/vad_gmm_unittest.cc", "vad/vad_sp_unittest.cc", "vad/vad_unittest.cc", "vad/vad_unittest.h", "wav_file_unittest.cc", "wav_header_unittest.cc", "window_generator_unittest.cc", ] # Does not compile on iOS for arm: webrtc:5544. if (!is_ios || target_cpu != "arm") { sources += [ "resampler/sinc_resampler_unittest.cc" ] } deps = [ ":common_audio", ":common_audio_c", ":fir_filter", ":fir_filter_factory", ":sinc_resampler", "../rtc_base:checks", "../rtc_base:rtc_base_approved", "../rtc_base:rtc_base_tests_utils", "../rtc_base/system:arch", "../system_wrappers", "../test:fileutils", "../test:rtc_expect_death", "../test:test_main", "../test:test_support", "//testing/gtest", ] if (is_android) { deps += [ "//testing/android/native_test:native_test_support" ] shard_timeout = 900 } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/audio_converter.cc0000664000175000017500000001757414475643423024342 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/audio_converter.h" #include #include #include #include #include "common_audio/channel_buffer.h" #include "common_audio/resampler/push_sinc_resampler.h" #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_conversions.h" namespace webrtc { class CopyConverter : public AudioConverter { public: CopyConverter(size_t src_channels, size_t src_frames, size_t dst_channels, size_t dst_frames) : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {} ~CopyConverter() override {} void Convert(const float* const* src, size_t src_size, float* const* dst, size_t dst_capacity) override { CheckSizes(src_size, dst_capacity); if (src != dst) { for (size_t i = 0; i < src_channels(); ++i) std::memcpy(dst[i], src[i], dst_frames() * sizeof(*dst[i])); } } }; class UpmixConverter : public AudioConverter { public: UpmixConverter(size_t src_channels, size_t src_frames, size_t dst_channels, size_t dst_frames) : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {} ~UpmixConverter() override {} void Convert(const float* const* src, size_t src_size, float* const* dst, size_t dst_capacity) override { CheckSizes(src_size, dst_capacity); for (size_t i = 0; i < dst_frames(); ++i) { const float value = src[0][i]; for (size_t j = 0; j < dst_channels(); ++j) dst[j][i] = value; } } }; class DownmixConverter : public AudioConverter { public: DownmixConverter(size_t src_channels, size_t src_frames, size_t dst_channels, size_t dst_frames) : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {} ~DownmixConverter() override {} void Convert(const float* const* src, size_t src_size, float* const* dst, size_t dst_capacity) override { CheckSizes(src_size, dst_capacity); float* dst_mono = dst[0]; for (size_t i = 0; i < src_frames(); ++i) { float sum = 0; for (size_t j = 0; j < src_channels(); ++j) sum += src[j][i]; dst_mono[i] = sum / src_channels(); } } }; class ResampleConverter : public AudioConverter { public: ResampleConverter(size_t src_channels, size_t src_frames, size_t dst_channels, size_t dst_frames) : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) { resamplers_.reserve(src_channels); for (size_t i = 0; i < src_channels; ++i) resamplers_.push_back(std::unique_ptr( new PushSincResampler(src_frames, dst_frames))); } ~ResampleConverter() override {} void Convert(const float* const* src, size_t src_size, float* const* dst, size_t dst_capacity) override { CheckSizes(src_size, dst_capacity); for (size_t i = 0; i < resamplers_.size(); ++i) resamplers_[i]->Resample(src[i], src_frames(), dst[i], dst_frames()); } private: std::vector> resamplers_; }; // Apply a vector of converters in serial, in the order given. At least two // converters must be provided. class CompositionConverter : public AudioConverter { public: explicit CompositionConverter( std::vector> converters) : converters_(std::move(converters)) { RTC_CHECK_GE(converters_.size(), 2); // We need an intermediate buffer after every converter. for (auto it = converters_.begin(); it != converters_.end() - 1; ++it) buffers_.push_back( std::unique_ptr>(new ChannelBuffer( (*it)->dst_frames(), (*it)->dst_channels()))); } ~CompositionConverter() override {} void Convert(const float* const* src, size_t src_size, float* const* dst, size_t dst_capacity) override { converters_.front()->Convert(src, src_size, buffers_.front()->channels(), buffers_.front()->size()); for (size_t i = 2; i < converters_.size(); ++i) { auto& src_buffer = buffers_[i - 2]; auto& dst_buffer = buffers_[i - 1]; converters_[i]->Convert(src_buffer->channels(), src_buffer->size(), dst_buffer->channels(), dst_buffer->size()); } converters_.back()->Convert(buffers_.back()->channels(), buffers_.back()->size(), dst, dst_capacity); } private: std::vector> converters_; std::vector>> buffers_; }; std::unique_ptr AudioConverter::Create(size_t src_channels, size_t src_frames, size_t dst_channels, size_t dst_frames) { std::unique_ptr sp; if (src_channels > dst_channels) { if (src_frames != dst_frames) { std::vector> converters; converters.push_back(std::unique_ptr(new DownmixConverter( src_channels, src_frames, dst_channels, src_frames))); converters.push_back( std::unique_ptr(new ResampleConverter( dst_channels, src_frames, dst_channels, dst_frames))); sp.reset(new CompositionConverter(std::move(converters))); } else { sp.reset(new DownmixConverter(src_channels, src_frames, dst_channels, dst_frames)); } } else if (src_channels < dst_channels) { if (src_frames != dst_frames) { std::vector> converters; converters.push_back( std::unique_ptr(new ResampleConverter( src_channels, src_frames, src_channels, dst_frames))); converters.push_back(std::unique_ptr(new UpmixConverter( src_channels, dst_frames, dst_channels, dst_frames))); sp.reset(new CompositionConverter(std::move(converters))); } else { sp.reset(new UpmixConverter(src_channels, src_frames, dst_channels, dst_frames)); } } else if (src_frames != dst_frames) { sp.reset(new ResampleConverter(src_channels, src_frames, dst_channels, dst_frames)); } else { sp.reset( new CopyConverter(src_channels, src_frames, dst_channels, dst_frames)); } return sp; } // For CompositionConverter. AudioConverter::AudioConverter() : src_channels_(0), src_frames_(0), dst_channels_(0), dst_frames_(0) {} AudioConverter::AudioConverter(size_t src_channels, size_t src_frames, size_t dst_channels, size_t dst_frames) : src_channels_(src_channels), src_frames_(src_frames), dst_channels_(dst_channels), dst_frames_(dst_frames) { RTC_CHECK(dst_channels == src_channels || dst_channels == 1 || src_channels == 1); } void AudioConverter::CheckSizes(size_t src_size, size_t dst_capacity) const { RTC_CHECK_EQ(src_size, src_channels() * src_frames()); RTC_CHECK_GE(dst_capacity, dst_channels() * dst_frames()); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/audio_converter.h0000664000175000017500000000507514475643423024175 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_AUDIO_CONVERTER_H_ #define COMMON_AUDIO_AUDIO_CONVERTER_H_ #include #include #include "rtc_base/constructor_magic.h" namespace webrtc { // Format conversion (remixing and resampling) for audio. Only simple remixing // conversions are supported: downmix to mono (i.e. |dst_channels| == 1) or // upmix from mono (i.e. |src_channels == 1|). // // The source and destination chunks have the same duration in time; specifying // the number of frames is equivalent to specifying the sample rates. class AudioConverter { public: // Returns a new AudioConverter, which will use the supplied format for its // lifetime. Caller is responsible for the memory. static std::unique_ptr Create(size_t src_channels, size_t src_frames, size_t dst_channels, size_t dst_frames); virtual ~AudioConverter() {} // Convert |src|, containing |src_size| samples, to |dst|, having a sample // capacity of |dst_capacity|. Both point to a series of buffers containing // the samples for each channel. The sizes must correspond to the format // passed to Create(). virtual void Convert(const float* const* src, size_t src_size, float* const* dst, size_t dst_capacity) = 0; size_t src_channels() const { return src_channels_; } size_t src_frames() const { return src_frames_; } size_t dst_channels() const { return dst_channels_; } size_t dst_frames() const { return dst_frames_; } protected: AudioConverter(); AudioConverter(size_t src_channels, size_t src_frames, size_t dst_channels, size_t dst_frames); // Helper to RTC_CHECK that inputs are correctly sized. void CheckSizes(size_t src_size, size_t dst_capacity) const; private: const size_t src_channels_; const size_t src_frames_; const size_t dst_channels_; const size_t dst_frames_; RTC_DISALLOW_COPY_AND_ASSIGN(AudioConverter); }; } // namespace webrtc #endif // COMMON_AUDIO_AUDIO_CONVERTER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/audio_util.cc0000664000175000017500000000333114475643423023272 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/include/audio_util.h" namespace webrtc { void FloatToS16(const float* src, size_t size, int16_t* dest) { for (size_t i = 0; i < size; ++i) dest[i] = FloatToS16(src[i]); } void S16ToFloat(const int16_t* src, size_t size, float* dest) { for (size_t i = 0; i < size; ++i) dest[i] = S16ToFloat(src[i]); } void S16ToFloatS16(const int16_t* src, size_t size, float* dest) { for (size_t i = 0; i < size; ++i) dest[i] = src[i]; } void FloatS16ToS16(const float* src, size_t size, int16_t* dest) { for (size_t i = 0; i < size; ++i) dest[i] = FloatS16ToS16(src[i]); } void FloatToFloatS16(const float* src, size_t size, float* dest) { for (size_t i = 0; i < size; ++i) dest[i] = FloatToFloatS16(src[i]); } void FloatS16ToFloat(const float* src, size_t size, float* dest) { for (size_t i = 0; i < size; ++i) dest[i] = FloatS16ToFloat(src[i]); } template <> void DownmixInterleavedToMono(const int16_t* interleaved, size_t num_frames, int num_channels, int16_t* deinterleaved) { DownmixInterleavedToMonoImpl(interleaved, num_frames, num_channels, deinterleaved); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/channel_buffer.cc0000664000175000017500000000424414475643423024101 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/channel_buffer.h" #include #include "common_audio/include/audio_util.h" #include "rtc_base/checks.h" namespace webrtc { IFChannelBuffer::IFChannelBuffer(size_t num_frames, size_t num_channels, size_t num_bands) : ivalid_(true), ibuf_(num_frames, num_channels, num_bands), fvalid_(true), fbuf_(num_frames, num_channels, num_bands) {} IFChannelBuffer::~IFChannelBuffer() = default; ChannelBuffer* IFChannelBuffer::ibuf() { RefreshI(); fvalid_ = false; return &ibuf_; } ChannelBuffer* IFChannelBuffer::fbuf() { RefreshF(); ivalid_ = false; return &fbuf_; } const ChannelBuffer* IFChannelBuffer::ibuf_const() const { RefreshI(); return &ibuf_; } const ChannelBuffer* IFChannelBuffer::fbuf_const() const { RefreshF(); return &fbuf_; } void IFChannelBuffer::RefreshF() const { if (!fvalid_) { RTC_DCHECK(ivalid_); fbuf_.set_num_channels(ibuf_.num_channels()); const int16_t* const* int_channels = ibuf_.channels(); float* const* float_channels = fbuf_.channels(); for (size_t i = 0; i < ibuf_.num_channels(); ++i) { for (size_t j = 0; j < ibuf_.num_frames(); ++j) { float_channels[i][j] = int_channels[i][j]; } } fvalid_ = true; } } void IFChannelBuffer::RefreshI() const { if (!ivalid_) { RTC_DCHECK(fvalid_); int16_t* const* int_channels = ibuf_.channels(); ibuf_.set_num_channels(fbuf_.num_channels()); const float* const* float_channels = fbuf_.channels(); for (size_t i = 0; i < fbuf_.num_channels(); ++i) { FloatS16ToS16(float_channels[i], ibuf_.num_frames(), int_channels[i]); } ivalid_ = true; } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/channel_buffer.h0000664000175000017500000001705014475643423023742 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_CHANNEL_BUFFER_H_ #define COMMON_AUDIO_CHANNEL_BUFFER_H_ #include #include #include #include "api/array_view.h" #include "common_audio/include/audio_util.h" #include "rtc_base/checks.h" #include "rtc_base/gtest_prod_util.h" namespace webrtc { // Helper to encapsulate a contiguous data buffer, full or split into frequency // bands, with access to a pointer arrays of the deinterleaved channels and // bands. The buffer is zero initialized at creation. // // The buffer structure is showed below for a 2 channel and 2 bands case: // // |data_|: // { [ --- b1ch1 --- ] [ --- b2ch1 --- ] [ --- b1ch2 --- ] [ --- b2ch2 --- ] } // // The pointer arrays for the same example are as follows: // // |channels_|: // { [ b1ch1* ] [ b1ch2* ] [ b2ch1* ] [ b2ch2* ] } // // |bands_|: // { [ b1ch1* ] [ b2ch1* ] [ b1ch2* ] [ b2ch2* ] } template class ChannelBuffer { public: ChannelBuffer(size_t num_frames, size_t num_channels, size_t num_bands = 1) : data_(new T[num_frames * num_channels]()), channels_(new T*[num_channels * num_bands]), bands_(new T*[num_channels * num_bands]), num_frames_(num_frames), num_frames_per_band_(num_frames / num_bands), num_allocated_channels_(num_channels), num_channels_(num_channels), num_bands_(num_bands), bands_view_(num_allocated_channels_, std::vector>(num_bands_)), channels_view_( num_bands_, std::vector>(num_allocated_channels_)) { // Temporarily cast away const_ness to allow populating the array views. auto* bands_view = const_cast>>*>(&bands_view_); auto* channels_view = const_cast>>*>( &channels_view_); for (size_t ch = 0; ch < num_allocated_channels_; ++ch) { for (size_t band = 0; band < num_bands_; ++band) { (*channels_view)[band][ch] = rtc::ArrayView( &data_[ch * num_frames_ + band * num_frames_per_band_], num_frames_per_band_); (*bands_view)[ch][band] = channels_view_[band][ch]; channels_[band * num_allocated_channels_ + ch] = channels_view_[band][ch].data(); bands_[ch * num_bands_ + band] = channels_[band * num_allocated_channels_ + ch]; } } } // Returns a pointer array to the channels. // If band is explicitly specificed, the channels for a specific band are // returned and the usage becomes: channels(band)[channel][sample]. // Where: // 0 <= band < |num_bands_| // 0 <= channel < |num_allocated_channels_| // 0 <= sample < |num_frames_per_band_| // If band is not explicitly specified, the full-band channels (or lower band // channels) are returned and the usage becomes: channels()[channel][sample]. // Where: // 0 <= channel < |num_allocated_channels_| // 0 <= sample < |num_frames_| const T* const* channels(size_t band = 0) const { RTC_DCHECK_LT(band, num_bands_); return &channels_[band * num_allocated_channels_]; } T* const* channels(size_t band = 0) { const ChannelBuffer* t = this; return const_cast(t->channels(band)); } rtc::ArrayView> channels_view(size_t band = 0) { return channels_view_[band]; } rtc::ArrayView> channels_view(size_t band = 0) const { return channels_view_[band]; } // Returns a pointer array to the bands for a specific channel. // Usage: // bands(channel)[band][sample]. // Where: // 0 <= channel < |num_channels_| // 0 <= band < |num_bands_| // 0 <= sample < |num_frames_per_band_| const T* const* bands(size_t channel) const { RTC_DCHECK_LT(channel, num_channels_); RTC_DCHECK_GE(channel, 0); return &bands_[channel * num_bands_]; } T* const* bands(size_t channel) { const ChannelBuffer* t = this; return const_cast(t->bands(channel)); } rtc::ArrayView> bands_view(size_t channel) { return bands_view_[channel]; } rtc::ArrayView> bands_view(size_t channel) const { return bands_view_[channel]; } // Sets the |slice| pointers to the |start_frame| position for each channel. // Returns |slice| for convenience. const T* const* Slice(T** slice, size_t start_frame) const { RTC_DCHECK_LT(start_frame, num_frames_); for (size_t i = 0; i < num_channels_; ++i) slice[i] = &channels_[i][start_frame]; return slice; } T** Slice(T** slice, size_t start_frame) { const ChannelBuffer* t = this; return const_cast(t->Slice(slice, start_frame)); } size_t num_frames() const { return num_frames_; } size_t num_frames_per_band() const { return num_frames_per_band_; } size_t num_channels() const { return num_channels_; } size_t num_bands() const { return num_bands_; } size_t size() const { return num_frames_ * num_allocated_channels_; } void set_num_channels(size_t num_channels) { RTC_DCHECK_LE(num_channels, num_allocated_channels_); num_channels_ = num_channels; } void SetDataForTesting(const T* data, size_t size) { RTC_CHECK_EQ(size, this->size()); memcpy(data_.get(), data, size * sizeof(*data)); } private: std::unique_ptr data_; std::unique_ptr channels_; std::unique_ptr bands_; const size_t num_frames_; const size_t num_frames_per_band_; // Number of channels the internal buffer holds. const size_t num_allocated_channels_; // Number of channels the user sees. size_t num_channels_; const size_t num_bands_; const std::vector>> bands_view_; const std::vector>> channels_view_; }; // One int16_t and one float ChannelBuffer that are kept in sync. The sync is // broken when someone requests write access to either ChannelBuffer, and // reestablished when someone requests the outdated ChannelBuffer. It is // therefore safe to use the return value of ibuf_const() and fbuf_const() // until the next call to ibuf() or fbuf(), and the return value of ibuf() and // fbuf() until the next call to any of the other functions. class IFChannelBuffer { public: IFChannelBuffer(size_t num_frames, size_t num_channels, size_t num_bands = 1); ~IFChannelBuffer(); ChannelBuffer* ibuf(); ChannelBuffer* fbuf(); const ChannelBuffer* ibuf_const() const; const ChannelBuffer* fbuf_const() const; size_t num_frames() const { return ibuf_.num_frames(); } size_t num_frames_per_band() const { return ibuf_.num_frames_per_band(); } size_t num_channels() const { return ivalid_ ? ibuf_.num_channels() : fbuf_.num_channels(); } void set_num_channels(size_t num_channels) { ibuf_.set_num_channels(num_channels); fbuf_.set_num_channels(num_channels); } size_t num_bands() const { return ibuf_.num_bands(); } private: void RefreshF() const; void RefreshI() const; mutable bool ivalid_; mutable ChannelBuffer ibuf_; mutable bool fvalid_; mutable ChannelBuffer fbuf_; }; } // namespace webrtc #endif // COMMON_AUDIO_CHANNEL_BUFFER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/fir_filter.h0000664000175000017500000000160214475643423023122 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_FIR_FILTER_H_ #define COMMON_AUDIO_FIR_FILTER_H_ #include namespace webrtc { // Finite Impulse Response filter using floating-point arithmetic. class FIRFilter { public: virtual ~FIRFilter() {} // Filters the |in| data supplied. // |out| must be previously allocated and it must be at least of |length|. virtual void Filter(const float* in, size_t length, float* out) = 0; }; } // namespace webrtc #endif // COMMON_AUDIO_FIR_FILTER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/fir_filter_avx2.cc0000664000175000017500000000650014475643423024222 0ustar00arunarun/* * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/fir_filter_avx2.h" #include #include #include #include #include "rtc_base/checks.h" #include "rtc_base/memory/aligned_malloc.h" namespace webrtc { FIRFilterAVX2::FIRFilterAVX2(const float* unaligned_coefficients, size_t unaligned_coefficients_length, size_t max_input_length) : // Closest higher multiple of eight. coefficients_length_((unaligned_coefficients_length + 7) & ~0x07), state_length_(coefficients_length_ - 1), coefficients_(static_cast( AlignedMalloc(sizeof(float) * coefficients_length_, 32))), state_(static_cast( AlignedMalloc(sizeof(float) * (max_input_length + state_length_), 32))) { // Add zeros at the end of the coefficients. RTC_DCHECK_GE(coefficients_length_, unaligned_coefficients_length); size_t padding = coefficients_length_ - unaligned_coefficients_length; memset(coefficients_.get(), 0, padding * sizeof(coefficients_[0])); // The coefficients are reversed to compensate for the order in which the // input samples are acquired (most recent last). for (size_t i = 0; i < unaligned_coefficients_length; ++i) { coefficients_[i + padding] = unaligned_coefficients[unaligned_coefficients_length - i - 1]; } memset(state_.get(), 0, (max_input_length + state_length_) * sizeof(state_[0])); } FIRFilterAVX2::~FIRFilterAVX2() = default; void FIRFilterAVX2::Filter(const float* in, size_t length, float* out) { RTC_DCHECK_GT(length, 0); memcpy(&state_[state_length_], in, length * sizeof(*in)); // Convolves the input signal |in| with the filter kernel |coefficients_| // taking into account the previous state. for (size_t i = 0; i < length; ++i) { float* in_ptr = &state_[i]; float* coef_ptr = coefficients_.get(); __m256 m_sum = _mm256_setzero_ps(); __m256 m_in; // Depending on if the pointer is aligned with 32 bytes or not it is loaded // differently. if (reinterpret_cast(in_ptr) & 0x1F) { for (size_t j = 0; j < coefficients_length_; j += 8) { m_in = _mm256_loadu_ps(in_ptr + j); m_sum = _mm256_fmadd_ps(m_in, _mm256_load_ps(coef_ptr + j), m_sum); } } else { for (size_t j = 0; j < coefficients_length_; j += 8) { m_in = _mm256_load_ps(in_ptr + j); m_sum = _mm256_fmadd_ps(m_in, _mm256_load_ps(coef_ptr + j), m_sum); } } __m128 m128_sum = _mm_add_ps(_mm256_extractf128_ps(m_sum, 0), _mm256_extractf128_ps(m_sum, 1)); m128_sum = _mm_add_ps(_mm_movehl_ps(m128_sum, m128_sum), m128_sum); _mm_store_ss(out + i, _mm_add_ss(m128_sum, _mm_shuffle_ps(m128_sum, m128_sum, 1))); } // Update current state. memmove(state_.get(), &state_[length], state_length_ * sizeof(state_[0])); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/fir_filter_avx2.h0000664000175000017500000000223414475643423024064 0ustar00arunarun/* * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_FIR_FILTER_AVX2_H_ #define COMMON_AUDIO_FIR_FILTER_AVX2_H_ #include #include #include "common_audio/fir_filter.h" #include "rtc_base/memory/aligned_malloc.h" namespace webrtc { class FIRFilterAVX2 : public FIRFilter { public: FIRFilterAVX2(const float* coefficients, size_t coefficients_length, size_t max_input_length); ~FIRFilterAVX2() override; void Filter(const float* in, size_t length, float* out) override; private: const size_t coefficients_length_; const size_t state_length_; std::unique_ptr coefficients_; std::unique_ptr state_; }; } // namespace webrtc #endif // COMMON_AUDIO_FIR_FILTER_AVX2_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/fir_filter_c.cc0000664000175000017500000000361514475643423023570 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/fir_filter_c.h" #include #include #include "rtc_base/checks.h" namespace webrtc { FIRFilterC::~FIRFilterC() {} FIRFilterC::FIRFilterC(const float* coefficients, size_t coefficients_length) : coefficients_length_(coefficients_length), state_length_(coefficients_length - 1), coefficients_(new float[coefficients_length_]), state_(new float[state_length_]) { for (size_t i = 0; i < coefficients_length_; ++i) { coefficients_[i] = coefficients[coefficients_length_ - i - 1]; } memset(state_.get(), 0, state_length_ * sizeof(state_[0])); } void FIRFilterC::Filter(const float* in, size_t length, float* out) { RTC_DCHECK_GT(length, 0); // Convolves the input signal |in| with the filter kernel |coefficients_| // taking into account the previous state. for (size_t i = 0; i < length; ++i) { out[i] = 0.f; size_t j; for (j = 0; state_length_ > i && j < state_length_ - i; ++j) { out[i] += state_[i + j] * coefficients_[j]; } for (; j < coefficients_length_; ++j) { out[i] += in[j + i - state_length_] * coefficients_[j]; } } // Update current state. if (length >= state_length_) { memcpy(state_.get(), &in[length - state_length_], state_length_ * sizeof(*in)); } else { memmove(state_.get(), &state_[length], (state_length_ - length) * sizeof(state_[0])); memcpy(&state_[state_length_ - length], in, length * sizeof(*in)); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/fir_filter_c.h0000664000175000017500000000176114475643423023432 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_FIR_FILTER_C_H_ #define COMMON_AUDIO_FIR_FILTER_C_H_ #include #include #include "common_audio/fir_filter.h" namespace webrtc { class FIRFilterC : public FIRFilter { public: FIRFilterC(const float* coefficients, size_t coefficients_length); ~FIRFilterC() override; void Filter(const float* in, size_t length, float* out) override; private: size_t coefficients_length_; size_t state_length_; std::unique_ptr coefficients_; std::unique_ptr state_; }; } // namespace webrtc #endif // COMMON_AUDIO_FIR_FILTER_C_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/fir_filter_factory.cc0000664000175000017500000000354414475643423025016 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/fir_filter_factory.h" #include "common_audio/fir_filter_c.h" #include "rtc_base/checks.h" #include "rtc_base/system/arch.h" #if defined(WEBRTC_HAS_NEON) #include "common_audio/fir_filter_neon.h" #elif defined(WEBRTC_ARCH_X86_FAMILY) #include "common_audio/fir_filter_avx2.h" #include "common_audio/fir_filter_sse.h" #include "system_wrappers/include/cpu_features_wrapper.h" // kSSE2, WebRtc_G... #endif namespace webrtc { FIRFilter* CreateFirFilter(const float* coefficients, size_t coefficients_length, size_t max_input_length) { if (!coefficients || coefficients_length <= 0 || max_input_length <= 0) { RTC_NOTREACHED(); return nullptr; } FIRFilter* filter = nullptr; // If we know the minimum architecture at compile time, avoid CPU detection. #if defined(WEBRTC_ARCH_X86_FAMILY) // x86 CPU detection required. if (GetCPUInfo(kAVX2)) { filter = new FIRFilterAVX2(coefficients, coefficients_length, max_input_length); } else if (GetCPUInfo(kSSE2)) { filter = new FIRFilterSSE2(coefficients, coefficients_length, max_input_length); } else { filter = new FIRFilterC(coefficients, coefficients_length); } #elif defined(WEBRTC_HAS_NEON) filter = new FIRFilterNEON(coefficients, coefficients_length, max_input_length); #else filter = new FIRFilterC(coefficients, coefficients_length); #endif return filter; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/fir_filter_factory.h0000664000175000017500000000216214475643423024653 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_FIR_FILTER_FACTORY_H_ #define COMMON_AUDIO_FIR_FILTER_FACTORY_H_ #include namespace webrtc { class FIRFilter; // Creates a filter with the given coefficients. All initial state values will // be zeros. // The length of the chunks fed to the filter should never be greater than // |max_input_length|. This is needed because, when vectorizing it is // necessary to concatenate the input after the state, and resizing this array // dynamically is expensive. FIRFilter* CreateFirFilter(const float* coefficients, size_t coefficients_length, size_t max_input_length); } // namespace webrtc #endif // COMMON_AUDIO_FIR_FILTER_FACTORY_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/fir_filter_neon.cc0000664000175000017500000000512114475643423024277 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/fir_filter_neon.h" #include #include #include "rtc_base/checks.h" #include "rtc_base/memory/aligned_malloc.h" namespace webrtc { FIRFilterNEON::~FIRFilterNEON() {} FIRFilterNEON::FIRFilterNEON(const float* coefficients, size_t coefficients_length, size_t max_input_length) : // Closest higher multiple of four. coefficients_length_((coefficients_length + 3) & ~0x03), state_length_(coefficients_length_ - 1), coefficients_(static_cast( AlignedMalloc(sizeof(float) * coefficients_length_, 16))), state_(static_cast( AlignedMalloc(sizeof(float) * (max_input_length + state_length_), 16))) { // Add zeros at the end of the coefficients. size_t padding = coefficients_length_ - coefficients_length; memset(coefficients_.get(), 0.f, padding * sizeof(coefficients_[0])); // The coefficients are reversed to compensate for the order in which the // input samples are acquired (most recent last). for (size_t i = 0; i < coefficients_length; ++i) { coefficients_[i + padding] = coefficients[coefficients_length - i - 1]; } memset(state_.get(), 0.f, (max_input_length + state_length_) * sizeof(state_[0])); } void FIRFilterNEON::Filter(const float* in, size_t length, float* out) { RTC_DCHECK_GT(length, 0); memcpy(&state_[state_length_], in, length * sizeof(*in)); // Convolves the input signal |in| with the filter kernel |coefficients_| // taking into account the previous state. for (size_t i = 0; i < length; ++i) { float* in_ptr = &state_[i]; float* coef_ptr = coefficients_.get(); float32x4_t m_sum = vmovq_n_f32(0); float32x4_t m_in; for (size_t j = 0; j < coefficients_length_; j += 4) { m_in = vld1q_f32(in_ptr + j); m_sum = vmlaq_f32(m_sum, m_in, vld1q_f32(coef_ptr + j)); } float32x2_t m_half = vadd_f32(vget_high_f32(m_sum), vget_low_f32(m_sum)); out[i] = vget_lane_f32(vpadd_f32(m_half, m_half), 0); } // Update current state. memmove(state_.get(), &state_[length], state_length_ * sizeof(state_[0])); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/fir_filter_neon.h0000664000175000017500000000217314475643423024145 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_FIR_FILTER_NEON_H_ #define COMMON_AUDIO_FIR_FILTER_NEON_H_ #include #include "common_audio/fir_filter.h" #include "rtc_base/memory/aligned_malloc.h" namespace webrtc { class FIRFilterNEON : public FIRFilter { public: FIRFilterNEON(const float* coefficients, size_t coefficients_length, size_t max_input_length); ~FIRFilterNEON() override; void Filter(const float* in, size_t length, float* out) override; private: size_t coefficients_length_; size_t state_length_; std::unique_ptr coefficients_; std::unique_ptr state_; }; } // namespace webrtc #endif // COMMON_AUDIO_FIR_FILTER_NEON_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/fir_filter_sse.cc0000664000175000017500000000573714475643423024147 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/fir_filter_sse.h" #include #include #include #include "rtc_base/checks.h" #include "rtc_base/memory/aligned_malloc.h" namespace webrtc { FIRFilterSSE2::~FIRFilterSSE2() {} FIRFilterSSE2::FIRFilterSSE2(const float* coefficients, size_t coefficients_length, size_t max_input_length) : // Closest higher multiple of four. coefficients_length_((coefficients_length + 3) & ~0x03), state_length_(coefficients_length_ - 1), coefficients_(static_cast( AlignedMalloc(sizeof(float) * coefficients_length_, 16))), state_(static_cast( AlignedMalloc(sizeof(float) * (max_input_length + state_length_), 16))) { // Add zeros at the end of the coefficients. size_t padding = coefficients_length_ - coefficients_length; memset(coefficients_.get(), 0, padding * sizeof(coefficients_[0])); // The coefficients are reversed to compensate for the order in which the // input samples are acquired (most recent last). for (size_t i = 0; i < coefficients_length; ++i) { coefficients_[i + padding] = coefficients[coefficients_length - i - 1]; } memset(state_.get(), 0, (max_input_length + state_length_) * sizeof(state_[0])); } void FIRFilterSSE2::Filter(const float* in, size_t length, float* out) { RTC_DCHECK_GT(length, 0); memcpy(&state_[state_length_], in, length * sizeof(*in)); // Convolves the input signal |in| with the filter kernel |coefficients_| // taking into account the previous state. for (size_t i = 0; i < length; ++i) { float* in_ptr = &state_[i]; float* coef_ptr = coefficients_.get(); __m128 m_sum = _mm_setzero_ps(); __m128 m_in; // Depending on if the pointer is aligned with 16 bytes or not it is loaded // differently. if (reinterpret_cast(in_ptr) & 0x0F) { for (size_t j = 0; j < coefficients_length_; j += 4) { m_in = _mm_loadu_ps(in_ptr + j); m_sum = _mm_add_ps(m_sum, _mm_mul_ps(m_in, _mm_load_ps(coef_ptr + j))); } } else { for (size_t j = 0; j < coefficients_length_; j += 4) { m_in = _mm_load_ps(in_ptr + j); m_sum = _mm_add_ps(m_sum, _mm_mul_ps(m_in, _mm_load_ps(coef_ptr + j))); } } m_sum = _mm_add_ps(_mm_movehl_ps(m_sum, m_sum), m_sum); _mm_store_ss(out + i, _mm_add_ss(m_sum, _mm_shuffle_ps(m_sum, m_sum, 1))); } // Update current state. memmove(state_.get(), &state_[length], state_length_ * sizeof(state_[0])); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/fir_filter_sse.h0000664000175000017500000000221514475643423023775 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_FIR_FILTER_SSE_H_ #define COMMON_AUDIO_FIR_FILTER_SSE_H_ #include #include #include "common_audio/fir_filter.h" #include "rtc_base/memory/aligned_malloc.h" namespace webrtc { class FIRFilterSSE2 : public FIRFilter { public: FIRFilterSSE2(const float* coefficients, size_t coefficients_length, size_t max_input_length); ~FIRFilterSSE2() override; void Filter(const float* in, size_t length, float* out) override; private: size_t coefficients_length_; size_t state_length_; std::unique_ptr coefficients_; std::unique_ptr state_; }; } // namespace webrtc #endif // COMMON_AUDIO_FIR_FILTER_SSE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/include/0000775000175000017500000000000014475643423022250 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/include/audio_util.h0000664000175000017500000001545014475643423024564 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_ #define COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_ #include #include #include #include #include #include "rtc_base/checks.h" namespace webrtc { typedef std::numeric_limits limits_int16; // The conversion functions use the following naming convention: // S16: int16_t [-32768, 32767] // Float: float [-1.0, 1.0] // FloatS16: float [-32768.0, 32768.0] // Dbfs: float [-20.0*log(10, 32768), 0] = [-90.3, 0] // The ratio conversion functions use this naming convention: // Ratio: float (0, +inf) // Db: float (-inf, +inf) static inline float S16ToFloat(int16_t v) { constexpr float kScaling = 1.f / 32768.f; return v * kScaling; } static inline int16_t FloatS16ToS16(float v) { v = std::min(v, 32767.f); v = std::max(v, -32768.f); return static_cast(v + std::copysign(0.5f, v)); } static inline int16_t FloatToS16(float v) { v *= 32768.f; v = std::min(v, 32767.f); v = std::max(v, -32768.f); return static_cast(v + std::copysign(0.5f, v)); } static inline float FloatToFloatS16(float v) { v = std::min(v, 1.f); v = std::max(v, -1.f); return v * 32768.f; } static inline float FloatS16ToFloat(float v) { v = std::min(v, 32768.f); v = std::max(v, -32768.f); constexpr float kScaling = 1.f / 32768.f; return v * kScaling; } void FloatToS16(const float* src, size_t size, int16_t* dest); void S16ToFloat(const int16_t* src, size_t size, float* dest); void S16ToFloatS16(const int16_t* src, size_t size, float* dest); void FloatS16ToS16(const float* src, size_t size, int16_t* dest); void FloatToFloatS16(const float* src, size_t size, float* dest); void FloatS16ToFloat(const float* src, size_t size, float* dest); inline float DbToRatio(float v) { return std::pow(10.0f, v / 20.0f); } inline float DbfsToFloatS16(float v) { static constexpr float kMaximumAbsFloatS16 = -limits_int16::min(); return DbToRatio(v) * kMaximumAbsFloatS16; } inline float FloatS16ToDbfs(float v) { RTC_DCHECK_GE(v, 0); // kMinDbfs is equal to -20.0 * log10(-limits_int16::min()) static constexpr float kMinDbfs = -90.30899869919436f; if (v <= 1.0f) { return kMinDbfs; } // Equal to 20 * log10(v / (-limits_int16::min())) return 20.0f * std::log10(v) + kMinDbfs; } // Copy audio from |src| channels to |dest| channels unless |src| and |dest| // point to the same address. |src| and |dest| must have the same number of // channels, and there must be sufficient space allocated in |dest|. template void CopyAudioIfNeeded(const T* const* src, int num_frames, int num_channels, T* const* dest) { for (int i = 0; i < num_channels; ++i) { if (src[i] != dest[i]) { std::copy(src[i], src[i] + num_frames, dest[i]); } } } // Deinterleave audio from |interleaved| to the channel buffers pointed to // by |deinterleaved|. There must be sufficient space allocated in the // |deinterleaved| buffers (|num_channel| buffers with |samples_per_channel| // per buffer). template void Deinterleave(const T* interleaved, size_t samples_per_channel, size_t num_channels, T* const* deinterleaved) { for (size_t i = 0; i < num_channels; ++i) { T* channel = deinterleaved[i]; size_t interleaved_idx = i; for (size_t j = 0; j < samples_per_channel; ++j) { channel[j] = interleaved[interleaved_idx]; interleaved_idx += num_channels; } } } // Interleave audio from the channel buffers pointed to by |deinterleaved| to // |interleaved|. There must be sufficient space allocated in |interleaved| // (|samples_per_channel| * |num_channels|). template void Interleave(const T* const* deinterleaved, size_t samples_per_channel, size_t num_channels, T* interleaved) { for (size_t i = 0; i < num_channels; ++i) { const T* channel = deinterleaved[i]; size_t interleaved_idx = i; for (size_t j = 0; j < samples_per_channel; ++j) { interleaved[interleaved_idx] = channel[j]; interleaved_idx += num_channels; } } } // Copies audio from a single channel buffer pointed to by |mono| to each // channel of |interleaved|. There must be sufficient space allocated in // |interleaved| (|samples_per_channel| * |num_channels|). template void UpmixMonoToInterleaved(const T* mono, int num_frames, int num_channels, T* interleaved) { int interleaved_idx = 0; for (int i = 0; i < num_frames; ++i) { for (int j = 0; j < num_channels; ++j) { interleaved[interleaved_idx++] = mono[i]; } } } template void DownmixToMono(const T* const* input_channels, size_t num_frames, int num_channels, T* out) { for (size_t i = 0; i < num_frames; ++i) { Intermediate value = input_channels[0][i]; for (int j = 1; j < num_channels; ++j) { value += input_channels[j][i]; } out[i] = value / num_channels; } } // Downmixes an interleaved multichannel signal to a single channel by averaging // all channels. template void DownmixInterleavedToMonoImpl(const T* interleaved, size_t num_frames, int num_channels, T* deinterleaved) { RTC_DCHECK_GT(num_channels, 0); RTC_DCHECK_GT(num_frames, 0); const T* const end = interleaved + num_frames * num_channels; while (interleaved < end) { const T* const frame_end = interleaved + num_channels; Intermediate value = *interleaved++; while (interleaved < frame_end) { value += *interleaved++; } *deinterleaved++ = value / num_channels; } } template void DownmixInterleavedToMono(const T* interleaved, size_t num_frames, int num_channels, T* deinterleaved); template <> void DownmixInterleavedToMono(const int16_t* interleaved, size_t num_frames, int num_channels, int16_t* deinterleaved); } // namespace webrtc #endif // COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/meson.build0000664000175000017500000001055314475643423022773 0ustar00arunaruncommon_audio_sources = [ 'audio_converter.cc', 'audio_util.cc', 'channel_buffer.cc', 'fir_filter_c.cc', 'fir_filter_factory.cc', 'real_fourier.cc', 'real_fourier_ooura.cc', 'resampler/push_resampler.cc', 'resampler/push_sinc_resampler.cc', 'resampler/resampler.cc', 'resampler/sinc_resampler.cc', 'resampler/sinusoidal_linear_chirp_source.cc', 'ring_buffer.c', 'signal_processing/auto_correlation.c', 'signal_processing/auto_corr_to_refl_coef.c', 'signal_processing/complex_bit_reverse.c', 'signal_processing/complex_fft.c', 'signal_processing/copy_set_operations.c', 'signal_processing/cross_correlation.c', 'signal_processing/division_operations.c', 'signal_processing/dot_product_with_scale.cc', 'signal_processing/downsample_fast.c', 'signal_processing/filter_ar.c', 'signal_processing/filter_ar_fast_q12.c', 'signal_processing/energy.c', 'signal_processing/filter_ma_fast_q12.c', 'signal_processing/get_hanning_window.c', 'signal_processing/get_scaling_square.c', 'signal_processing/ilbc_specific_functions.c', 'signal_processing/levinson_durbin.c', 'signal_processing/lpc_to_refl_coef.c', 'signal_processing/min_max_operations.c', 'signal_processing/randomization_functions.c', 'signal_processing/real_fft.c', 'signal_processing/refl_coef_to_lpc.c', 'signal_processing/resample_48khz.c', 'signal_processing/resample_by_2.c', 'signal_processing/resample_by_2_internal.c', 'signal_processing/resample.c', 'signal_processing/resample_fractional.c', 'signal_processing/spl_init.c', 'signal_processing/spl_inl.c', 'signal_processing/splitting_filter.c', 'signal_processing/spl_sqrt.c', 'signal_processing/sqrt_of_one_minus_x_squared.c', 'signal_processing/vector_scaling_operations.c', 'smoothing_filter.cc', 'third_party/ooura/fft_size_128/ooura_fft.cc', 'third_party/ooura/fft_size_256/fft4g.cc', 'third_party/spl_sqrt_floor/spl_sqrt_floor.c', 'vad/vad.cc', 'vad/vad_core.c', 'vad/vad_filterbank.c', 'vad/vad_gmm.c', 'vad/vad_sp.c', 'vad/webrtc_vad.c', 'wav_file.cc', 'wav_header.cc', 'window_generator.cc', ] arch_libs = [] if have_x86 arch_libs += [ static_library('common_audio_sse2', [ 'fir_filter_sse.cc', 'resampler/sinc_resampler_sse.cc', 'third_party/ooura/fft_size_128/ooura_fft_sse2.cc', ], dependencies: common_deps, include_directories: webrtc_inc, c_args: common_cflags + ['-msse2'], cpp_args: common_cxxflags + ['-msse2'] ) ] arch_libs += [ static_library('common_audio_avx', [ 'fir_filter_avx2.cc', 'resampler/sinc_resampler_avx2.cc', ], dependencies: common_deps, include_directories: webrtc_inc, c_args: common_cflags + ['-mavx2', '-mfma'], cpp_args: common_cxxflags + ['-mavx2', '-mfma'] ) ] endif if have_mips common_audio_sources += [ 'signal_processing/complex_bit_reverse_mips.c', 'signal_processing/complex_fft_mips.c', 'signal_processing/cross_correlation_mips.c', 'signal_processing/downsample_fast_mips.c', 'signal_processing/filter_ar_fast_q12_mips.c', 'signal_processing/min_max_operations_mips.c', 'signal_processing/resample_by_2_mips.c', 'signal_processing/vector_scaling_operations_mips.c', 'third_party/ooura/fft_size_128/ooura_fft_mips.c', 'third_party/spl_sqrt_floor/spl_sqrt_floor_mips.c', ] endif if have_arm common_audio_sources += [ 'signal_processing/complex_bit_reverse_arm.S', 'third_party/spl_sqrt_floor/spl_sqrt_floor_arm.S', ] endif if have_armv7 common_audio_sources += [ 'signal_processing/filter_ar_fast_q12_armv7.S', ] endif if have_neon common_audio_sources += [ 'fir_filter_neon.cc', 'resampler/sinc_resampler_neon.cc', 'signal_processing/cross_correlation_neon.c', 'signal_processing/downsample_fast_neon.c', 'signal_processing/min_max_operations_neon.c', 'third_party/ooura/fft_size_128/ooura_fft_neon.cc', ] endif if not have_arm common_audio_sources += [ 'signal_processing/complex_bit_reverse.c', 'signal_processing/filter_ar_fast_q12.c', ] endif libcommon_audio = static_library('common_audio', common_audio_sources, dependencies: common_deps, include_directories: webrtc_inc, c_args: common_cflags, cpp_args: common_cxxflags ) common_audio_dep = declare_dependency( link_with: [libcommon_audio] + arch_libs, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/real_fourier.cc0000664000175000017500000000306214475643423023613 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/real_fourier.h" #include "common_audio/real_fourier_ooura.h" #include "common_audio/signal_processing/include/signal_processing_library.h" #include "rtc_base/checks.h" namespace webrtc { using std::complex; const size_t RealFourier::kFftBufferAlignment = 32; std::unique_ptr RealFourier::Create(int fft_order) { return std::unique_ptr(new RealFourierOoura(fft_order)); } int RealFourier::FftOrder(size_t length) { RTC_CHECK_GT(length, 0U); return WebRtcSpl_GetSizeInBits(static_cast(length - 1)); } size_t RealFourier::FftLength(int order) { RTC_CHECK_GE(order, 0); return size_t{1} << order; } size_t RealFourier::ComplexLength(int order) { return FftLength(order) / 2 + 1; } RealFourier::fft_real_scoper RealFourier::AllocRealBuffer(int count) { return fft_real_scoper(static_cast( AlignedMalloc(sizeof(float) * count, kFftBufferAlignment))); } RealFourier::fft_cplx_scoper RealFourier::AllocCplxBuffer(int count) { return fft_cplx_scoper(static_cast*>( AlignedMalloc(sizeof(complex) * count, kFftBufferAlignment))); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/real_fourier.h0000664000175000017500000000553114475643423023460 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_REAL_FOURIER_H_ #define COMMON_AUDIO_REAL_FOURIER_H_ #include #include #include #include "rtc_base/memory/aligned_malloc.h" // Uniform interface class for the real DFT and its inverse, for power-of-2 // input lengths. Also contains helper functions for buffer allocation, taking // care of any memory alignment requirements the underlying library might have. namespace webrtc { class RealFourier { public: // Shorthand typenames for the scopers used by the buffer allocation helpers. typedef std::unique_ptr fft_real_scoper; typedef std::unique_ptr[], AlignedFreeDeleter> fft_cplx_scoper; // The alignment required for all input and output buffers, in bytes. static const size_t kFftBufferAlignment; // Construct a wrapper instance for the given input order, which must be // between 1 and kMaxFftOrder, inclusively. static std::unique_ptr Create(int fft_order); virtual ~RealFourier() {} // Helper to compute the smallest FFT order (a power of 2) which will contain // the given input length. static int FftOrder(size_t length); // Helper to compute the input length from the FFT order. static size_t FftLength(int order); // Helper to compute the exact length, in complex floats, of the transform // output (i.e. |2^order / 2 + 1|). static size_t ComplexLength(int order); // Buffer allocation helpers. The buffers are large enough to hold |count| // floats/complexes and suitably aligned for use by the implementation. // The returned scopers are set up with proper deleters; the caller owns // the allocated memory. static fft_real_scoper AllocRealBuffer(int count); static fft_cplx_scoper AllocCplxBuffer(int count); // Main forward transform interface. The output array need only be big // enough for |2^order / 2 + 1| elements - the conjugate pairs are not // returned. Input and output must be properly aligned (e.g. through // AllocRealBuffer and AllocCplxBuffer) and input length must be // |2^order| (same as given at construction time). virtual void Forward(const float* src, std::complex* dest) const = 0; // Inverse transform. Same input format as output above, conjugate pairs // not needed. virtual void Inverse(const std::complex* src, float* dest) const = 0; virtual int order() const = 0; }; } // namespace webrtc #endif // COMMON_AUDIO_REAL_FOURIER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/real_fourier_ooura.cc0000664000175000017500000000567714475643423025036 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/real_fourier_ooura.h" #include #include #include "common_audio/third_party/ooura/fft_size_256/fft4g.h" #include "rtc_base/checks.h" namespace webrtc { using std::complex; namespace { void Conjugate(complex* array, size_t complex_length) { std::for_each(array, array + complex_length, [=](complex& v) { v = std::conj(v); }); } size_t ComputeWorkIpSize(size_t fft_length) { return static_cast( 2 + std::ceil(std::sqrt(static_cast(fft_length)))); } } // namespace RealFourierOoura::RealFourierOoura(int fft_order) : order_(fft_order), length_(FftLength(order_)), complex_length_(ComplexLength(order_)), // Zero-initializing work_ip_ will cause rdft to initialize these work // arrays on the first call. work_ip_(new size_t[ComputeWorkIpSize(length_)]()), work_w_(new float[complex_length_]()) { RTC_CHECK_GE(fft_order, 1); } RealFourierOoura::~RealFourierOoura() = default; void RealFourierOoura::Forward(const float* src, complex* dest) const { { // This cast is well-defined since C++11. See "Non-static data members" at: // http://en.cppreference.com/w/cpp/numeric/complex auto* dest_float = reinterpret_cast(dest); std::copy(src, src + length_, dest_float); WebRtc_rdft(length_, 1, dest_float, work_ip_.get(), work_w_.get()); } // Ooura places real[n/2] in imag[0]. dest[complex_length_ - 1] = complex(dest[0].imag(), 0.0f); dest[0] = complex(dest[0].real(), 0.0f); // Ooura returns the conjugate of the usual Fourier definition. Conjugate(dest, complex_length_); } void RealFourierOoura::Inverse(const complex* src, float* dest) const { { auto* dest_complex = reinterpret_cast*>(dest); // The real output array is shorter than the input complex array by one // complex element. const size_t dest_complex_length = complex_length_ - 1; std::copy(src, src + dest_complex_length, dest_complex); // Restore Ooura's conjugate definition. Conjugate(dest_complex, dest_complex_length); // Restore real[n/2] to imag[0]. dest_complex[0] = complex(dest_complex[0].real(), src[complex_length_ - 1].real()); } WebRtc_rdft(length_, -1, dest, work_ip_.get(), work_w_.get()); // Ooura returns a scaled version. const float scale = 2.0f / length_; std::for_each(dest, dest + length_, [scale](float& v) { v *= scale; }); } int RealFourierOoura::order() const { return order_; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/real_fourier_ooura.h0000664000175000017500000000244614475643423024667 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_REAL_FOURIER_OOURA_H_ #define COMMON_AUDIO_REAL_FOURIER_OOURA_H_ #include #include #include #include "common_audio/real_fourier.h" namespace webrtc { class RealFourierOoura : public RealFourier { public: explicit RealFourierOoura(int fft_order); ~RealFourierOoura() override; void Forward(const float* src, std::complex* dest) const override; void Inverse(const std::complex* src, float* dest) const override; int order() const override; private: const int order_; const size_t length_; const size_t complex_length_; // These are work arrays for Ooura. The names are based on the comments in // common_audio/third_party/ooura/fft_size_256/fft4g.cc. const std::unique_ptr work_ip_; const std::unique_ptr work_w_; }; } // namespace webrtc #endif // COMMON_AUDIO_REAL_FOURIER_OOURA_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/real_fourier_openmax.h0000664000175000017500000000232714475643423025207 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef WEBRTC_COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_ #define WEBRTC_COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_ #include #include "webrtc/common_audio/real_fourier.h" namespace webrtc { class RealFourierOpenmax : public RealFourier { public: explicit RealFourierOpenmax(int fft_order); ~RealFourierOpenmax() override; void Forward(const float* src, std::complex* dest) const override; void Inverse(const std::complex* src, float* dest) const override; int order() const override { return order_; } private: // Basically a forward declare of OMXFFTSpec_R_F32. To get rid of the // dependency on openmax. typedef void OMXFFTSpec_R_F32_; const int order_; OMXFFTSpec_R_F32_* const omx_spec_; }; } // namespace webrtc #endif // WEBRTC_COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/resampler/0000775000175000017500000000000014475643423022617 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/resampler/include/0000775000175000017500000000000014475643423024242 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/resampler/include/push_resampler.h0000664000175000017500000000376314475643423027455 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_RESAMPLER_INCLUDE_PUSH_RESAMPLER_H_ #define COMMON_AUDIO_RESAMPLER_INCLUDE_PUSH_RESAMPLER_H_ #include #include namespace webrtc { class PushSincResampler; // Wraps PushSincResampler to provide stereo support. // TODO(ajm): add support for an arbitrary number of channels. template class PushResampler { public: PushResampler(); virtual ~PushResampler(); // Must be called whenever the parameters change. Free to be called at any // time as it is a no-op if parameters have not changed since the last call. int InitializeIfNeeded(int src_sample_rate_hz, int dst_sample_rate_hz, size_t num_channels); // Returns the total number of samples provided in destination (e.g. 32 kHz, // 2 channel audio gives 640 samples). int Resample(const T* src, size_t src_length, T* dst, size_t dst_capacity); private: int src_sample_rate_hz_; int dst_sample_rate_hz_; size_t num_channels_; // Vector that is needed to provide the proper inputs and outputs to the // interleave/de-interleave methods used in Resample. This needs to be // heap-allocated on the state to support an arbitrary number of channels // without doing run-time heap-allocations in the Resample method. std::vector channel_data_array_; struct ChannelResampler { std::unique_ptr resampler; std::vector source; std::vector destination; }; std::vector channel_resamplers_; }; } // namespace webrtc #endif // COMMON_AUDIO_RESAMPLER_INCLUDE_PUSH_RESAMPLER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/resampler/include/resampler.h0000664000175000017500000000515514475643423026413 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * A wrapper for resampling a numerous amount of sampling combinations. */ #ifndef COMMON_AUDIO_RESAMPLER_INCLUDE_RESAMPLER_H_ #define COMMON_AUDIO_RESAMPLER_INCLUDE_RESAMPLER_H_ #include #include namespace webrtc { // All methods return 0 on success and -1 on failure. class Resampler { public: Resampler(); Resampler(int inFreq, int outFreq, size_t num_channels); ~Resampler(); // Reset all states int Reset(int inFreq, int outFreq, size_t num_channels); // Reset all states if any parameter has changed int ResetIfNeeded(int inFreq, int outFreq, size_t num_channels); // Resample samplesIn to samplesOut. int Push(const int16_t* samplesIn, size_t lengthIn, int16_t* samplesOut, size_t maxLen, size_t& outLen); // NOLINT: to avoid changing APIs private: enum ResamplerMode { kResamplerMode1To1, kResamplerMode1To2, kResamplerMode1To3, kResamplerMode1To4, kResamplerMode1To6, kResamplerMode1To12, kResamplerMode2To3, kResamplerMode2To11, kResamplerMode4To11, kResamplerMode8To11, kResamplerMode11To16, kResamplerMode11To32, kResamplerMode2To1, kResamplerMode3To1, kResamplerMode4To1, kResamplerMode6To1, kResamplerMode12To1, kResamplerMode3To2, kResamplerMode11To2, kResamplerMode11To4, kResamplerMode11To8 }; // Computes the resampler mode for a given sampling frequency pair. // Returns -1 for unsupported frequency pairs. static int ComputeResamplerMode(int in_freq_hz, int out_freq_hz, ResamplerMode* mode); // Generic pointers since we don't know what states we'll need void* state1_; void* state2_; void* state3_; // Storage if needed int16_t* in_buffer_; int16_t* out_buffer_; size_t in_buffer_size_; size_t out_buffer_size_; size_t in_buffer_size_max_; size_t out_buffer_size_max_; int my_in_frequency_khz_; int my_out_frequency_khz_; ResamplerMode my_mode_; size_t num_channels_; // Extra instance for stereo Resampler* helper_left_; Resampler* helper_right_; }; } // namespace webrtc #endif // COMMON_AUDIO_RESAMPLER_INCLUDE_RESAMPLER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/resampler/push_resampler.cc0000664000175000017500000001251314475643423026161 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/resampler/include/push_resampler.h" #include #include #include #include "common_audio/include/audio_util.h" #include "common_audio/resampler/push_sinc_resampler.h" #include "rtc_base/checks.h" namespace webrtc { namespace { // These checks were factored out into a non-templatized function // due to problems with clang on Windows in debug builds. // For some reason having the DCHECKs inline in the template code // caused the compiler to generate code that threw off the linker. // TODO(tommi): Re-enable when we've figured out what the problem is. // http://crbug.com/615050 void CheckValidInitParams(int src_sample_rate_hz, int dst_sample_rate_hz, size_t num_channels) { // The below checks are temporarily disabled on WEBRTC_WIN due to problems // with clang debug builds. #if !defined(WEBRTC_WIN) && defined(__clang__) RTC_DCHECK_GT(src_sample_rate_hz, 0); RTC_DCHECK_GT(dst_sample_rate_hz, 0); RTC_DCHECK_GT(num_channels, 0); #endif } void CheckExpectedBufferSizes(size_t src_length, size_t dst_capacity, size_t num_channels, int src_sample_rate, int dst_sample_rate) { // The below checks are temporarily disabled on WEBRTC_WIN due to problems // with clang debug builds. // TODO(tommi): Re-enable when we've figured out what the problem is. // http://crbug.com/615050 #if !defined(WEBRTC_WIN) && defined(__clang__) const size_t src_size_10ms = src_sample_rate * num_channels / 100; const size_t dst_size_10ms = dst_sample_rate * num_channels / 100; RTC_DCHECK_EQ(src_length, src_size_10ms); RTC_DCHECK_GE(dst_capacity, dst_size_10ms); #endif } } // namespace template PushResampler::PushResampler() : src_sample_rate_hz_(0), dst_sample_rate_hz_(0), num_channels_(0) {} template PushResampler::~PushResampler() {} template int PushResampler::InitializeIfNeeded(int src_sample_rate_hz, int dst_sample_rate_hz, size_t num_channels) { CheckValidInitParams(src_sample_rate_hz, dst_sample_rate_hz, num_channels); if (src_sample_rate_hz == src_sample_rate_hz_ && dst_sample_rate_hz == dst_sample_rate_hz_ && num_channels == num_channels_) { // No-op if settings haven't changed. return 0; } if (src_sample_rate_hz <= 0 || dst_sample_rate_hz <= 0 || num_channels <= 0) { return -1; } src_sample_rate_hz_ = src_sample_rate_hz; dst_sample_rate_hz_ = dst_sample_rate_hz; num_channels_ = num_channels; const size_t src_size_10ms_mono = static_cast(src_sample_rate_hz / 100); const size_t dst_size_10ms_mono = static_cast(dst_sample_rate_hz / 100); channel_resamplers_.clear(); for (size_t i = 0; i < num_channels; ++i) { channel_resamplers_.push_back(ChannelResampler()); auto channel_resampler = channel_resamplers_.rbegin(); channel_resampler->resampler = std::make_unique( src_size_10ms_mono, dst_size_10ms_mono); channel_resampler->source.resize(src_size_10ms_mono); channel_resampler->destination.resize(dst_size_10ms_mono); } channel_data_array_.resize(num_channels_); return 0; } template int PushResampler::Resample(const T* src, size_t src_length, T* dst, size_t dst_capacity) { CheckExpectedBufferSizes(src_length, dst_capacity, num_channels_, src_sample_rate_hz_, dst_sample_rate_hz_); if (src_sample_rate_hz_ == dst_sample_rate_hz_) { // The old resampler provides this memcpy facility in the case of matching // sample rates, so reproduce it here for the sinc resampler. memcpy(dst, src, src_length * sizeof(T)); return static_cast(src_length); } const size_t src_length_mono = src_length / num_channels_; const size_t dst_capacity_mono = dst_capacity / num_channels_; for (size_t ch = 0; ch < num_channels_; ++ch) { channel_data_array_[ch] = channel_resamplers_[ch].source.data(); } Deinterleave(src, src_length_mono, num_channels_, channel_data_array_.data()); size_t dst_length_mono = 0; for (auto& resampler : channel_resamplers_) { dst_length_mono = resampler.resampler->Resample( resampler.source.data(), src_length_mono, resampler.destination.data(), dst_capacity_mono); } for (size_t ch = 0; ch < num_channels_; ++ch) { channel_data_array_[ch] = channel_resamplers_[ch].destination.data(); } Interleave(channel_data_array_.data(), dst_length_mono, num_channels_, dst); return static_cast(dst_length_mono * num_channels_); } // Explictly generate required instantiations. template class PushResampler; template class PushResampler; } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/resampler/push_sinc_resampler.cc0000664000175000017500000000756714475643423027212 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/resampler/push_sinc_resampler.h" #include #include "common_audio/include/audio_util.h" #include "rtc_base/checks.h" namespace webrtc { PushSincResampler::PushSincResampler(size_t source_frames, size_t destination_frames) : resampler_(new SincResampler(source_frames * 1.0 / destination_frames, source_frames, this)), source_ptr_(nullptr), source_ptr_int_(nullptr), destination_frames_(destination_frames), first_pass_(true), source_available_(0) {} PushSincResampler::~PushSincResampler() {} size_t PushSincResampler::Resample(const int16_t* source, size_t source_length, int16_t* destination, size_t destination_capacity) { if (!float_buffer_.get()) float_buffer_.reset(new float[destination_frames_]); source_ptr_int_ = source; // Pass nullptr as the float source to have Run() read from the int16 source. Resample(nullptr, source_length, float_buffer_.get(), destination_frames_); FloatS16ToS16(float_buffer_.get(), destination_frames_, destination); source_ptr_int_ = nullptr; return destination_frames_; } size_t PushSincResampler::Resample(const float* source, size_t source_length, float* destination, size_t destination_capacity) { RTC_CHECK_EQ(source_length, resampler_->request_frames()); RTC_CHECK_GE(destination_capacity, destination_frames_); // Cache the source pointer. Calling Resample() will immediately trigger // the Run() callback whereupon we provide the cached value. source_ptr_ = source; source_available_ = source_length; // On the first pass, we call Resample() twice. During the first call, we // provide dummy input and discard the output. This is done to prime the // SincResampler buffer with the correct delay (half the kernel size), thereby // ensuring that all later Resample() calls will only result in one input // request through Run(). // // If this wasn't done, SincResampler would call Run() twice on the first // pass, and we'd have to introduce an entire |source_frames| of delay, rather // than the minimum half kernel. // // It works out that ChunkSize() is exactly the amount of output we need to // request in order to prime the buffer with a single Run() request for // |source_frames|. if (first_pass_) resampler_->Resample(resampler_->ChunkSize(), destination); resampler_->Resample(destination_frames_, destination); source_ptr_ = nullptr; return destination_frames_; } void PushSincResampler::Run(size_t frames, float* destination) { // Ensure we are only asked for the available samples. This would fail if // Run() was triggered more than once per Resample() call. RTC_CHECK_EQ(source_available_, frames); if (first_pass_) { // Provide dummy input on the first pass, the output of which will be // discarded, as described in Resample(). std::memset(destination, 0, frames * sizeof(*destination)); first_pass_ = false; return; } if (source_ptr_) { std::memcpy(destination, source_ptr_, frames * sizeof(*destination)); } else { for (size_t i = 0; i < frames; ++i) destination[i] = static_cast(source_ptr_int_[i]); } source_available_ -= frames; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/resampler/push_sinc_resampler.h0000664000175000017500000000574614475643423027051 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_RESAMPLER_PUSH_SINC_RESAMPLER_H_ #define COMMON_AUDIO_RESAMPLER_PUSH_SINC_RESAMPLER_H_ #include #include #include #include "common_audio/resampler/sinc_resampler.h" #include "rtc_base/constructor_magic.h" namespace webrtc { // A thin wrapper over SincResampler to provide a push-based interface as // required by WebRTC. SincResampler uses a pull-based interface, and will // use SincResamplerCallback::Run() to request data upon a call to Resample(). // These Run() calls will happen on the same thread Resample() is called on. class PushSincResampler : public SincResamplerCallback { public: // Provide the size of the source and destination blocks in samples. These // must correspond to the same time duration (typically 10 ms) as the sample // ratio is inferred from them. PushSincResampler(size_t source_frames, size_t destination_frames); ~PushSincResampler() override; // Perform the resampling. |source_frames| must always equal the // |source_frames| provided at construction. |destination_capacity| must be // at least as large as |destination_frames|. Returns the number of samples // provided in destination (for convenience, since this will always be equal // to |destination_frames|). size_t Resample(const int16_t* source, size_t source_frames, int16_t* destination, size_t destination_capacity); size_t Resample(const float* source, size_t source_frames, float* destination, size_t destination_capacity); // Delay due to the filter kernel. Essentially, the time after which an input // sample will appear in the resampled output. static float AlgorithmicDelaySeconds(int source_rate_hz) { return 1.f / source_rate_hz * SincResampler::kKernelSize / 2; } protected: // Implements SincResamplerCallback. void Run(size_t frames, float* destination) override; private: friend class PushSincResamplerTest; SincResampler* get_resampler_for_testing() { return resampler_.get(); } std::unique_ptr resampler_; std::unique_ptr float_buffer_; const float* source_ptr_; const int16_t* source_ptr_int_; const size_t destination_frames_; // True on the first call to Resample(), to prime the SincResampler buffer. bool first_pass_; // Used to assert we are only requested for as much data as is available. size_t source_available_; RTC_DISALLOW_COPY_AND_ASSIGN(PushSincResampler); }; } // namespace webrtc #endif // COMMON_AUDIO_RESAMPLER_PUSH_SINC_RESAMPLER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/resampler/resampler.cc0000664000175000017500000007053014475643423025125 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * A wrapper for resampling a numerous amount of sampling combinations. */ #include "common_audio/resampler/include/resampler.h" #include #include #include #include "common_audio/signal_processing/include/signal_processing_library.h" #include "rtc_base/logging.h" namespace webrtc { Resampler::Resampler() : state1_(nullptr), state2_(nullptr), state3_(nullptr), in_buffer_(nullptr), out_buffer_(nullptr), in_buffer_size_(0), out_buffer_size_(0), in_buffer_size_max_(0), out_buffer_size_max_(0), my_in_frequency_khz_(0), my_out_frequency_khz_(0), my_mode_(kResamplerMode1To1), num_channels_(0), helper_left_(nullptr), helper_right_(nullptr) {} Resampler::Resampler(int inFreq, int outFreq, size_t num_channels) : Resampler() { Reset(inFreq, outFreq, num_channels); } Resampler::~Resampler() { if (state1_) { free(state1_); } if (state2_) { free(state2_); } if (state3_) { free(state3_); } if (in_buffer_) { free(in_buffer_); } if (out_buffer_) { free(out_buffer_); } if (helper_left_) { delete helper_left_; } if (helper_right_) { delete helper_right_; } } int Resampler::ResetIfNeeded(int inFreq, int outFreq, size_t num_channels) { int tmpInFreq_kHz = inFreq / 1000; int tmpOutFreq_kHz = outFreq / 1000; if ((tmpInFreq_kHz != my_in_frequency_khz_) || (tmpOutFreq_kHz != my_out_frequency_khz_) || (num_channels != num_channels_)) { return Reset(inFreq, outFreq, num_channels); } else { return 0; } } int Resampler::Reset(int inFreq, int outFreq, size_t num_channels) { if (num_channels != 1 && num_channels != 2) { RTC_LOG(LS_WARNING) << "Reset() called with unsupported channel count, num_channels = " << num_channels; return -1; } ResamplerMode mode; if (ComputeResamplerMode(inFreq, outFreq, &mode) != 0) { RTC_LOG(LS_WARNING) << "Reset() called with unsupported sample rates, inFreq = " << inFreq << ", outFreq = " << outFreq; return -1; } // Reinitialize internal state for the frequencies and sample rates. num_channels_ = num_channels; my_mode_ = mode; if (state1_) { free(state1_); state1_ = nullptr; } if (state2_) { free(state2_); state2_ = nullptr; } if (state3_) { free(state3_); state3_ = nullptr; } if (in_buffer_) { free(in_buffer_); in_buffer_ = nullptr; } if (out_buffer_) { free(out_buffer_); out_buffer_ = nullptr; } if (helper_left_) { delete helper_left_; helper_left_ = nullptr; } if (helper_right_) { delete helper_right_; helper_right_ = nullptr; } in_buffer_size_ = 0; out_buffer_size_ = 0; in_buffer_size_max_ = 0; out_buffer_size_max_ = 0; // We need to track what domain we're in. my_in_frequency_khz_ = inFreq / 1000; my_out_frequency_khz_ = outFreq / 1000; if (num_channels_ == 2) { // Create two mono resamplers. helper_left_ = new Resampler(inFreq, outFreq, 1); helper_right_ = new Resampler(inFreq, outFreq, 1); } // Now create the states we need. switch (my_mode_) { case kResamplerMode1To1: // No state needed; break; case kResamplerMode1To2: state1_ = malloc(8 * sizeof(int32_t)); memset(state1_, 0, 8 * sizeof(int32_t)); break; case kResamplerMode1To3: state1_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz)); WebRtcSpl_ResetResample16khzTo48khz( static_cast(state1_)); break; case kResamplerMode1To4: // 1:2 state1_ = malloc(8 * sizeof(int32_t)); memset(state1_, 0, 8 * sizeof(int32_t)); // 2:4 state2_ = malloc(8 * sizeof(int32_t)); memset(state2_, 0, 8 * sizeof(int32_t)); break; case kResamplerMode1To6: // 1:2 state1_ = malloc(8 * sizeof(int32_t)); memset(state1_, 0, 8 * sizeof(int32_t)); // 2:6 state2_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz)); WebRtcSpl_ResetResample16khzTo48khz( static_cast(state2_)); break; case kResamplerMode1To12: // 1:2 state1_ = malloc(8 * sizeof(int32_t)); memset(state1_, 0, 8 * sizeof(int32_t)); // 2:4 state2_ = malloc(8 * sizeof(int32_t)); memset(state2_, 0, 8 * sizeof(int32_t)); // 4:12 state3_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz)); WebRtcSpl_ResetResample16khzTo48khz( static_cast(state3_)); break; case kResamplerMode2To3: // 2:6 state1_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz)); WebRtcSpl_ResetResample16khzTo48khz( static_cast(state1_)); // 6:3 state2_ = malloc(8 * sizeof(int32_t)); memset(state2_, 0, 8 * sizeof(int32_t)); break; case kResamplerMode2To11: state1_ = malloc(8 * sizeof(int32_t)); memset(state1_, 0, 8 * sizeof(int32_t)); state2_ = malloc(sizeof(WebRtcSpl_State8khzTo22khz)); WebRtcSpl_ResetResample8khzTo22khz( static_cast(state2_)); break; case kResamplerMode4To11: state1_ = malloc(sizeof(WebRtcSpl_State8khzTo22khz)); WebRtcSpl_ResetResample8khzTo22khz( static_cast(state1_)); break; case kResamplerMode8To11: state1_ = malloc(sizeof(WebRtcSpl_State16khzTo22khz)); WebRtcSpl_ResetResample16khzTo22khz( static_cast(state1_)); break; case kResamplerMode11To16: state1_ = malloc(8 * sizeof(int32_t)); memset(state1_, 0, 8 * sizeof(int32_t)); state2_ = malloc(sizeof(WebRtcSpl_State22khzTo16khz)); WebRtcSpl_ResetResample22khzTo16khz( static_cast(state2_)); break; case kResamplerMode11To32: // 11 -> 22 state1_ = malloc(8 * sizeof(int32_t)); memset(state1_, 0, 8 * sizeof(int32_t)); // 22 -> 16 state2_ = malloc(sizeof(WebRtcSpl_State22khzTo16khz)); WebRtcSpl_ResetResample22khzTo16khz( static_cast(state2_)); // 16 -> 32 state3_ = malloc(8 * sizeof(int32_t)); memset(state3_, 0, 8 * sizeof(int32_t)); break; case kResamplerMode2To1: state1_ = malloc(8 * sizeof(int32_t)); memset(state1_, 0, 8 * sizeof(int32_t)); break; case kResamplerMode3To1: state1_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz)); WebRtcSpl_ResetResample48khzTo16khz( static_cast(state1_)); break; case kResamplerMode4To1: // 4:2 state1_ = malloc(8 * sizeof(int32_t)); memset(state1_, 0, 8 * sizeof(int32_t)); // 2:1 state2_ = malloc(8 * sizeof(int32_t)); memset(state2_, 0, 8 * sizeof(int32_t)); break; case kResamplerMode6To1: // 6:2 state1_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz)); WebRtcSpl_ResetResample48khzTo16khz( static_cast(state1_)); // 2:1 state2_ = malloc(8 * sizeof(int32_t)); memset(state2_, 0, 8 * sizeof(int32_t)); break; case kResamplerMode12To1: // 12:4 state1_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz)); WebRtcSpl_ResetResample48khzTo16khz( static_cast(state1_)); // 4:2 state2_ = malloc(8 * sizeof(int32_t)); memset(state2_, 0, 8 * sizeof(int32_t)); // 2:1 state3_ = malloc(8 * sizeof(int32_t)); memset(state3_, 0, 8 * sizeof(int32_t)); break; case kResamplerMode3To2: // 3:6 state1_ = malloc(8 * sizeof(int32_t)); memset(state1_, 0, 8 * sizeof(int32_t)); // 6:2 state2_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz)); WebRtcSpl_ResetResample48khzTo16khz( static_cast(state2_)); break; case kResamplerMode11To2: state1_ = malloc(sizeof(WebRtcSpl_State22khzTo8khz)); WebRtcSpl_ResetResample22khzTo8khz( static_cast(state1_)); state2_ = malloc(8 * sizeof(int32_t)); memset(state2_, 0, 8 * sizeof(int32_t)); break; case kResamplerMode11To4: state1_ = malloc(sizeof(WebRtcSpl_State22khzTo8khz)); WebRtcSpl_ResetResample22khzTo8khz( static_cast(state1_)); break; case kResamplerMode11To8: state1_ = malloc(sizeof(WebRtcSpl_State22khzTo16khz)); WebRtcSpl_ResetResample22khzTo16khz( static_cast(state1_)); break; } return 0; } int Resampler::ComputeResamplerMode(int in_freq_hz, int out_freq_hz, ResamplerMode* mode) { // Start with a math exercise, Euclid's algorithm to find the gcd: int a = in_freq_hz; int b = out_freq_hz; int c = a % b; while (c != 0) { a = b; b = c; c = a % b; } // b is now the gcd; // Scale with GCD const int reduced_in_freq = in_freq_hz / b; const int reduced_out_freq = out_freq_hz / b; if (reduced_in_freq == reduced_out_freq) { *mode = kResamplerMode1To1; } else if (reduced_in_freq == 1) { switch (reduced_out_freq) { case 2: *mode = kResamplerMode1To2; break; case 3: *mode = kResamplerMode1To3; break; case 4: *mode = kResamplerMode1To4; break; case 6: *mode = kResamplerMode1To6; break; case 12: *mode = kResamplerMode1To12; break; default: return -1; } } else if (reduced_out_freq == 1) { switch (reduced_in_freq) { case 2: *mode = kResamplerMode2To1; break; case 3: *mode = kResamplerMode3To1; break; case 4: *mode = kResamplerMode4To1; break; case 6: *mode = kResamplerMode6To1; break; case 12: *mode = kResamplerMode12To1; break; default: return -1; } } else if ((reduced_in_freq == 2) && (reduced_out_freq == 3)) { *mode = kResamplerMode2To3; } else if ((reduced_in_freq == 2) && (reduced_out_freq == 11)) { *mode = kResamplerMode2To11; } else if ((reduced_in_freq == 4) && (reduced_out_freq == 11)) { *mode = kResamplerMode4To11; } else if ((reduced_in_freq == 8) && (reduced_out_freq == 11)) { *mode = kResamplerMode8To11; } else if ((reduced_in_freq == 3) && (reduced_out_freq == 2)) { *mode = kResamplerMode3To2; } else if ((reduced_in_freq == 11) && (reduced_out_freq == 2)) { *mode = kResamplerMode11To2; } else if ((reduced_in_freq == 11) && (reduced_out_freq == 4)) { *mode = kResamplerMode11To4; } else if ((reduced_in_freq == 11) && (reduced_out_freq == 16)) { *mode = kResamplerMode11To16; } else if ((reduced_in_freq == 11) && (reduced_out_freq == 32)) { *mode = kResamplerMode11To32; } else if ((reduced_in_freq == 11) && (reduced_out_freq == 8)) { *mode = kResamplerMode11To8; } else { return -1; } return 0; } // Synchronous resampling, all output samples are written to samplesOut int Resampler::Push(const int16_t* samplesIn, size_t lengthIn, int16_t* samplesOut, size_t maxLen, size_t& outLen) { if (num_channels_ == 2) { // Split up the signal and call the helper object for each channel int16_t* left = static_cast(malloc(lengthIn * sizeof(int16_t) / 2)); int16_t* right = static_cast(malloc(lengthIn * sizeof(int16_t) / 2)); int16_t* out_left = static_cast(malloc(maxLen / 2 * sizeof(int16_t))); int16_t* out_right = static_cast(malloc(maxLen / 2 * sizeof(int16_t))); int res = 0; for (size_t i = 0; i < lengthIn; i += 2) { left[i >> 1] = samplesIn[i]; right[i >> 1] = samplesIn[i + 1]; } // It's OK to overwrite the local parameter, since it's just a copy lengthIn = lengthIn / 2; size_t actualOutLen_left = 0; size_t actualOutLen_right = 0; // Do resampling for right channel res |= helper_left_->Push(left, lengthIn, out_left, maxLen / 2, actualOutLen_left); res |= helper_right_->Push(right, lengthIn, out_right, maxLen / 2, actualOutLen_right); if (res || (actualOutLen_left != actualOutLen_right)) { free(left); free(right); free(out_left); free(out_right); return -1; } // Reassemble the signal for (size_t i = 0; i < actualOutLen_left; i++) { samplesOut[i * 2] = out_left[i]; samplesOut[i * 2 + 1] = out_right[i]; } outLen = 2 * actualOutLen_left; free(left); free(right); free(out_left); free(out_right); return 0; } // Containers for temp samples int16_t* tmp; int16_t* tmp_2; // tmp data for resampling routines int32_t* tmp_mem; switch (my_mode_) { case kResamplerMode1To1: memcpy(samplesOut, samplesIn, lengthIn * sizeof(int16_t)); outLen = lengthIn; break; case kResamplerMode1To2: if (maxLen < (lengthIn * 2)) { return -1; } WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut, static_cast(state1_)); outLen = lengthIn * 2; return 0; case kResamplerMode1To3: // We can only handle blocks of 160 samples // Can be fixed, but I don't think it's needed if ((lengthIn % 160) != 0) { return -1; } if (maxLen < (lengthIn * 3)) { return -1; } tmp_mem = static_cast(malloc(336 * sizeof(int32_t))); for (size_t i = 0; i < lengthIn; i += 160) { WebRtcSpl_Resample16khzTo48khz( samplesIn + i, samplesOut + i * 3, static_cast(state1_), tmp_mem); } outLen = lengthIn * 3; free(tmp_mem); return 0; case kResamplerMode1To4: if (maxLen < (lengthIn * 4)) { return -1; } tmp = static_cast(malloc(sizeof(int16_t) * 2 * lengthIn)); // 1:2 WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, static_cast(state1_)); // 2:4 WebRtcSpl_UpsampleBy2(tmp, lengthIn * 2, samplesOut, static_cast(state2_)); outLen = lengthIn * 4; free(tmp); return 0; case kResamplerMode1To6: // We can only handle blocks of 80 samples // Can be fixed, but I don't think it's needed if ((lengthIn % 80) != 0) { return -1; } if (maxLen < (lengthIn * 6)) { return -1; } // 1:2 tmp_mem = static_cast(malloc(336 * sizeof(int32_t))); tmp = static_cast(malloc(sizeof(int16_t) * 2 * lengthIn)); WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, static_cast(state1_)); outLen = lengthIn * 2; for (size_t i = 0; i < outLen; i += 160) { WebRtcSpl_Resample16khzTo48khz( tmp + i, samplesOut + i * 3, static_cast(state2_), tmp_mem); } outLen = outLen * 3; free(tmp_mem); free(tmp); return 0; case kResamplerMode1To12: // We can only handle blocks of 40 samples // Can be fixed, but I don't think it's needed if ((lengthIn % 40) != 0) { return -1; } if (maxLen < (lengthIn * 12)) { return -1; } tmp_mem = static_cast(malloc(336 * sizeof(int32_t))); tmp = static_cast(malloc(sizeof(int16_t) * 4 * lengthIn)); // 1:2 WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut, static_cast(state1_)); outLen = lengthIn * 2; // 2:4 WebRtcSpl_UpsampleBy2(samplesOut, outLen, tmp, static_cast(state2_)); outLen = outLen * 2; // 4:12 for (size_t i = 0; i < outLen; i += 160) { // WebRtcSpl_Resample16khzTo48khz() takes a block of 160 samples // as input and outputs a resampled block of 480 samples. The // data is now actually in 32 kHz sampling rate, despite the // function name, and with a resampling factor of three becomes // 96 kHz. WebRtcSpl_Resample16khzTo48khz( tmp + i, samplesOut + i * 3, static_cast(state3_), tmp_mem); } outLen = outLen * 3; free(tmp_mem); free(tmp); return 0; case kResamplerMode2To3: if (maxLen < (lengthIn * 3 / 2)) { return -1; } // 2:6 // We can only handle blocks of 160 samples // Can be fixed, but I don't think it's needed if ((lengthIn % 160) != 0) { return -1; } tmp = static_cast(malloc(sizeof(int16_t) * lengthIn * 3)); tmp_mem = static_cast(malloc(336 * sizeof(int32_t))); for (size_t i = 0; i < lengthIn; i += 160) { WebRtcSpl_Resample16khzTo48khz( samplesIn + i, tmp + i * 3, static_cast(state1_), tmp_mem); } lengthIn = lengthIn * 3; // 6:3 WebRtcSpl_DownsampleBy2(tmp, lengthIn, samplesOut, static_cast(state2_)); outLen = lengthIn / 2; free(tmp); free(tmp_mem); return 0; case kResamplerMode2To11: // We can only handle blocks of 80 samples // Can be fixed, but I don't think it's needed if ((lengthIn % 80) != 0) { return -1; } if (maxLen < ((lengthIn * 11) / 2)) { return -1; } tmp = static_cast(malloc(sizeof(int16_t) * 2 * lengthIn)); // 1:2 WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, static_cast(state1_)); lengthIn *= 2; tmp_mem = static_cast(malloc(98 * sizeof(int32_t))); for (size_t i = 0; i < lengthIn; i += 80) { WebRtcSpl_Resample8khzTo22khz( tmp + i, samplesOut + (i * 11) / 4, static_cast(state2_), tmp_mem); } outLen = (lengthIn * 11) / 4; free(tmp_mem); free(tmp); return 0; case kResamplerMode4To11: // We can only handle blocks of 80 samples // Can be fixed, but I don't think it's needed if ((lengthIn % 80) != 0) { return -1; } if (maxLen < ((lengthIn * 11) / 4)) { return -1; } tmp_mem = static_cast(malloc(98 * sizeof(int32_t))); for (size_t i = 0; i < lengthIn; i += 80) { WebRtcSpl_Resample8khzTo22khz( samplesIn + i, samplesOut + (i * 11) / 4, static_cast(state1_), tmp_mem); } outLen = (lengthIn * 11) / 4; free(tmp_mem); return 0; case kResamplerMode8To11: // We can only handle blocks of 160 samples // Can be fixed, but I don't think it's needed if ((lengthIn % 160) != 0) { return -1; } if (maxLen < ((lengthIn * 11) / 8)) { return -1; } tmp_mem = static_cast(malloc(88 * sizeof(int32_t))); for (size_t i = 0; i < lengthIn; i += 160) { WebRtcSpl_Resample16khzTo22khz( samplesIn + i, samplesOut + (i * 11) / 8, static_cast(state1_), tmp_mem); } outLen = (lengthIn * 11) / 8; free(tmp_mem); return 0; case kResamplerMode11To16: // We can only handle blocks of 110 samples if ((lengthIn % 110) != 0) { return -1; } if (maxLen < ((lengthIn * 16) / 11)) { return -1; } tmp_mem = static_cast(malloc(104 * sizeof(int32_t))); tmp = static_cast(malloc((sizeof(int16_t) * lengthIn * 2))); WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, static_cast(state1_)); for (size_t i = 0; i < (lengthIn * 2); i += 220) { WebRtcSpl_Resample22khzTo16khz( tmp + i, samplesOut + (i / 220) * 160, static_cast(state2_), tmp_mem); } outLen = (lengthIn * 16) / 11; free(tmp_mem); free(tmp); return 0; case kResamplerMode11To32: // We can only handle blocks of 110 samples if ((lengthIn % 110) != 0) { return -1; } if (maxLen < ((lengthIn * 32) / 11)) { return -1; } tmp_mem = static_cast(malloc(104 * sizeof(int32_t))); tmp = static_cast(malloc((sizeof(int16_t) * lengthIn * 2))); // 11 -> 22 kHz in samplesOut WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut, static_cast(state1_)); // 22 -> 16 in tmp for (size_t i = 0; i < (lengthIn * 2); i += 220) { WebRtcSpl_Resample22khzTo16khz( samplesOut + i, tmp + (i / 220) * 160, static_cast(state2_), tmp_mem); } // 16 -> 32 in samplesOut WebRtcSpl_UpsampleBy2(tmp, (lengthIn * 16) / 11, samplesOut, static_cast(state3_)); outLen = (lengthIn * 32) / 11; free(tmp_mem); free(tmp); return 0; case kResamplerMode2To1: if (maxLen < (lengthIn / 2)) { return -1; } WebRtcSpl_DownsampleBy2(samplesIn, lengthIn, samplesOut, static_cast(state1_)); outLen = lengthIn / 2; return 0; case kResamplerMode3To1: // We can only handle blocks of 480 samples // Can be fixed, but I don't think it's needed if ((lengthIn % 480) != 0) { return -1; } if (maxLen < (lengthIn / 3)) { return -1; } tmp_mem = static_cast(malloc(496 * sizeof(int32_t))); for (size_t i = 0; i < lengthIn; i += 480) { WebRtcSpl_Resample48khzTo16khz( samplesIn + i, samplesOut + i / 3, static_cast(state1_), tmp_mem); } outLen = lengthIn / 3; free(tmp_mem); return 0; case kResamplerMode4To1: if (maxLen < (lengthIn / 4)) { return -1; } tmp = static_cast(malloc(sizeof(int16_t) * lengthIn / 2)); // 4:2 WebRtcSpl_DownsampleBy2(samplesIn, lengthIn, tmp, static_cast(state1_)); // 2:1 WebRtcSpl_DownsampleBy2(tmp, lengthIn / 2, samplesOut, static_cast(state2_)); outLen = lengthIn / 4; free(tmp); return 0; case kResamplerMode6To1: // We can only handle blocks of 480 samples // Can be fixed, but I don't think it's needed if ((lengthIn % 480) != 0) { return -1; } if (maxLen < (lengthIn / 6)) { return -1; } tmp_mem = static_cast(malloc(496 * sizeof(int32_t))); tmp = static_cast(malloc((sizeof(int16_t) * lengthIn) / 3)); for (size_t i = 0; i < lengthIn; i += 480) { WebRtcSpl_Resample48khzTo16khz( samplesIn + i, tmp + i / 3, static_cast(state1_), tmp_mem); } outLen = lengthIn / 3; free(tmp_mem); WebRtcSpl_DownsampleBy2(tmp, outLen, samplesOut, static_cast(state2_)); free(tmp); outLen = outLen / 2; return 0; case kResamplerMode12To1: // We can only handle blocks of 480 samples // Can be fixed, but I don't think it's needed if ((lengthIn % 480) != 0) { return -1; } if (maxLen < (lengthIn / 12)) { return -1; } tmp_mem = static_cast(malloc(496 * sizeof(int32_t))); tmp = static_cast(malloc((sizeof(int16_t) * lengthIn) / 3)); tmp_2 = static_cast(malloc((sizeof(int16_t) * lengthIn) / 6)); // 12:4 for (size_t i = 0; i < lengthIn; i += 480) { // WebRtcSpl_Resample48khzTo16khz() takes a block of 480 samples // as input and outputs a resampled block of 160 samples. The // data is now actually in 96 kHz sampling rate, despite the // function name, and with a resampling factor of 1/3 becomes // 32 kHz. WebRtcSpl_Resample48khzTo16khz( samplesIn + i, tmp + i / 3, static_cast(state1_), tmp_mem); } outLen = lengthIn / 3; free(tmp_mem); // 4:2 WebRtcSpl_DownsampleBy2(tmp, outLen, tmp_2, static_cast(state2_)); outLen = outLen / 2; free(tmp); // 2:1 WebRtcSpl_DownsampleBy2(tmp_2, outLen, samplesOut, static_cast(state3_)); free(tmp_2); outLen = outLen / 2; return 0; case kResamplerMode3To2: if (maxLen < (lengthIn * 2 / 3)) { return -1; } // 3:6 tmp = static_cast(malloc(sizeof(int16_t) * lengthIn * 2)); WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, static_cast(state1_)); lengthIn *= 2; // 6:2 // We can only handle blocks of 480 samples // Can be fixed, but I don't think it's needed if ((lengthIn % 480) != 0) { free(tmp); return -1; } tmp_mem = static_cast(malloc(496 * sizeof(int32_t))); for (size_t i = 0; i < lengthIn; i += 480) { WebRtcSpl_Resample48khzTo16khz( tmp + i, samplesOut + i / 3, static_cast(state2_), tmp_mem); } outLen = lengthIn / 3; free(tmp); free(tmp_mem); return 0; case kResamplerMode11To2: // We can only handle blocks of 220 samples // Can be fixed, but I don't think it's needed if ((lengthIn % 220) != 0) { return -1; } if (maxLen < ((lengthIn * 2) / 11)) { return -1; } tmp_mem = static_cast(malloc(126 * sizeof(int32_t))); tmp = static_cast(malloc((lengthIn * 4) / 11 * sizeof(int16_t))); for (size_t i = 0; i < lengthIn; i += 220) { WebRtcSpl_Resample22khzTo8khz( samplesIn + i, tmp + (i * 4) / 11, static_cast(state1_), tmp_mem); } lengthIn = (lengthIn * 4) / 11; WebRtcSpl_DownsampleBy2(tmp, lengthIn, samplesOut, static_cast(state2_)); outLen = lengthIn / 2; free(tmp_mem); free(tmp); return 0; case kResamplerMode11To4: // We can only handle blocks of 220 samples // Can be fixed, but I don't think it's needed if ((lengthIn % 220) != 0) { return -1; } if (maxLen < ((lengthIn * 4) / 11)) { return -1; } tmp_mem = static_cast(malloc(126 * sizeof(int32_t))); for (size_t i = 0; i < lengthIn; i += 220) { WebRtcSpl_Resample22khzTo8khz( samplesIn + i, samplesOut + (i * 4) / 11, static_cast(state1_), tmp_mem); } outLen = (lengthIn * 4) / 11; free(tmp_mem); return 0; case kResamplerMode11To8: // We can only handle blocks of 160 samples // Can be fixed, but I don't think it's needed if ((lengthIn % 220) != 0) { return -1; } if (maxLen < ((lengthIn * 8) / 11)) { return -1; } tmp_mem = static_cast(malloc(104 * sizeof(int32_t))); for (size_t i = 0; i < lengthIn; i += 220) { WebRtcSpl_Resample22khzTo16khz( samplesIn + i, samplesOut + (i * 8) / 11, static_cast(state1_), tmp_mem); } outLen = (lengthIn * 8) / 11; free(tmp_mem); return 0; break; } return 0; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/resampler/sinc_resampler.cc0000664000175000017500000003317614475643423026146 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Modified from the Chromium original: // src/media/base/sinc_resampler.cc // Initial input buffer layout, dividing into regions r0_ to r4_ (note: r0_, r3_ // and r4_ will move after the first load): // // |----------------|-----------------------------------------|----------------| // // request_frames_ // <---------------------------------------------------------> // r0_ (during first load) // // kKernelSize / 2 kKernelSize / 2 kKernelSize / 2 kKernelSize / 2 // <---------------> <---------------> <---------------> <---------------> // r1_ r2_ r3_ r4_ // // block_size_ == r4_ - r2_ // <---------------------------------------> // // request_frames_ // <------------------ ... -----------------> // r0_ (during second load) // // On the second request r0_ slides to the right by kKernelSize / 2 and r3_, r4_ // and block_size_ are reinitialized via step (3) in the algorithm below. // // These new regions remain constant until a Flush() occurs. While complicated, // this allows us to reduce jitter by always requesting the same amount from the // provided callback. // // The algorithm: // // 1) Allocate input_buffer of size: request_frames_ + kKernelSize; this ensures // there's enough room to read request_frames_ from the callback into region // r0_ (which will move between the first and subsequent passes). // // 2) Let r1_, r2_ each represent half the kernel centered around r0_: // // r0_ = input_buffer_ + kKernelSize / 2 // r1_ = input_buffer_ // r2_ = r0_ // // r0_ is always request_frames_ in size. r1_, r2_ are kKernelSize / 2 in // size. r1_ must be zero initialized to avoid convolution with garbage (see // step (5) for why). // // 3) Let r3_, r4_ each represent half the kernel right aligned with the end of // r0_ and choose block_size_ as the distance in frames between r4_ and r2_: // // r3_ = r0_ + request_frames_ - kKernelSize // r4_ = r0_ + request_frames_ - kKernelSize / 2 // block_size_ = r4_ - r2_ = request_frames_ - kKernelSize / 2 // // 4) Consume request_frames_ frames into r0_. // // 5) Position kernel centered at start of r2_ and generate output frames until // the kernel is centered at the start of r4_ or we've finished generating // all the output frames. // // 6) Wrap left over data from the r3_ to r1_ and r4_ to r2_. // // 7) If we're on the second load, in order to avoid overwriting the frames we // just wrapped from r4_ we need to slide r0_ to the right by the size of // r4_, which is kKernelSize / 2: // // r0_ = r0_ + kKernelSize / 2 = input_buffer_ + kKernelSize // // r3_, r4_, and block_size_ then need to be reinitialized, so goto (3). // // 8) Else, if we're not on the second load, goto (4). // // Note: we're glossing over how the sub-sample handling works with // |virtual_source_idx_|, etc. // MSVC++ requires this to be set before any other includes to get M_PI. #define _USE_MATH_DEFINES #include "common_audio/resampler/sinc_resampler.h" #include #include #include #include #include "rtc_base/checks.h" #include "rtc_base/system/arch.h" #include "system_wrappers/include/cpu_features_wrapper.h" // kSSE2, WebRtc_G... namespace webrtc { namespace { double SincScaleFactor(double io_ratio) { // |sinc_scale_factor| is basically the normalized cutoff frequency of the // low-pass filter. double sinc_scale_factor = io_ratio > 1.0 ? 1.0 / io_ratio : 1.0; // The sinc function is an idealized brick-wall filter, but since we're // windowing it the transition from pass to stop does not happen right away. // So we should adjust the low pass filter cutoff slightly downward to avoid // some aliasing at the very high-end. // TODO(crogers): this value is empirical and to be more exact should vary // depending on kKernelSize. sinc_scale_factor *= 0.9; return sinc_scale_factor; } } // namespace const size_t SincResampler::kKernelSize; // If we know the minimum architecture at compile time, avoid CPU detection. void SincResampler::InitializeCPUSpecificFeatures() { #if defined(WEBRTC_HAS_NEON) convolve_proc_ = Convolve_NEON; #elif defined(WEBRTC_ARCH_X86_FAMILY) // Using AVX2 instead of SSE2 when AVX2 supported. if (GetCPUInfo(kAVX2)) convolve_proc_ = Convolve_AVX2; else if (GetCPUInfo(kSSE2)) convolve_proc_ = Convolve_SSE; else convolve_proc_ = Convolve_C; #else // Unknown architecture. convolve_proc_ = Convolve_C; #endif } SincResampler::SincResampler(double io_sample_rate_ratio, size_t request_frames, SincResamplerCallback* read_cb) : io_sample_rate_ratio_(io_sample_rate_ratio), read_cb_(read_cb), request_frames_(request_frames), input_buffer_size_(request_frames_ + kKernelSize), // Create input buffers with a 32-byte alignment for SIMD optimizations. kernel_storage_(static_cast( AlignedMalloc(sizeof(float) * kKernelStorageSize, 32))), kernel_pre_sinc_storage_(static_cast( AlignedMalloc(sizeof(float) * kKernelStorageSize, 32))), kernel_window_storage_(static_cast( AlignedMalloc(sizeof(float) * kKernelStorageSize, 32))), input_buffer_(static_cast( AlignedMalloc(sizeof(float) * input_buffer_size_, 32))), convolve_proc_(nullptr), r1_(input_buffer_.get()), r2_(input_buffer_.get() + kKernelSize / 2) { InitializeCPUSpecificFeatures(); RTC_DCHECK(convolve_proc_); RTC_DCHECK_GT(request_frames_, 0); Flush(); RTC_DCHECK_GT(block_size_, kKernelSize); memset(kernel_storage_.get(), 0, sizeof(*kernel_storage_.get()) * kKernelStorageSize); memset(kernel_pre_sinc_storage_.get(), 0, sizeof(*kernel_pre_sinc_storage_.get()) * kKernelStorageSize); memset(kernel_window_storage_.get(), 0, sizeof(*kernel_window_storage_.get()) * kKernelStorageSize); InitializeKernel(); } SincResampler::~SincResampler() {} void SincResampler::UpdateRegions(bool second_load) { // Setup various region pointers in the buffer (see diagram above). If we're // on the second load we need to slide r0_ to the right by kKernelSize / 2. r0_ = input_buffer_.get() + (second_load ? kKernelSize : kKernelSize / 2); r3_ = r0_ + request_frames_ - kKernelSize; r4_ = r0_ + request_frames_ - kKernelSize / 2; block_size_ = r4_ - r2_; // r1_ at the beginning of the buffer. RTC_DCHECK_EQ(r1_, input_buffer_.get()); // r1_ left of r2_, r4_ left of r3_ and size correct. RTC_DCHECK_EQ(r2_ - r1_, r4_ - r3_); // r2_ left of r3. RTC_DCHECK_LT(r2_, r3_); } void SincResampler::InitializeKernel() { // Blackman window parameters. static const double kAlpha = 0.16; static const double kA0 = 0.5 * (1.0 - kAlpha); static const double kA1 = 0.5; static const double kA2 = 0.5 * kAlpha; // Generates a set of windowed sinc() kernels. // We generate a range of sub-sample offsets from 0.0 to 1.0. const double sinc_scale_factor = SincScaleFactor(io_sample_rate_ratio_); for (size_t offset_idx = 0; offset_idx <= kKernelOffsetCount; ++offset_idx) { const float subsample_offset = static_cast(offset_idx) / kKernelOffsetCount; for (size_t i = 0; i < kKernelSize; ++i) { const size_t idx = i + offset_idx * kKernelSize; const float pre_sinc = static_cast( M_PI * (static_cast(i) - static_cast(kKernelSize / 2) - subsample_offset)); kernel_pre_sinc_storage_[idx] = pre_sinc; // Compute Blackman window, matching the offset of the sinc(). const float x = (i - subsample_offset) / kKernelSize; const float window = static_cast(kA0 - kA1 * cos(2.0 * M_PI * x) + kA2 * cos(4.0 * M_PI * x)); kernel_window_storage_[idx] = window; // Compute the sinc with offset, then window the sinc() function and store // at the correct offset. kernel_storage_[idx] = static_cast( window * ((pre_sinc == 0) ? sinc_scale_factor : (sin(sinc_scale_factor * pre_sinc) / pre_sinc))); } } } void SincResampler::SetRatio(double io_sample_rate_ratio) { if (fabs(io_sample_rate_ratio_ - io_sample_rate_ratio) < std::numeric_limits::epsilon()) { return; } io_sample_rate_ratio_ = io_sample_rate_ratio; // Optimize reinitialization by reusing values which are independent of // |sinc_scale_factor|. Provides a 3x speedup. const double sinc_scale_factor = SincScaleFactor(io_sample_rate_ratio_); for (size_t offset_idx = 0; offset_idx <= kKernelOffsetCount; ++offset_idx) { for (size_t i = 0; i < kKernelSize; ++i) { const size_t idx = i + offset_idx * kKernelSize; const float window = kernel_window_storage_[idx]; const float pre_sinc = kernel_pre_sinc_storage_[idx]; kernel_storage_[idx] = static_cast( window * ((pre_sinc == 0) ? sinc_scale_factor : (sin(sinc_scale_factor * pre_sinc) / pre_sinc))); } } } void SincResampler::Resample(size_t frames, float* destination) { size_t remaining_frames = frames; // Step (1) -- Prime the input buffer at the start of the input stream. if (!buffer_primed_ && remaining_frames) { read_cb_->Run(request_frames_, r0_); buffer_primed_ = true; } // Step (2) -- Resample! const what we can outside of the loop for speed. It // actually has an impact on ARM performance. See inner loop comment below. const double current_io_ratio = io_sample_rate_ratio_; const float* const kernel_ptr = kernel_storage_.get(); while (remaining_frames) { // |i| may be negative if the last Resample() call ended on an iteration // that put |virtual_source_idx_| over the limit. // // Note: The loop construct here can severely impact performance on ARM // or when built with clang. See https://codereview.chromium.org/18566009/ for (int i = static_cast( ceil((block_size_ - virtual_source_idx_) / current_io_ratio)); i > 0; --i) { RTC_DCHECK_LT(virtual_source_idx_, block_size_); // |virtual_source_idx_| lies in between two kernel offsets so figure out // what they are. const int source_idx = static_cast(virtual_source_idx_); const double subsample_remainder = virtual_source_idx_ - source_idx; const double virtual_offset_idx = subsample_remainder * kKernelOffsetCount; const int offset_idx = static_cast(virtual_offset_idx); // We'll compute "convolutions" for the two kernels which straddle // |virtual_source_idx_|. const float* const k1 = kernel_ptr + offset_idx * kKernelSize; const float* const k2 = k1 + kKernelSize; // Ensure |k1|, |k2| are 32-byte aligned for SIMD usage. Should always be // true so long as kKernelSize is a multiple of 32. RTC_DCHECK_EQ(0, reinterpret_cast(k1) % 32); RTC_DCHECK_EQ(0, reinterpret_cast(k2) % 32); // Initialize input pointer based on quantized |virtual_source_idx_|. const float* const input_ptr = r1_ + source_idx; // Figure out how much to weight each kernel's "convolution". const double kernel_interpolation_factor = virtual_offset_idx - offset_idx; *destination++ = convolve_proc_(input_ptr, k1, k2, kernel_interpolation_factor); // Advance the virtual index. virtual_source_idx_ += current_io_ratio; if (!--remaining_frames) return; } // Wrap back around to the start. virtual_source_idx_ -= block_size_; // Step (3) -- Copy r3_, r4_ to r1_, r2_. // This wraps the last input frames back to the start of the buffer. memcpy(r1_, r3_, sizeof(*input_buffer_.get()) * kKernelSize); // Step (4) -- Reinitialize regions if necessary. if (r0_ == r2_) UpdateRegions(true); // Step (5) -- Refresh the buffer with more input. read_cb_->Run(request_frames_, r0_); } } #undef CONVOLVE_FUNC size_t SincResampler::ChunkSize() const { return static_cast(block_size_ / io_sample_rate_ratio_); } void SincResampler::Flush() { virtual_source_idx_ = 0; buffer_primed_ = false; memset(input_buffer_.get(), 0, sizeof(*input_buffer_.get()) * input_buffer_size_); UpdateRegions(false); } float SincResampler::Convolve_C(const float* input_ptr, const float* k1, const float* k2, double kernel_interpolation_factor) { float sum1 = 0; float sum2 = 0; // Generate a single output sample. Unrolling this loop hurt performance in // local testing. size_t n = kKernelSize; while (n--) { sum1 += *input_ptr * *k1++; sum2 += *input_ptr++ * *k2++; } // Linearly interpolate the two "convolutions". return static_cast((1.0 - kernel_interpolation_factor) * sum1 + kernel_interpolation_factor * sum2); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/resampler/sinc_resampler.h0000664000175000017500000001574314475643423026010 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Modified from the Chromium original here: // src/media/base/sinc_resampler.h #ifndef COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_ #define COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_ #include #include #include "rtc_base/constructor_magic.h" #include "rtc_base/gtest_prod_util.h" #include "rtc_base/memory/aligned_malloc.h" #include "rtc_base/system/arch.h" namespace webrtc { // Callback class for providing more data into the resampler. Expects |frames| // of data to be rendered into |destination|; zero padded if not enough frames // are available to satisfy the request. class SincResamplerCallback { public: virtual ~SincResamplerCallback() {} virtual void Run(size_t frames, float* destination) = 0; }; // SincResampler is a high-quality single-channel sample-rate converter. class SincResampler { public: // The kernel size can be adjusted for quality (higher is better) at the // expense of performance. Must be a multiple of 32. // TODO(dalecurtis): Test performance to see if we can jack this up to 64+. static const size_t kKernelSize = 32; // Default request size. Affects how often and for how much SincResampler // calls back for input. Must be greater than kKernelSize. static const size_t kDefaultRequestSize = 512; // The kernel offset count is used for interpolation and is the number of // sub-sample kernel shifts. Can be adjusted for quality (higher is better) // at the expense of allocating more memory. static const size_t kKernelOffsetCount = 32; static const size_t kKernelStorageSize = kKernelSize * (kKernelOffsetCount + 1); // Constructs a SincResampler with the specified |read_cb|, which is used to // acquire audio data for resampling. |io_sample_rate_ratio| is the ratio // of input / output sample rates. |request_frames| controls the size in // frames of the buffer requested by each |read_cb| call. The value must be // greater than kKernelSize. Specify kDefaultRequestSize if there are no // request size constraints. SincResampler(double io_sample_rate_ratio, size_t request_frames, SincResamplerCallback* read_cb); virtual ~SincResampler(); // Resample |frames| of data from |read_cb_| into |destination|. void Resample(size_t frames, float* destination); // The maximum size in frames that guarantees Resample() will only make a // single call to |read_cb_| for more data. size_t ChunkSize() const; size_t request_frames() const { return request_frames_; } // Flush all buffered data and reset internal indices. Not thread safe, do // not call while Resample() is in progress. void Flush(); // Update |io_sample_rate_ratio_|. SetRatio() will cause a reconstruction of // the kernels used for resampling. Not thread safe, do not call while // Resample() is in progress. // // TODO(ajm): Use this in PushSincResampler rather than reconstructing // SincResampler. We would also need a way to update |request_frames_|. void SetRatio(double io_sample_rate_ratio); float* get_kernel_for_testing() { return kernel_storage_.get(); } private: FRIEND_TEST_ALL_PREFIXES(SincResamplerTest, Convolve); FRIEND_TEST_ALL_PREFIXES(SincResamplerTest, ConvolveBenchmark); void InitializeKernel(); void UpdateRegions(bool second_load); // Selects runtime specific CPU features like SSE. Must be called before // using SincResampler. // TODO(ajm): Currently managed by the class internally. See the note with // |convolve_proc_| below. void InitializeCPUSpecificFeatures(); // Compute convolution of |k1| and |k2| over |input_ptr|, resultant sums are // linearly interpolated using |kernel_interpolation_factor|. On x86 and ARM // the underlying implementation is chosen at run time. static float Convolve_C(const float* input_ptr, const float* k1, const float* k2, double kernel_interpolation_factor); #if defined(WEBRTC_ARCH_X86_FAMILY) static float Convolve_SSE(const float* input_ptr, const float* k1, const float* k2, double kernel_interpolation_factor); static float Convolve_AVX2(const float* input_ptr, const float* k1, const float* k2, double kernel_interpolation_factor); #elif defined(WEBRTC_HAS_NEON) static float Convolve_NEON(const float* input_ptr, const float* k1, const float* k2, double kernel_interpolation_factor); #endif // The ratio of input / output sample rates. double io_sample_rate_ratio_; // An index on the source input buffer with sub-sample precision. It must be // double precision to avoid drift. double virtual_source_idx_; // The buffer is primed once at the very beginning of processing. bool buffer_primed_; // Source of data for resampling. SincResamplerCallback* read_cb_; // The size (in samples) to request from each |read_cb_| execution. const size_t request_frames_; // The number of source frames processed per pass. size_t block_size_; // The size (in samples) of the internal buffer used by the resampler. const size_t input_buffer_size_; // Contains kKernelOffsetCount kernels back-to-back, each of size kKernelSize. // The kernel offsets are sub-sample shifts of a windowed sinc shifted from // 0.0 to 1.0 sample. std::unique_ptr kernel_storage_; std::unique_ptr kernel_pre_sinc_storage_; std::unique_ptr kernel_window_storage_; // Data from the source is copied into this buffer for each processing pass. std::unique_ptr input_buffer_; // Stores the runtime selection of which Convolve function to use. // TODO(ajm): Move to using a global static which must only be initialized // once by the user. We're not doing this initially, because we don't have // e.g. a LazyInstance helper in webrtc. typedef float (*ConvolveProc)(const float*, const float*, const float*, double); ConvolveProc convolve_proc_; // Pointers to the various regions inside |input_buffer_|. See the diagram at // the top of the .cc file for more information. float* r0_; float* const r1_; float* const r2_; float* r3_; float* r4_; RTC_DISALLOW_COPY_AND_ASSIGN(SincResampler); }; } // namespace webrtc #endif // COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/resampler/sinc_resampler_avx2.cc0000664000175000017500000000500214475643423027071 0ustar00arunarun/* * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include #include #include #include #include "common_audio/resampler/sinc_resampler.h" namespace webrtc { float SincResampler::Convolve_AVX2(const float* input_ptr, const float* k1, const float* k2, double kernel_interpolation_factor) { __m256 m_input; __m256 m_sums1 = _mm256_setzero_ps(); __m256 m_sums2 = _mm256_setzero_ps(); // Based on |input_ptr| alignment, we need to use loadu or load. Unrolling // these loops has not been tested or benchmarked. bool aligned_input = (reinterpret_cast(input_ptr) & 0x1F) == 0; if (!aligned_input) { for (size_t i = 0; i < kKernelSize; i += 8) { m_input = _mm256_loadu_ps(input_ptr + i); m_sums1 = _mm256_fmadd_ps(m_input, _mm256_load_ps(k1 + i), m_sums1); m_sums2 = _mm256_fmadd_ps(m_input, _mm256_load_ps(k2 + i), m_sums2); } } else { for (size_t i = 0; i < kKernelSize; i += 8) { m_input = _mm256_load_ps(input_ptr + i); m_sums1 = _mm256_fmadd_ps(m_input, _mm256_load_ps(k1 + i), m_sums1); m_sums2 = _mm256_fmadd_ps(m_input, _mm256_load_ps(k2 + i), m_sums2); } } // Linearly interpolate the two "convolutions". __m128 m128_sums1 = _mm_add_ps(_mm256_extractf128_ps(m_sums1, 0), _mm256_extractf128_ps(m_sums1, 1)); __m128 m128_sums2 = _mm_add_ps(_mm256_extractf128_ps(m_sums2, 0), _mm256_extractf128_ps(m_sums2, 1)); m128_sums1 = _mm_mul_ps( m128_sums1, _mm_set_ps1(static_cast(1.0 - kernel_interpolation_factor))); m128_sums2 = _mm_mul_ps( m128_sums2, _mm_set_ps1(static_cast(kernel_interpolation_factor))); m128_sums1 = _mm_add_ps(m128_sums1, m128_sums2); // Sum components together. float result; m128_sums2 = _mm_add_ps(_mm_movehl_ps(m128_sums1, m128_sums1), m128_sums1); _mm_store_ss(&result, _mm_add_ss(m128_sums2, _mm_shuffle_ps(m128_sums2, m128_sums2, 1))); return result; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/resampler/sinc_resampler_neon.cc0000664000175000017500000000310414475643423027151 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Modified from the Chromium original: // src/media/base/sinc_resampler.cc #include #include "common_audio/resampler/sinc_resampler.h" namespace webrtc { float SincResampler::Convolve_NEON(const float* input_ptr, const float* k1, const float* k2, double kernel_interpolation_factor) { float32x4_t m_input; float32x4_t m_sums1 = vmovq_n_f32(0); float32x4_t m_sums2 = vmovq_n_f32(0); const float* upper = input_ptr + kKernelSize; for (; input_ptr < upper;) { m_input = vld1q_f32(input_ptr); input_ptr += 4; m_sums1 = vmlaq_f32(m_sums1, m_input, vld1q_f32(k1)); k1 += 4; m_sums2 = vmlaq_f32(m_sums2, m_input, vld1q_f32(k2)); k2 += 4; } // Linearly interpolate the two "convolutions". m_sums1 = vmlaq_f32( vmulq_f32(m_sums1, vmovq_n_f32(1.0 - kernel_interpolation_factor)), m_sums2, vmovq_n_f32(kernel_interpolation_factor)); // Sum components together. float32x2_t m_half = vadd_f32(vget_high_f32(m_sums1), vget_low_f32(m_sums1)); return vget_lane_f32(vpadd_f32(m_half, m_half), 0); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/resampler/sinc_resampler_sse.cc0000664000175000017500000000430214475643423027005 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Modified from the Chromium original: // src/media/base/simd/sinc_resampler_sse.cc #include #include #include #include "common_audio/resampler/sinc_resampler.h" namespace webrtc { float SincResampler::Convolve_SSE(const float* input_ptr, const float* k1, const float* k2, double kernel_interpolation_factor) { __m128 m_input; __m128 m_sums1 = _mm_setzero_ps(); __m128 m_sums2 = _mm_setzero_ps(); // Based on |input_ptr| alignment, we need to use loadu or load. Unrolling // these loops hurt performance in local testing. if (reinterpret_cast(input_ptr) & 0x0F) { for (size_t i = 0; i < kKernelSize; i += 4) { m_input = _mm_loadu_ps(input_ptr + i); m_sums1 = _mm_add_ps(m_sums1, _mm_mul_ps(m_input, _mm_load_ps(k1 + i))); m_sums2 = _mm_add_ps(m_sums2, _mm_mul_ps(m_input, _mm_load_ps(k2 + i))); } } else { for (size_t i = 0; i < kKernelSize; i += 4) { m_input = _mm_load_ps(input_ptr + i); m_sums1 = _mm_add_ps(m_sums1, _mm_mul_ps(m_input, _mm_load_ps(k1 + i))); m_sums2 = _mm_add_ps(m_sums2, _mm_mul_ps(m_input, _mm_load_ps(k2 + i))); } } // Linearly interpolate the two "convolutions". m_sums1 = _mm_mul_ps( m_sums1, _mm_set_ps1(static_cast(1.0 - kernel_interpolation_factor))); m_sums2 = _mm_mul_ps( m_sums2, _mm_set_ps1(static_cast(kernel_interpolation_factor))); m_sums1 = _mm_add_ps(m_sums1, m_sums2); // Sum components together. float result; m_sums2 = _mm_add_ps(_mm_movehl_ps(m_sums1, m_sums1), m_sums1); _mm_store_ss(&result, _mm_add_ss(m_sums2, _mm_shuffle_ps(m_sums2, m_sums2, 1))); return result; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.cc0000664000175000017500000000403014475643423031374 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // MSVC++ requires this to be set before any other includes to get M_PI. #define _USE_MATH_DEFINES #include "common_audio/resampler/sinusoidal_linear_chirp_source.h" #include namespace webrtc { SinusoidalLinearChirpSource::SinusoidalLinearChirpSource(int sample_rate, size_t samples, double max_frequency, double delay_samples) : sample_rate_(sample_rate), total_samples_(samples), max_frequency_(max_frequency), current_index_(0), delay_samples_(delay_samples) { // Chirp rate. double duration = static_cast(total_samples_) / sample_rate_; k_ = (max_frequency_ - kMinFrequency) / duration; } void SinusoidalLinearChirpSource::Run(size_t frames, float* destination) { for (size_t i = 0; i < frames; ++i, ++current_index_) { // Filter out frequencies higher than Nyquist. if (Frequency(current_index_) > 0.5 * sample_rate_) { destination[i] = 0; } else { // Calculate time in seconds. if (current_index_ < delay_samples_) { destination[i] = 0; } else { // Sinusoidal linear chirp. double t = (current_index_ - delay_samples_) / sample_rate_; destination[i] = sin(2 * M_PI * (kMinFrequency * t + (k_ / 2) * t * t)); } } } } double SinusoidalLinearChirpSource::Frequency(size_t position) { return kMinFrequency + (position - delay_samples_) * (max_frequency_ - kMinFrequency) / total_samples_; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h0000664000175000017500000000351514475643423031245 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Modified from the Chromium original here: // src/media/base/sinc_resampler_unittest.cc #ifndef COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_ #define COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_ #include "common_audio/resampler/sinc_resampler.h" #include "rtc_base/constructor_magic.h" namespace webrtc { // Fake audio source for testing the resampler. Generates a sinusoidal linear // chirp (http://en.wikipedia.org/wiki/Chirp) which can be tuned to stress the // resampler for the specific sample rate conversion being used. class SinusoidalLinearChirpSource : public SincResamplerCallback { public: // |delay_samples| can be used to insert a fractional sample delay into the // source. It will produce zeros until non-negative time is reached. SinusoidalLinearChirpSource(int sample_rate, size_t samples, double max_frequency, double delay_samples); ~SinusoidalLinearChirpSource() override {} void Run(size_t frames, float* destination) override; double Frequency(size_t position); private: enum { kMinFrequency = 5 }; int sample_rate_; size_t total_samples_; double max_frequency_; double k_; size_t current_index_; double delay_samples_; RTC_DISALLOW_COPY_AND_ASSIGN(SinusoidalLinearChirpSource); }; } // namespace webrtc #endif // COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/ring_buffer.c0000664000175000017500000001527714475643423023275 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // A ring buffer to hold arbitrary data. Provides no thread safety. Unless // otherwise specified, functions return 0 on success and -1 on error. #include "common_audio/ring_buffer.h" #include // size_t #include #include // Get address of region(s) from which we can read data. // If the region is contiguous, |data_ptr_bytes_2| will be zero. // If non-contiguous, |data_ptr_bytes_2| will be the size in bytes of the second // region. Returns room available to be read or |element_count|, whichever is // smaller. static size_t GetBufferReadRegions(RingBuffer* buf, size_t element_count, void** data_ptr_1, size_t* data_ptr_bytes_1, void** data_ptr_2, size_t* data_ptr_bytes_2) { const size_t readable_elements = WebRtc_available_read(buf); const size_t read_elements = (readable_elements < element_count ? readable_elements : element_count); const size_t margin = buf->element_count - buf->read_pos; // Check to see if read is not contiguous. if (read_elements > margin) { // Write data in two blocks that wrap the buffer. *data_ptr_1 = buf->data + buf->read_pos * buf->element_size; *data_ptr_bytes_1 = margin * buf->element_size; *data_ptr_2 = buf->data; *data_ptr_bytes_2 = (read_elements - margin) * buf->element_size; } else { *data_ptr_1 = buf->data + buf->read_pos * buf->element_size; *data_ptr_bytes_1 = read_elements * buf->element_size; *data_ptr_2 = NULL; *data_ptr_bytes_2 = 0; } return read_elements; } RingBuffer* WebRtc_CreateBuffer(size_t element_count, size_t element_size) { RingBuffer* self = NULL; if (element_count == 0 || element_size == 0) { return NULL; } self = malloc(sizeof(RingBuffer)); if (!self) { return NULL; } self->data = malloc(element_count * element_size); if (!self->data) { free(self); self = NULL; return NULL; } self->element_count = element_count; self->element_size = element_size; WebRtc_InitBuffer(self); return self; } void WebRtc_InitBuffer(RingBuffer* self) { self->read_pos = 0; self->write_pos = 0; self->rw_wrap = SAME_WRAP; // Initialize buffer to zeros memset(self->data, 0, self->element_count * self->element_size); } void WebRtc_FreeBuffer(void* handle) { RingBuffer* self = (RingBuffer*)handle; if (!self) { return; } free(self->data); free(self); } size_t WebRtc_ReadBuffer(RingBuffer* self, void** data_ptr, void* data, size_t element_count) { if (self == NULL) { return 0; } if (data == NULL) { return 0; } { void* buf_ptr_1 = NULL; void* buf_ptr_2 = NULL; size_t buf_ptr_bytes_1 = 0; size_t buf_ptr_bytes_2 = 0; const size_t read_count = GetBufferReadRegions(self, element_count, &buf_ptr_1, &buf_ptr_bytes_1, &buf_ptr_2, &buf_ptr_bytes_2); if (buf_ptr_bytes_2 > 0) { // We have a wrap around when reading the buffer. Copy the buffer data to // |data| and point to it. memcpy(data, buf_ptr_1, buf_ptr_bytes_1); memcpy(((char*) data) + buf_ptr_bytes_1, buf_ptr_2, buf_ptr_bytes_2); buf_ptr_1 = data; } else if (!data_ptr) { // No wrap, but a memcpy was requested. memcpy(data, buf_ptr_1, buf_ptr_bytes_1); } if (data_ptr) { // |buf_ptr_1| == |data| in the case of a wrap. *data_ptr = read_count == 0 ? NULL : buf_ptr_1; } // Update read position WebRtc_MoveReadPtr(self, (int) read_count); return read_count; } } size_t WebRtc_WriteBuffer(RingBuffer* self, const void* data, size_t element_count) { if (!self) { return 0; } if (!data) { return 0; } { const size_t free_elements = WebRtc_available_write(self); const size_t write_elements = (free_elements < element_count ? free_elements : element_count); size_t n = write_elements; const size_t margin = self->element_count - self->write_pos; if (write_elements > margin) { // Buffer wrap around when writing. memcpy(self->data + self->write_pos * self->element_size, data, margin * self->element_size); self->write_pos = 0; n -= margin; self->rw_wrap = DIFF_WRAP; } memcpy(self->data + self->write_pos * self->element_size, ((const char*) data) + ((write_elements - n) * self->element_size), n * self->element_size); self->write_pos += n; return write_elements; } } int WebRtc_MoveReadPtr(RingBuffer* self, int element_count) { if (!self) { return 0; } { // We need to be able to take care of negative changes, hence use "int" // instead of "size_t". const int free_elements = (int) WebRtc_available_write(self); const int readable_elements = (int) WebRtc_available_read(self); int read_pos = (int) self->read_pos; if (element_count > readable_elements) { element_count = readable_elements; } if (element_count < -free_elements) { element_count = -free_elements; } read_pos += element_count; if (read_pos > (int) self->element_count) { // Buffer wrap around. Restart read position and wrap indicator. read_pos -= (int) self->element_count; self->rw_wrap = SAME_WRAP; } if (read_pos < 0) { // Buffer wrap around. Restart read position and wrap indicator. read_pos += (int) self->element_count; self->rw_wrap = DIFF_WRAP; } self->read_pos = (size_t) read_pos; return element_count; } } size_t WebRtc_available_read(const RingBuffer* self) { if (!self) { return 0; } if (self->rw_wrap == SAME_WRAP) { return self->write_pos - self->read_pos; } else { return self->element_count - self->read_pos + self->write_pos; } } size_t WebRtc_available_write(const RingBuffer* self) { if (!self) { return 0; } return self->element_count - WebRtc_available_read(self); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/ring_buffer.h0000664000175000017500000000556314475643423023277 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // A ring buffer to hold arbitrary data. Provides no thread safety. Unless // otherwise specified, functions return 0 on success and -1 on error. #ifndef COMMON_AUDIO_RING_BUFFER_H_ #define COMMON_AUDIO_RING_BUFFER_H_ // TODO(alessiob): Used by AEC, AECm and AudioRingBuffer. Remove when possible. #ifdef __cplusplus extern "C" { #endif #include // size_t enum Wrap { SAME_WRAP, DIFF_WRAP }; typedef struct RingBuffer { size_t read_pos; size_t write_pos; size_t element_count; size_t element_size; enum Wrap rw_wrap; char* data; } RingBuffer; // Creates and initializes the buffer. Returns null on failure. RingBuffer* WebRtc_CreateBuffer(size_t element_count, size_t element_size); void WebRtc_InitBuffer(RingBuffer* handle); void WebRtc_FreeBuffer(void* handle); // Reads data from the buffer. Returns the number of elements that were read. // The |data_ptr| will point to the address where the read data is located. // If no data can be read, |data_ptr| is set to |NULL|. If all data can be read // without buffer wrap around then |data_ptr| will point to the location in the // buffer. Otherwise, the data will be copied to |data| (memory allocation done // by the user) and |data_ptr| points to the address of |data|. |data_ptr| is // only guaranteed to be valid until the next call to WebRtc_WriteBuffer(). // // To force a copying to |data|, pass a null |data_ptr|. // // Returns number of elements read. size_t WebRtc_ReadBuffer(RingBuffer* handle, void** data_ptr, void* data, size_t element_count); // Writes |data| to buffer and returns the number of elements written. size_t WebRtc_WriteBuffer(RingBuffer* handle, const void* data, size_t element_count); // Moves the buffer read position and returns the number of elements moved. // Positive |element_count| moves the read position towards the write position, // that is, flushing the buffer. Negative |element_count| moves the read // position away from the the write position, that is, stuffing the buffer. // Returns number of elements moved. int WebRtc_MoveReadPtr(RingBuffer* handle, int element_count); // Returns number of available elements to read. size_t WebRtc_available_read(const RingBuffer* handle); // Returns number of available elements for write. size_t WebRtc_available_write(const RingBuffer* handle); #ifdef __cplusplus } #endif #endif // COMMON_AUDIO_RING_BUFFER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/0000775000175000017500000000000014475643423024336 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c0000664000175000017500000000545314475643423031214 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the function WebRtcSpl_AutoCorrToReflCoef(). * The description header can be found in signal_processing_library.h * */ #include "common_audio/signal_processing/include/signal_processing_library.h" void WebRtcSpl_AutoCorrToReflCoef(const int32_t *R, int use_order, int16_t *K) { int i, n; int16_t tmp; const int32_t *rptr; int32_t L_num, L_den; int16_t *acfptr, *pptr, *wptr, *p1ptr, *w1ptr, ACF[WEBRTC_SPL_MAX_LPC_ORDER], P[WEBRTC_SPL_MAX_LPC_ORDER], W[WEBRTC_SPL_MAX_LPC_ORDER]; // Initialize loop and pointers. acfptr = ACF; rptr = R; pptr = P; p1ptr = &P[1]; w1ptr = &W[1]; wptr = w1ptr; // First loop; n=0. Determine shifting. tmp = WebRtcSpl_NormW32(*R); *acfptr = (int16_t)((*rptr++ << tmp) >> 16); *pptr++ = *acfptr++; // Initialize ACF, P and W. for (i = 1; i <= use_order; i++) { *acfptr = (int16_t)((*rptr++ << tmp) >> 16); *wptr++ = *acfptr; *pptr++ = *acfptr++; } // Compute reflection coefficients. for (n = 1; n <= use_order; n++, K++) { tmp = WEBRTC_SPL_ABS_W16(*p1ptr); if (*P < tmp) { for (i = n; i <= use_order; i++) *K++ = 0; return; } // Division: WebRtcSpl_div(tmp, *P) *K = 0; if (tmp != 0) { L_num = tmp; L_den = *P; i = 15; while (i--) { (*K) <<= 1; L_num <<= 1; if (L_num >= L_den) { L_num -= L_den; (*K)++; } } if (*p1ptr > 0) *K = -*K; } // Last iteration; don't do Schur recursion. if (n == use_order) return; // Schur recursion. pptr = P; wptr = w1ptr; tmp = (int16_t)(((int32_t)*p1ptr * (int32_t)*K + 16384) >> 15); *pptr = WebRtcSpl_AddSatW16(*pptr, tmp); pptr++; for (i = 1; i <= use_order - n; i++) { tmp = (int16_t)(((int32_t)*wptr * (int32_t)*K + 16384) >> 15); *pptr = WebRtcSpl_AddSatW16(*(pptr + 1), tmp); pptr++; tmp = (int16_t)(((int32_t)*pptr * (int32_t)*K + 16384) >> 15); *wptr = WebRtcSpl_AddSatW16(*wptr, tmp); wptr++; } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/auto_correlation.c0000664000175000017500000000420114475643423030050 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/signal_processing/include/signal_processing_library.h" #include "rtc_base/checks.h" size_t WebRtcSpl_AutoCorrelation(const int16_t* in_vector, size_t in_vector_length, size_t order, int32_t* result, int* scale) { int32_t sum = 0; size_t i = 0, j = 0; int16_t smax = 0; int scaling = 0; RTC_DCHECK_LE(order, in_vector_length); // Find the maximum absolute value of the samples. smax = WebRtcSpl_MaxAbsValueW16(in_vector, in_vector_length); // In order to avoid overflow when computing the sum we should scale the // samples so that (in_vector_length * smax * smax) will not overflow. if (smax == 0) { scaling = 0; } else { // Number of bits in the sum loop. int nbits = WebRtcSpl_GetSizeInBits((uint32_t)in_vector_length); // Number of bits to normalize smax. int t = WebRtcSpl_NormW32(WEBRTC_SPL_MUL(smax, smax)); if (t > nbits) { scaling = 0; } else { scaling = nbits - t; } } // Perform the actual correlation calculation. for (i = 0; i < order + 1; i++) { sum = 0; /* Unroll the loop to improve performance. */ for (j = 0; i + j + 3 < in_vector_length; j += 4) { sum += (in_vector[j + 0] * in_vector[i + j + 0]) >> scaling; sum += (in_vector[j + 1] * in_vector[i + j + 1]) >> scaling; sum += (in_vector[j + 2] * in_vector[i + j + 2]) >> scaling; sum += (in_vector[j + 3] * in_vector[i + j + 3]) >> scaling; } for (; j < in_vector_length - i; j++) { sum += (in_vector[j] * in_vector[i + j]) >> scaling; } *result++ = sum; } *scale = scaling; return order + 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/complex_bit_reverse.c0000664000175000017500000001043614475643423030546 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/signal_processing/include/signal_processing_library.h" /* Tables for data buffer indexes that are bit reversed and thus need to be * swapped. Note that, index_7[{0, 2, 4, ...}] are for the left side of the swap * operations, while index_7[{1, 3, 5, ...}] are for the right side of the * operation. Same for index_8. */ /* Indexes for the case of stages == 7. */ static const int16_t index_7[112] = { 1, 64, 2, 32, 3, 96, 4, 16, 5, 80, 6, 48, 7, 112, 9, 72, 10, 40, 11, 104, 12, 24, 13, 88, 14, 56, 15, 120, 17, 68, 18, 36, 19, 100, 21, 84, 22, 52, 23, 116, 25, 76, 26, 44, 27, 108, 29, 92, 30, 60, 31, 124, 33, 66, 35, 98, 37, 82, 38, 50, 39, 114, 41, 74, 43, 106, 45, 90, 46, 58, 47, 122, 49, 70, 51, 102, 53, 86, 55, 118, 57, 78, 59, 110, 61, 94, 63, 126, 67, 97, 69, 81, 71, 113, 75, 105, 77, 89, 79, 121, 83, 101, 87, 117, 91, 109, 95, 125, 103, 115, 111, 123 }; /* Indexes for the case of stages == 8. */ static const int16_t index_8[240] = { 1, 128, 2, 64, 3, 192, 4, 32, 5, 160, 6, 96, 7, 224, 8, 16, 9, 144, 10, 80, 11, 208, 12, 48, 13, 176, 14, 112, 15, 240, 17, 136, 18, 72, 19, 200, 20, 40, 21, 168, 22, 104, 23, 232, 25, 152, 26, 88, 27, 216, 28, 56, 29, 184, 30, 120, 31, 248, 33, 132, 34, 68, 35, 196, 37, 164, 38, 100, 39, 228, 41, 148, 42, 84, 43, 212, 44, 52, 45, 180, 46, 116, 47, 244, 49, 140, 50, 76, 51, 204, 53, 172, 54, 108, 55, 236, 57, 156, 58, 92, 59, 220, 61, 188, 62, 124, 63, 252, 65, 130, 67, 194, 69, 162, 70, 98, 71, 226, 73, 146, 74, 82, 75, 210, 77, 178, 78, 114, 79, 242, 81, 138, 83, 202, 85, 170, 86, 106, 87, 234, 89, 154, 91, 218, 93, 186, 94, 122, 95, 250, 97, 134, 99, 198, 101, 166, 103, 230, 105, 150, 107, 214, 109, 182, 110, 118, 111, 246, 113, 142, 115, 206, 117, 174, 119, 238, 121, 158, 123, 222, 125, 190, 127, 254, 131, 193, 133, 161, 135, 225, 137, 145, 139, 209, 141, 177, 143, 241, 147, 201, 149, 169, 151, 233, 155, 217, 157, 185, 159, 249, 163, 197, 167, 229, 171, 213, 173, 181, 175, 245, 179, 205, 183, 237, 187, 221, 191, 253, 199, 227, 203, 211, 207, 243, 215, 235, 223, 251, 239, 247 }; void WebRtcSpl_ComplexBitReverse(int16_t* __restrict complex_data, int stages) { /* For any specific value of stages, we know exactly the indexes that are * bit reversed. Currently (Feb. 2012) in WebRTC the only possible values of * stages are 7 and 8, so we use tables to save unnecessary iterations and * calculations for these two cases. */ if (stages == 7 || stages == 8) { int m = 0; int length = 112; const int16_t* index = index_7; if (stages == 8) { length = 240; index = index_8; } /* Decimation in time. Swap the elements with bit-reversed indexes. */ for (m = 0; m < length; m += 2) { /* We declare a int32_t* type pointer, to load both the 16-bit real * and imaginary elements from complex_data in one instruction, reducing * complexity. */ int32_t* complex_data_ptr = (int32_t*)complex_data; int32_t temp = 0; temp = complex_data_ptr[index[m]]; /* Real and imaginary */ complex_data_ptr[index[m]] = complex_data_ptr[index[m + 1]]; complex_data_ptr[index[m + 1]] = temp; } } else { int m = 0, mr = 0, l = 0; int n = 1 << stages; int nn = n - 1; /* Decimation in time - re-order data */ for (m = 1; m <= nn; ++m) { int32_t* complex_data_ptr = (int32_t*)complex_data; int32_t temp = 0; /* Find out indexes that are bit-reversed. */ l = n; do { l >>= 1; } while (l > nn - mr); mr = (mr & (l - 1)) + l; if (mr <= m) { continue; } /* Swap the elements with bit-reversed indexes. * This is similar to the loop in the stages == 7 or 8 cases. */ temp = complex_data_ptr[m]; /* Real and imaginary */ complex_data_ptr[m] = complex_data_ptr[mr]; complex_data_ptr[mr] = temp; } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/complex_bit_reverse_arm.S0000664000175000017500000001077614475643423031374 0ustar00arunarun@ @ Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. @ @ Use of this source code is governed by a BSD-style license @ that can be found in the LICENSE file in the root of the source @ tree. An additional intellectual property rights grant can be found @ in the file PATENTS. All contributing project authors may @ be found in the AUTHORS file in the root of the source tree. @ @ This file contains the function WebRtcSpl_ComplexBitReverse(), optimized @ for ARMv5 platforms. @ Reference C code is in file complex_bit_reverse.c. Bit-exact. #include "rtc_base/system/asm_defines.h" GLOBAL_FUNCTION WebRtcSpl_ComplexBitReverse .align 2 DEFINE_FUNCTION WebRtcSpl_ComplexBitReverse push {r4-r7} cmp r1, #7 adr r3, index_7 @ Table pointer. mov r4, #112 @ Number of interations. beq PRE_LOOP_STAGES_7_OR_8 cmp r1, #8 adr r3, index_8 @ Table pointer. mov r4, #240 @ Number of interations. beq PRE_LOOP_STAGES_7_OR_8 mov r3, #1 @ Initialize m. mov r1, r3, asl r1 @ n = 1 << stages; subs r6, r1, #1 @ nn = n - 1; ble END mov r5, r0 @ &complex_data mov r4, #0 @ ml LOOP_GENERIC: rsb r12, r4, r6 @ l > nn - mr mov r2, r1 @ n LOOP_SHIFT: asr r2, #1 @ l >>= 1; cmp r2, r12 bgt LOOP_SHIFT sub r12, r2, #1 and r4, r12, r4 add r4, r2 @ mr = (mr & (l - 1)) + l; cmp r4, r3 @ mr <= m ? ble UPDATE_REGISTERS mov r12, r4, asl #2 ldr r7, [r5, #4] @ complex_data[2 * m, 2 * m + 1]. @ Offset 4 due to m incrementing from 1. ldr r2, [r0, r12] @ complex_data[2 * mr, 2 * mr + 1]. str r7, [r0, r12] str r2, [r5, #4] UPDATE_REGISTERS: add r3, r3, #1 add r5, #4 cmp r3, r1 bne LOOP_GENERIC b END PRE_LOOP_STAGES_7_OR_8: add r4, r3, r4, asl #1 LOOP_STAGES_7_OR_8: ldrsh r2, [r3], #2 @ index[m] ldrsh r5, [r3], #2 @ index[m + 1] ldr r1, [r0, r2] @ complex_data[index[m], index[m] + 1] ldr r12, [r0, r5] @ complex_data[index[m + 1], index[m + 1] + 1] cmp r3, r4 str r1, [r0, r5] str r12, [r0, r2] bne LOOP_STAGES_7_OR_8 END: pop {r4-r7} bx lr @ The index tables. Note the values are doubles of the actual indexes for 16-bit @ elements, different from the generic C code. It actually provides byte offsets @ for the indexes. .align 2 index_7: @ Indexes for stages == 7. .short 4, 256, 8, 128, 12, 384, 16, 64, 20, 320, 24, 192, 28, 448, 36, 288 .short 40, 160, 44, 416, 48, 96, 52, 352, 56, 224, 60, 480, 68, 272, 72, 144 .short 76, 400, 84, 336, 88, 208, 92, 464, 100, 304, 104, 176, 108, 432, 116 .short 368, 120, 240, 124, 496, 132, 264, 140, 392, 148, 328, 152, 200, 156 .short 456, 164, 296, 172, 424, 180, 360, 184, 232, 188, 488, 196, 280, 204 .short 408, 212, 344, 220, 472, 228, 312, 236, 440, 244, 376, 252, 504, 268 .short 388, 276, 324, 284, 452, 300, 420, 308, 356, 316, 484, 332, 404, 348 .short 468, 364, 436, 380, 500, 412, 460, 444, 492 index_8: @ Indexes for stages == 8. .short 4, 512, 8, 256, 12, 768, 16, 128, 20, 640, 24, 384, 28, 896, 32, 64 .short 36, 576, 40, 320, 44, 832, 48, 192, 52, 704, 56, 448, 60, 960, 68, 544 .short 72, 288, 76, 800, 80, 160, 84, 672, 88, 416, 92, 928, 100, 608, 104 .short 352, 108, 864, 112, 224, 116, 736, 120, 480, 124, 992, 132, 528, 136 .short 272, 140, 784, 148, 656, 152, 400, 156, 912, 164, 592, 168, 336, 172 .short 848, 176, 208, 180, 720, 184, 464, 188, 976, 196, 560, 200, 304, 204 .short 816, 212, 688, 216, 432, 220, 944, 228, 624, 232, 368, 236, 880, 244 .short 752, 248, 496, 252, 1008, 260, 520, 268, 776, 276, 648, 280, 392, 284 .short 904, 292, 584, 296, 328, 300, 840, 308, 712, 312, 456, 316, 968, 324 .short 552, 332, 808, 340, 680, 344, 424, 348, 936, 356, 616, 364, 872, 372 .short 744, 376, 488, 380, 1000, 388, 536, 396, 792, 404, 664, 412, 920, 420 .short 600, 428, 856, 436, 728, 440, 472, 444, 984, 452, 568, 460, 824, 468 .short 696, 476, 952, 484, 632, 492, 888, 500, 760, 508, 1016, 524, 772, 532 .short 644, 540, 900, 548, 580, 556, 836, 564, 708, 572, 964, 588, 804, 596 .short 676, 604, 932, 620, 868, 628, 740, 636, 996, 652, 788, 668, 916, 684 .short 852, 692, 724, 700, 980, 716, 820, 732, 948, 748, 884, 764, 1012, 796 .short 908, 812, 844, 828, 972, 860, 940, 892, 1004, 956, 988 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/complex_bit_reverse_mips.c0000664000175000017500000002253414475643423031600 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/signal_processing/include/signal_processing_library.h" static int16_t coefTable_7[] = { 4, 256, 8, 128, 12, 384, 16, 64, 20, 320, 24, 192, 28, 448, 36, 288, 40, 160, 44, 416, 48, 96, 52, 352, 56, 224, 60, 480, 68, 272, 72, 144, 76, 400, 84, 336, 88, 208, 92, 464, 100, 304, 104, 176, 108, 432, 116, 368, 120, 240, 124, 496, 132, 264, 140, 392, 148, 328, 152, 200, 156, 456, 164, 296, 172, 424, 180, 360, 184, 232, 188, 488, 196, 280, 204, 408, 212, 344, 220, 472, 228, 312, 236, 440, 244, 376, 252, 504, 268, 388, 276, 324, 284, 452, 300, 420, 308, 356, 316, 484, 332, 404, 348, 468, 364, 436, 380, 500, 412, 460, 444, 492 }; static int16_t coefTable_8[] = { 4, 512, 8, 256, 12, 768, 16, 128, 20, 640, 24, 384, 28, 896, 32, 64, 36, 576, 40, 320, 44, 832, 48, 192, 52, 704, 56, 448, 60, 960, 68, 544, 72, 288, 76, 800, 80, 160, 84, 672, 88, 416, 92, 928, 100, 608, 104, 352, 108, 864, 112, 224, 116, 736, 120, 480, 124, 992, 132, 528, 136, 272, 140, 784, 148, 656, 152, 400, 156, 912, 164, 592, 168, 336, 172, 848, 176, 208, 180, 720, 184, 464, 188, 976, 196, 560, 200, 304, 204, 816, 212, 688, 216, 432, 220, 944, 228, 624, 232, 368, 236, 880, 244, 752, 248, 496, 252, 1008, 260, 520, 268, 776, 276, 648, 280, 392, 284, 904, 292, 584, 296, 328, 300, 840, 308, 712, 312, 456, 316, 968, 324, 552, 332, 808, 340, 680, 344, 424, 348, 936, 356, 616, 364, 872, 372, 744, 376, 488, 380, 1000, 388, 536, 396, 792, 404, 664, 412, 920, 420, 600, 428, 856, 436, 728, 440, 472, 444, 984, 452, 568, 460, 824, 468, 696, 476, 952, 484, 632, 492, 888, 500, 760, 508, 1016, 524, 772, 532, 644, 540, 900, 548, 580, 556, 836, 564, 708, 572, 964, 588, 804, 596, 676, 604, 932, 620, 868, 628, 740, 636, 996, 652, 788, 668, 916, 684, 852, 692, 724, 700, 980, 716, 820, 732, 948, 748, 884, 764, 1012, 796, 908, 812, 844, 828, 972, 860, 940, 892, 1004, 956, 988 }; void WebRtcSpl_ComplexBitReverse(int16_t frfi[], int stages) { int l; int16_t tr, ti; int32_t tmp1, tmp2, tmp3, tmp4; int32_t* ptr_i; int32_t* ptr_j; if (stages == 8) { int16_t* pcoeftable_8 = coefTable_8; __asm __volatile ( ".set push \n\t" ".set noreorder \n\t" "addiu %[l], $zero, 120 \n\t" "1: \n\t" "addiu %[l], %[l], -4 \n\t" "lh %[tr], 0(%[pcoeftable_8]) \n\t" "lh %[ti], 2(%[pcoeftable_8]) \n\t" "lh %[tmp3], 4(%[pcoeftable_8]) \n\t" "lh %[tmp4], 6(%[pcoeftable_8]) \n\t" "addu %[ptr_i], %[frfi], %[tr] \n\t" "addu %[ptr_j], %[frfi], %[ti] \n\t" "addu %[tr], %[frfi], %[tmp3] \n\t" "addu %[ti], %[frfi], %[tmp4] \n\t" "ulw %[tmp1], 0(%[ptr_i]) \n\t" "ulw %[tmp2], 0(%[ptr_j]) \n\t" "ulw %[tmp3], 0(%[tr]) \n\t" "ulw %[tmp4], 0(%[ti]) \n\t" "usw %[tmp1], 0(%[ptr_j]) \n\t" "usw %[tmp2], 0(%[ptr_i]) \n\t" "usw %[tmp4], 0(%[tr]) \n\t" "usw %[tmp3], 0(%[ti]) \n\t" "lh %[tmp1], 8(%[pcoeftable_8]) \n\t" "lh %[tmp2], 10(%[pcoeftable_8]) \n\t" "lh %[tr], 12(%[pcoeftable_8]) \n\t" "lh %[ti], 14(%[pcoeftable_8]) \n\t" "addu %[ptr_i], %[frfi], %[tmp1] \n\t" "addu %[ptr_j], %[frfi], %[tmp2] \n\t" "addu %[tr], %[frfi], %[tr] \n\t" "addu %[ti], %[frfi], %[ti] \n\t" "ulw %[tmp1], 0(%[ptr_i]) \n\t" "ulw %[tmp2], 0(%[ptr_j]) \n\t" "ulw %[tmp3], 0(%[tr]) \n\t" "ulw %[tmp4], 0(%[ti]) \n\t" "usw %[tmp1], 0(%[ptr_j]) \n\t" "usw %[tmp2], 0(%[ptr_i]) \n\t" "usw %[tmp4], 0(%[tr]) \n\t" "usw %[tmp3], 0(%[ti]) \n\t" "bgtz %[l], 1b \n\t" " addiu %[pcoeftable_8], %[pcoeftable_8], 16 \n\t" ".set pop \n\t" : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [ptr_i] "=&r" (ptr_i), [ptr_j] "=&r" (ptr_j), [tr] "=&r" (tr), [l] "=&r" (l), [tmp3] "=&r" (tmp3), [pcoeftable_8] "+r" (pcoeftable_8), [ti] "=&r" (ti), [tmp4] "=&r" (tmp4) : [frfi] "r" (frfi) : "memory" ); } else if (stages == 7) { int16_t* pcoeftable_7 = coefTable_7; __asm __volatile ( ".set push \n\t" ".set noreorder \n\t" "addiu %[l], $zero, 56 \n\t" "1: \n\t" "addiu %[l], %[l], -4 \n\t" "lh %[tr], 0(%[pcoeftable_7]) \n\t" "lh %[ti], 2(%[pcoeftable_7]) \n\t" "lh %[tmp3], 4(%[pcoeftable_7]) \n\t" "lh %[tmp4], 6(%[pcoeftable_7]) \n\t" "addu %[ptr_i], %[frfi], %[tr] \n\t" "addu %[ptr_j], %[frfi], %[ti] \n\t" "addu %[tr], %[frfi], %[tmp3] \n\t" "addu %[ti], %[frfi], %[tmp4] \n\t" "ulw %[tmp1], 0(%[ptr_i]) \n\t" "ulw %[tmp2], 0(%[ptr_j]) \n\t" "ulw %[tmp3], 0(%[tr]) \n\t" "ulw %[tmp4], 0(%[ti]) \n\t" "usw %[tmp1], 0(%[ptr_j]) \n\t" "usw %[tmp2], 0(%[ptr_i]) \n\t" "usw %[tmp4], 0(%[tr]) \n\t" "usw %[tmp3], 0(%[ti]) \n\t" "lh %[tmp1], 8(%[pcoeftable_7]) \n\t" "lh %[tmp2], 10(%[pcoeftable_7]) \n\t" "lh %[tr], 12(%[pcoeftable_7]) \n\t" "lh %[ti], 14(%[pcoeftable_7]) \n\t" "addu %[ptr_i], %[frfi], %[tmp1] \n\t" "addu %[ptr_j], %[frfi], %[tmp2] \n\t" "addu %[tr], %[frfi], %[tr] \n\t" "addu %[ti], %[frfi], %[ti] \n\t" "ulw %[tmp1], 0(%[ptr_i]) \n\t" "ulw %[tmp2], 0(%[ptr_j]) \n\t" "ulw %[tmp3], 0(%[tr]) \n\t" "ulw %[tmp4], 0(%[ti]) \n\t" "usw %[tmp1], 0(%[ptr_j]) \n\t" "usw %[tmp2], 0(%[ptr_i]) \n\t" "usw %[tmp4], 0(%[tr]) \n\t" "usw %[tmp3], 0(%[ti]) \n\t" "bgtz %[l], 1b \n\t" " addiu %[pcoeftable_7], %[pcoeftable_7], 16 \n\t" ".set pop \n\t" : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [ptr_i] "=&r" (ptr_i), [ptr_j] "=&r" (ptr_j), [ti] "=&r" (ti), [tr] "=&r" (tr), [l] "=&r" (l), [pcoeftable_7] "+r" (pcoeftable_7), [tmp3] "=&r" (tmp3), [tmp4] "=&r" (tmp4) : [frfi] "r" (frfi) : "memory" ); } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/complex_fft.c0000664000175000017500000002315414475643423027015 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the function WebRtcSpl_ComplexFFT(). * The description header can be found in signal_processing_library.h * */ #include "common_audio/signal_processing/complex_fft_tables.h" #include "common_audio/signal_processing/include/signal_processing_library.h" #include "rtc_base/system/arch.h" #define CFFTSFT 14 #define CFFTRND 1 #define CFFTRND2 16384 #define CIFFTSFT 14 #define CIFFTRND 1 int WebRtcSpl_ComplexFFT(int16_t frfi[], int stages, int mode) { int i, j, l, k, istep, n, m; int16_t wr, wi; int32_t tr32, ti32, qr32, qi32; /* The 1024-value is a constant given from the size of kSinTable1024[], * and should not be changed depending on the input parameter 'stages' */ n = 1 << stages; if (n > 1024) return -1; l = 1; k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change depending on the input parameter 'stages' */ if (mode == 0) { // mode==0: Low-complexity and Low-accuracy mode while (l < n) { istep = l << 1; for (m = 0; m < l; ++m) { j = m << k; /* The 256-value is a constant given as 1/4 of the size of * kSinTable1024[], and should not be changed depending on the input * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 */ wr = kSinTable1024[j + 256]; wi = -kSinTable1024[j]; for (i = m; i < n; i += istep) { j = i + l; tr32 = (wr * frfi[2 * j] - wi * frfi[2 * j + 1]) >> 15; ti32 = (wr * frfi[2 * j + 1] + wi * frfi[2 * j]) >> 15; qr32 = (int32_t)frfi[2 * i]; qi32 = (int32_t)frfi[2 * i + 1]; frfi[2 * j] = (int16_t)((qr32 - tr32) >> 1); frfi[2 * j + 1] = (int16_t)((qi32 - ti32) >> 1); frfi[2 * i] = (int16_t)((qr32 + tr32) >> 1); frfi[2 * i + 1] = (int16_t)((qi32 + ti32) >> 1); } } --k; l = istep; } } else { // mode==1: High-complexity and High-accuracy mode while (l < n) { istep = l << 1; for (m = 0; m < l; ++m) { j = m << k; /* The 256-value is a constant given as 1/4 of the size of * kSinTable1024[], and should not be changed depending on the input * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 */ wr = kSinTable1024[j + 256]; wi = -kSinTable1024[j]; #ifdef WEBRTC_ARCH_ARM_V7 int32_t wri = 0; __asm __volatile("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) : "r"((int32_t)wr), "r"((int32_t)wi)); #endif for (i = m; i < n; i += istep) { j = i + l; #ifdef WEBRTC_ARCH_ARM_V7 register int32_t frfi_r; __asm __volatile( "pkhbt %[frfi_r], %[frfi_even], %[frfi_odd]," " lsl #16\n\t" "smlsd %[tr32], %[wri], %[frfi_r], %[cfftrnd]\n\t" "smladx %[ti32], %[wri], %[frfi_r], %[cfftrnd]\n\t" :[frfi_r]"=&r"(frfi_r), [tr32]"=&r"(tr32), [ti32]"=r"(ti32) :[frfi_even]"r"((int32_t)frfi[2*j]), [frfi_odd]"r"((int32_t)frfi[2*j +1]), [wri]"r"(wri), [cfftrnd]"r"(CFFTRND)); #else tr32 = wr * frfi[2 * j] - wi * frfi[2 * j + 1] + CFFTRND; ti32 = wr * frfi[2 * j + 1] + wi * frfi[2 * j] + CFFTRND; #endif tr32 >>= 15 - CFFTSFT; ti32 >>= 15 - CFFTSFT; qr32 = ((int32_t)frfi[2 * i]) * (1 << CFFTSFT); qi32 = ((int32_t)frfi[2 * i + 1]) * (1 << CFFTSFT); frfi[2 * j] = (int16_t)( (qr32 - tr32 + CFFTRND2) >> (1 + CFFTSFT)); frfi[2 * j + 1] = (int16_t)( (qi32 - ti32 + CFFTRND2) >> (1 + CFFTSFT)); frfi[2 * i] = (int16_t)( (qr32 + tr32 + CFFTRND2) >> (1 + CFFTSFT)); frfi[2 * i + 1] = (int16_t)( (qi32 + ti32 + CFFTRND2) >> (1 + CFFTSFT)); } } --k; l = istep; } } return 0; } int WebRtcSpl_ComplexIFFT(int16_t frfi[], int stages, int mode) { size_t i, j, l, istep, n, m; int k, scale, shift; int16_t wr, wi; int32_t tr32, ti32, qr32, qi32; int32_t tmp32, round2; /* The 1024-value is a constant given from the size of kSinTable1024[], * and should not be changed depending on the input parameter 'stages' */ n = ((size_t)1) << stages; if (n > 1024) return -1; scale = 0; l = 1; k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change depending on the input parameter 'stages' */ while (l < n) { // variable scaling, depending upon data shift = 0; round2 = 8192; tmp32 = WebRtcSpl_MaxAbsValueW16(frfi, 2 * n); if (tmp32 > 13573) { shift++; scale++; round2 <<= 1; } if (tmp32 > 27146) { shift++; scale++; round2 <<= 1; } istep = l << 1; if (mode == 0) { // mode==0: Low-complexity and Low-accuracy mode for (m = 0; m < l; ++m) { j = m << k; /* The 256-value is a constant given as 1/4 of the size of * kSinTable1024[], and should not be changed depending on the input * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 */ wr = kSinTable1024[j + 256]; wi = kSinTable1024[j]; for (i = m; i < n; i += istep) { j = i + l; tr32 = (wr * frfi[2 * j] - wi * frfi[2 * j + 1]) >> 15; ti32 = (wr * frfi[2 * j + 1] + wi * frfi[2 * j]) >> 15; qr32 = (int32_t)frfi[2 * i]; qi32 = (int32_t)frfi[2 * i + 1]; frfi[2 * j] = (int16_t)((qr32 - tr32) >> shift); frfi[2 * j + 1] = (int16_t)((qi32 - ti32) >> shift); frfi[2 * i] = (int16_t)((qr32 + tr32) >> shift); frfi[2 * i + 1] = (int16_t)((qi32 + ti32) >> shift); } } } else { // mode==1: High-complexity and High-accuracy mode for (m = 0; m < l; ++m) { j = m << k; /* The 256-value is a constant given as 1/4 of the size of * kSinTable1024[], and should not be changed depending on the input * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 */ wr = kSinTable1024[j + 256]; wi = kSinTable1024[j]; #ifdef WEBRTC_ARCH_ARM_V7 int32_t wri = 0; __asm __volatile("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) : "r"((int32_t)wr), "r"((int32_t)wi)); #endif for (i = m; i < n; i += istep) { j = i + l; #ifdef WEBRTC_ARCH_ARM_V7 register int32_t frfi_r; __asm __volatile( "pkhbt %[frfi_r], %[frfi_even], %[frfi_odd], lsl #16\n\t" "smlsd %[tr32], %[wri], %[frfi_r], %[cifftrnd]\n\t" "smladx %[ti32], %[wri], %[frfi_r], %[cifftrnd]\n\t" :[frfi_r]"=&r"(frfi_r), [tr32]"=&r"(tr32), [ti32]"=r"(ti32) :[frfi_even]"r"((int32_t)frfi[2*j]), [frfi_odd]"r"((int32_t)frfi[2*j +1]), [wri]"r"(wri), [cifftrnd]"r"(CIFFTRND) ); #else tr32 = wr * frfi[2 * j] - wi * frfi[2 * j + 1] + CIFFTRND; ti32 = wr * frfi[2 * j + 1] + wi * frfi[2 * j] + CIFFTRND; #endif tr32 >>= 15 - CIFFTSFT; ti32 >>= 15 - CIFFTSFT; qr32 = ((int32_t)frfi[2 * i]) * (1 << CIFFTSFT); qi32 = ((int32_t)frfi[2 * i + 1]) * (1 << CIFFTSFT); frfi[2 * j] = (int16_t)( (qr32 - tr32 + round2) >> (shift + CIFFTSFT)); frfi[2 * j + 1] = (int16_t)( (qi32 - ti32 + round2) >> (shift + CIFFTSFT)); frfi[2 * i] = (int16_t)( (qr32 + tr32 + round2) >> (shift + CIFFTSFT)); frfi[2 * i + 1] = (int16_t)( (qi32 + ti32 + round2) >> (shift + CIFFTSFT)); } } } --k; l = istep; } return scale; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/complex_fft_mips.c0000664000175000017500000004634714475643423030056 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/signal_processing/complex_fft_tables.h" #include "common_audio/signal_processing/include/signal_processing_library.h" #define CFFTSFT 14 #define CFFTRND 1 #define CFFTRND2 16384 #define CIFFTSFT 14 #define CIFFTRND 1 int WebRtcSpl_ComplexFFT(int16_t frfi[], int stages, int mode) { int i = 0; int l = 0; int k = 0; int istep = 0; int n = 0; int m = 0; int32_t wr = 0, wi = 0; int32_t tmp1 = 0; int32_t tmp2 = 0; int32_t tmp3 = 0; int32_t tmp4 = 0; int32_t tmp5 = 0; int32_t tmp6 = 0; int32_t tmp = 0; int16_t* ptr_j = NULL; int16_t* ptr_i = NULL; n = 1 << stages; if (n > 1024) { return -1; } __asm __volatile ( ".set push \n\t" ".set noreorder \n\t" "addiu %[k], $zero, 10 \n\t" "addiu %[l], $zero, 1 \n\t" "3: \n\t" "sll %[istep], %[l], 1 \n\t" "move %[m], $zero \n\t" "sll %[tmp], %[l], 2 \n\t" "move %[i], $zero \n\t" "2: \n\t" #if defined(MIPS_DSP_R1_LE) "sllv %[tmp3], %[m], %[k] \n\t" "addiu %[tmp2], %[tmp3], 512 \n\t" "addiu %[m], %[m], 1 \n\t" "lhx %[wi], %[tmp3](%[kSinTable1024]) \n\t" "lhx %[wr], %[tmp2](%[kSinTable1024]) \n\t" #else // #if defined(MIPS_DSP_R1_LE) "sllv %[tmp3], %[m], %[k] \n\t" "addu %[ptr_j], %[tmp3], %[kSinTable1024] \n\t" "addiu %[ptr_i], %[ptr_j], 512 \n\t" "addiu %[m], %[m], 1 \n\t" "lh %[wi], 0(%[ptr_j]) \n\t" "lh %[wr], 0(%[ptr_i]) \n\t" #endif // #if defined(MIPS_DSP_R1_LE) "1: \n\t" "sll %[tmp1], %[i], 2 \n\t" "addu %[ptr_i], %[frfi], %[tmp1] \n\t" "addu %[ptr_j], %[ptr_i], %[tmp] \n\t" "lh %[tmp6], 0(%[ptr_i]) \n\t" "lh %[tmp5], 2(%[ptr_i]) \n\t" "lh %[tmp3], 0(%[ptr_j]) \n\t" "lh %[tmp4], 2(%[ptr_j]) \n\t" "addu %[i], %[i], %[istep] \n\t" #if defined(MIPS_DSP_R2_LE) "mult %[wr], %[tmp3] \n\t" "madd %[wi], %[tmp4] \n\t" "mult $ac1, %[wr], %[tmp4] \n\t" "msub $ac1, %[wi], %[tmp3] \n\t" "mflo %[tmp1] \n\t" "mflo %[tmp2], $ac1 \n\t" "sll %[tmp6], %[tmp6], 14 \n\t" "sll %[tmp5], %[tmp5], 14 \n\t" "shra_r.w %[tmp1], %[tmp1], 1 \n\t" "shra_r.w %[tmp2], %[tmp2], 1 \n\t" "subu %[tmp4], %[tmp6], %[tmp1] \n\t" "addu %[tmp1], %[tmp6], %[tmp1] \n\t" "addu %[tmp6], %[tmp5], %[tmp2] \n\t" "subu %[tmp5], %[tmp5], %[tmp2] \n\t" "shra_r.w %[tmp1], %[tmp1], 15 \n\t" "shra_r.w %[tmp6], %[tmp6], 15 \n\t" "shra_r.w %[tmp4], %[tmp4], 15 \n\t" "shra_r.w %[tmp5], %[tmp5], 15 \n\t" #else // #if defined(MIPS_DSP_R2_LE) "mul %[tmp2], %[wr], %[tmp4] \n\t" "mul %[tmp1], %[wr], %[tmp3] \n\t" "mul %[tmp4], %[wi], %[tmp4] \n\t" "mul %[tmp3], %[wi], %[tmp3] \n\t" "sll %[tmp6], %[tmp6], 14 \n\t" "sll %[tmp5], %[tmp5], 14 \n\t" "addiu %[tmp6], %[tmp6], 16384 \n\t" "addiu %[tmp5], %[tmp5], 16384 \n\t" "addu %[tmp1], %[tmp1], %[tmp4] \n\t" "subu %[tmp2], %[tmp2], %[tmp3] \n\t" "addiu %[tmp1], %[tmp1], 1 \n\t" "addiu %[tmp2], %[tmp2], 1 \n\t" "sra %[tmp1], %[tmp1], 1 \n\t" "sra %[tmp2], %[tmp2], 1 \n\t" "subu %[tmp4], %[tmp6], %[tmp1] \n\t" "addu %[tmp1], %[tmp6], %[tmp1] \n\t" "addu %[tmp6], %[tmp5], %[tmp2] \n\t" "subu %[tmp5], %[tmp5], %[tmp2] \n\t" "sra %[tmp4], %[tmp4], 15 \n\t" "sra %[tmp1], %[tmp1], 15 \n\t" "sra %[tmp6], %[tmp6], 15 \n\t" "sra %[tmp5], %[tmp5], 15 \n\t" #endif // #if defined(MIPS_DSP_R2_LE) "sh %[tmp1], 0(%[ptr_i]) \n\t" "sh %[tmp6], 2(%[ptr_i]) \n\t" "sh %[tmp4], 0(%[ptr_j]) \n\t" "blt %[i], %[n], 1b \n\t" " sh %[tmp5], 2(%[ptr_j]) \n\t" "blt %[m], %[l], 2b \n\t" " addu %[i], $zero, %[m] \n\t" "move %[l], %[istep] \n\t" "blt %[l], %[n], 3b \n\t" " addiu %[k], %[k], -1 \n\t" ".set pop \n\t" : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3), [tmp4] "=&r" (tmp4), [tmp5] "=&r" (tmp5), [tmp6] "=&r" (tmp6), [ptr_i] "=&r" (ptr_i), [i] "=&r" (i), [wi] "=&r" (wi), [wr] "=&r" (wr), [m] "=&r" (m), [istep] "=&r" (istep), [l] "=&r" (l), [k] "=&r" (k), [ptr_j] "=&r" (ptr_j), [tmp] "=&r" (tmp) : [n] "r" (n), [frfi] "r" (frfi), [kSinTable1024] "r" (kSinTable1024) : "hi", "lo", "memory" #if defined(MIPS_DSP_R2_LE) , "$ac1hi", "$ac1lo" #endif // #if defined(MIPS_DSP_R2_LE) ); return 0; } int WebRtcSpl_ComplexIFFT(int16_t frfi[], int stages, int mode) { int i = 0, l = 0, k = 0; int istep = 0, n = 0, m = 0; int scale = 0, shift = 0; int32_t wr = 0, wi = 0; int32_t tmp1 = 0, tmp2 = 0, tmp3 = 0, tmp4 = 0; int32_t tmp5 = 0, tmp6 = 0, tmp = 0, tempMax = 0, round2 = 0; int16_t* ptr_j = NULL; int16_t* ptr_i = NULL; n = 1 << stages; if (n > 1024) { return -1; } __asm __volatile ( ".set push \n\t" ".set noreorder \n\t" "addiu %[k], $zero, 10 \n\t" "addiu %[l], $zero, 1 \n\t" "move %[scale], $zero \n\t" "3: \n\t" "addiu %[shift], $zero, 14 \n\t" "addiu %[round2], $zero, 8192 \n\t" "move %[ptr_i], %[frfi] \n\t" "move %[tempMax], $zero \n\t" "addu %[i], %[n], %[n] \n\t" "5: \n\t" "lh %[tmp1], 0(%[ptr_i]) \n\t" "lh %[tmp2], 2(%[ptr_i]) \n\t" "lh %[tmp3], 4(%[ptr_i]) \n\t" "lh %[tmp4], 6(%[ptr_i]) \n\t" #if defined(MIPS_DSP_R1_LE) "absq_s.w %[tmp1], %[tmp1] \n\t" "absq_s.w %[tmp2], %[tmp2] \n\t" "absq_s.w %[tmp3], %[tmp3] \n\t" "absq_s.w %[tmp4], %[tmp4] \n\t" #else // #if defined(MIPS_DSP_R1_LE) "slt %[tmp5], %[tmp1], $zero \n\t" "subu %[tmp6], $zero, %[tmp1] \n\t" "movn %[tmp1], %[tmp6], %[tmp5] \n\t" "slt %[tmp5], %[tmp2], $zero \n\t" "subu %[tmp6], $zero, %[tmp2] \n\t" "movn %[tmp2], %[tmp6], %[tmp5] \n\t" "slt %[tmp5], %[tmp3], $zero \n\t" "subu %[tmp6], $zero, %[tmp3] \n\t" "movn %[tmp3], %[tmp6], %[tmp5] \n\t" "slt %[tmp5], %[tmp4], $zero \n\t" "subu %[tmp6], $zero, %[tmp4] \n\t" "movn %[tmp4], %[tmp6], %[tmp5] \n\t" #endif // #if defined(MIPS_DSP_R1_LE) "slt %[tmp5], %[tempMax], %[tmp1] \n\t" "movn %[tempMax], %[tmp1], %[tmp5] \n\t" "addiu %[i], %[i], -4 \n\t" "slt %[tmp5], %[tempMax], %[tmp2] \n\t" "movn %[tempMax], %[tmp2], %[tmp5] \n\t" "slt %[tmp5], %[tempMax], %[tmp3] \n\t" "movn %[tempMax], %[tmp3], %[tmp5] \n\t" "slt %[tmp5], %[tempMax], %[tmp4] \n\t" "movn %[tempMax], %[tmp4], %[tmp5] \n\t" "bgtz %[i], 5b \n\t" " addiu %[ptr_i], %[ptr_i], 8 \n\t" "addiu %[tmp1], $zero, 13573 \n\t" "addiu %[tmp2], $zero, 27146 \n\t" #if !defined(MIPS32_R2_LE) "sll %[tempMax], %[tempMax], 16 \n\t" "sra %[tempMax], %[tempMax], 16 \n\t" #else // #if !defined(MIPS32_R2_LE) "seh %[tempMax] \n\t" #endif // #if !defined(MIPS32_R2_LE) "slt %[tmp1], %[tmp1], %[tempMax] \n\t" "slt %[tmp2], %[tmp2], %[tempMax] \n\t" "addu %[tmp1], %[tmp1], %[tmp2] \n\t" "addu %[shift], %[shift], %[tmp1] \n\t" "addu %[scale], %[scale], %[tmp1] \n\t" "sllv %[round2], %[round2], %[tmp1] \n\t" "sll %[istep], %[l], 1 \n\t" "move %[m], $zero \n\t" "sll %[tmp], %[l], 2 \n\t" "2: \n\t" #if defined(MIPS_DSP_R1_LE) "sllv %[tmp3], %[m], %[k] \n\t" "addiu %[tmp2], %[tmp3], 512 \n\t" "addiu %[m], %[m], 1 \n\t" "lhx %[wi], %[tmp3](%[kSinTable1024]) \n\t" "lhx %[wr], %[tmp2](%[kSinTable1024]) \n\t" #else // #if defined(MIPS_DSP_R1_LE) "sllv %[tmp3], %[m], %[k] \n\t" "addu %[ptr_j], %[tmp3], %[kSinTable1024] \n\t" "addiu %[ptr_i], %[ptr_j], 512 \n\t" "addiu %[m], %[m], 1 \n\t" "lh %[wi], 0(%[ptr_j]) \n\t" "lh %[wr], 0(%[ptr_i]) \n\t" #endif // #if defined(MIPS_DSP_R1_LE) "1: \n\t" "sll %[tmp1], %[i], 2 \n\t" "addu %[ptr_i], %[frfi], %[tmp1] \n\t" "addu %[ptr_j], %[ptr_i], %[tmp] \n\t" "lh %[tmp3], 0(%[ptr_j]) \n\t" "lh %[tmp4], 2(%[ptr_j]) \n\t" "lh %[tmp6], 0(%[ptr_i]) \n\t" "lh %[tmp5], 2(%[ptr_i]) \n\t" "addu %[i], %[i], %[istep] \n\t" #if defined(MIPS_DSP_R2_LE) "mult %[wr], %[tmp3] \n\t" "msub %[wi], %[tmp4] \n\t" "mult $ac1, %[wr], %[tmp4] \n\t" "madd $ac1, %[wi], %[tmp3] \n\t" "mflo %[tmp1] \n\t" "mflo %[tmp2], $ac1 \n\t" "sll %[tmp6], %[tmp6], 14 \n\t" "sll %[tmp5], %[tmp5], 14 \n\t" "shra_r.w %[tmp1], %[tmp1], 1 \n\t" "shra_r.w %[tmp2], %[tmp2], 1 \n\t" "addu %[tmp6], %[tmp6], %[round2] \n\t" "addu %[tmp5], %[tmp5], %[round2] \n\t" "subu %[tmp4], %[tmp6], %[tmp1] \n\t" "addu %[tmp1], %[tmp6], %[tmp1] \n\t" "addu %[tmp6], %[tmp5], %[tmp2] \n\t" "subu %[tmp5], %[tmp5], %[tmp2] \n\t" "srav %[tmp4], %[tmp4], %[shift] \n\t" "srav %[tmp1], %[tmp1], %[shift] \n\t" "srav %[tmp6], %[tmp6], %[shift] \n\t" "srav %[tmp5], %[tmp5], %[shift] \n\t" #else // #if defined(MIPS_DSP_R2_LE) "mul %[tmp1], %[wr], %[tmp3] \n\t" "mul %[tmp2], %[wr], %[tmp4] \n\t" "mul %[tmp4], %[wi], %[tmp4] \n\t" "mul %[tmp3], %[wi], %[tmp3] \n\t" "sll %[tmp6], %[tmp6], 14 \n\t" "sll %[tmp5], %[tmp5], 14 \n\t" "sub %[tmp1], %[tmp1], %[tmp4] \n\t" "addu %[tmp2], %[tmp2], %[tmp3] \n\t" "addiu %[tmp1], %[tmp1], 1 \n\t" "addiu %[tmp2], %[tmp2], 1 \n\t" "sra %[tmp2], %[tmp2], 1 \n\t" "sra %[tmp1], %[tmp1], 1 \n\t" "addu %[tmp6], %[tmp6], %[round2] \n\t" "addu %[tmp5], %[tmp5], %[round2] \n\t" "subu %[tmp4], %[tmp6], %[tmp1] \n\t" "addu %[tmp1], %[tmp6], %[tmp1] \n\t" "addu %[tmp6], %[tmp5], %[tmp2] \n\t" "subu %[tmp5], %[tmp5], %[tmp2] \n\t" "sra %[tmp4], %[tmp4], %[shift] \n\t" "sra %[tmp1], %[tmp1], %[shift] \n\t" "sra %[tmp6], %[tmp6], %[shift] \n\t" "sra %[tmp5], %[tmp5], %[shift] \n\t" #endif // #if defined(MIPS_DSP_R2_LE) "sh %[tmp1], 0(%[ptr_i]) \n\t" "sh %[tmp6], 2(%[ptr_i]) \n\t" "sh %[tmp4], 0(%[ptr_j]) \n\t" "blt %[i], %[n], 1b \n\t" " sh %[tmp5], 2(%[ptr_j]) \n\t" "blt %[m], %[l], 2b \n\t" " addu %[i], $zero, %[m] \n\t" "move %[l], %[istep] \n\t" "blt %[l], %[n], 3b \n\t" " addiu %[k], %[k], -1 \n\t" ".set pop \n\t" : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3), [tmp4] "=&r" (tmp4), [tmp5] "=&r" (tmp5), [tmp6] "=&r" (tmp6), [ptr_i] "=&r" (ptr_i), [i] "=&r" (i), [m] "=&r" (m), [tmp] "=&r" (tmp), [istep] "=&r" (istep), [wi] "=&r" (wi), [wr] "=&r" (wr), [l] "=&r" (l), [k] "=&r" (k), [round2] "=&r" (round2), [ptr_j] "=&r" (ptr_j), [shift] "=&r" (shift), [scale] "=&r" (scale), [tempMax] "=&r" (tempMax) : [n] "r" (n), [frfi] "r" (frfi), [kSinTable1024] "r" (kSinTable1024) : "hi", "lo", "memory" #if defined(MIPS_DSP_R2_LE) , "$ac1hi", "$ac1lo" #endif // #if defined(MIPS_DSP_R2_LE) ); return scale; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/complex_fft_tables.h0000664000175000017500000002201614475643423030350 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_ #define COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_ #include static const int16_t kSinTable1024[] = { 0, 201, 402, 603, 804, 1005, 1206, 1406, 1607, 1808, 2009, 2209, 2410, 2610, 2811, 3011, 3211, 3411, 3611, 3811, 4011, 4210, 4409, 4608, 4807, 5006, 5205, 5403, 5601, 5799, 5997, 6195, 6392, 6589, 6786, 6982, 7179, 7375, 7571, 7766, 7961, 8156, 8351, 8545, 8739, 8932, 9126, 9319, 9511, 9703, 9895, 10087, 10278, 10469, 10659, 10849, 11038, 11227, 11416, 11604, 11792, 11980, 12166, 12353, 12539, 12724, 12909, 13094, 13278, 13462, 13645, 13827, 14009, 14191, 14372, 14552, 14732, 14911, 15090, 15268, 15446, 15623, 15799, 15975, 16150, 16325, 16499, 16672, 16845, 17017, 17189, 17360, 17530, 17699, 17868, 18036, 18204, 18371, 18537, 18702, 18867, 19031, 19194, 19357, 19519, 19680, 19840, 20000, 20159, 20317, 20474, 20631, 20787, 20942, 21096, 21249, 21402, 21554, 21705, 21855, 22004, 22153, 22301, 22448, 22594, 22739, 22883, 23027, 23169, 23311, 23452, 23592, 23731, 23869, 24006, 24143, 24278, 24413, 24546, 24679, 24811, 24942, 25072, 25201, 25329, 25456, 25582, 25707, 25831, 25954, 26077, 26198, 26318, 26437, 26556, 26673, 26789, 26905, 27019, 27132, 27244, 27355, 27466, 27575, 27683, 27790, 27896, 28001, 28105, 28208, 28309, 28410, 28510, 28608, 28706, 28802, 28897, 28992, 29085, 29177, 29268, 29358, 29446, 29534, 29621, 29706, 29790, 29873, 29955, 30036, 30116, 30195, 30272, 30349, 30424, 30498, 30571, 30643, 30713, 30783, 30851, 30918, 30984, 31049, 31113, 31175, 31236, 31297, 31356, 31413, 31470, 31525, 31580, 31633, 31684, 31735, 31785, 31833, 31880, 31926, 31970, 32014, 32056, 32097, 32137, 32176, 32213, 32249, 32284, 32318, 32350, 32382, 32412, 32441, 32468, 32495, 32520, 32544, 32567, 32588, 32609, 32628, 32646, 32662, 32678, 32692, 32705, 32717, 32727, 32736, 32744, 32751, 32757, 32761, 32764, 32766, 32767, 32766, 32764, 32761, 32757, 32751, 32744, 32736, 32727, 32717, 32705, 32692, 32678, 32662, 32646, 32628, 32609, 32588, 32567, 32544, 32520, 32495, 32468, 32441, 32412, 32382, 32350, 32318, 32284, 32249, 32213, 32176, 32137, 32097, 32056, 32014, 31970, 31926, 31880, 31833, 31785, 31735, 31684, 31633, 31580, 31525, 31470, 31413, 31356, 31297, 31236, 31175, 31113, 31049, 30984, 30918, 30851, 30783, 30713, 30643, 30571, 30498, 30424, 30349, 30272, 30195, 30116, 30036, 29955, 29873, 29790, 29706, 29621, 29534, 29446, 29358, 29268, 29177, 29085, 28992, 28897, 28802, 28706, 28608, 28510, 28410, 28309, 28208, 28105, 28001, 27896, 27790, 27683, 27575, 27466, 27355, 27244, 27132, 27019, 26905, 26789, 26673, 26556, 26437, 26318, 26198, 26077, 25954, 25831, 25707, 25582, 25456, 25329, 25201, 25072, 24942, 24811, 24679, 24546, 24413, 24278, 24143, 24006, 23869, 23731, 23592, 23452, 23311, 23169, 23027, 22883, 22739, 22594, 22448, 22301, 22153, 22004, 21855, 21705, 21554, 21402, 21249, 21096, 20942, 20787, 20631, 20474, 20317, 20159, 20000, 19840, 19680, 19519, 19357, 19194, 19031, 18867, 18702, 18537, 18371, 18204, 18036, 17868, 17699, 17530, 17360, 17189, 17017, 16845, 16672, 16499, 16325, 16150, 15975, 15799, 15623, 15446, 15268, 15090, 14911, 14732, 14552, 14372, 14191, 14009, 13827, 13645, 13462, 13278, 13094, 12909, 12724, 12539, 12353, 12166, 11980, 11792, 11604, 11416, 11227, 11038, 10849, 10659, 10469, 10278, 10087, 9895, 9703, 9511, 9319, 9126, 8932, 8739, 8545, 8351, 8156, 7961, 7766, 7571, 7375, 7179, 6982, 6786, 6589, 6392, 6195, 5997, 5799, 5601, 5403, 5205, 5006, 4807, 4608, 4409, 4210, 4011, 3811, 3611, 3411, 3211, 3011, 2811, 2610, 2410, 2209, 2009, 1808, 1607, 1406, 1206, 1005, 804, 603, 402, 201, 0, -201, -402, -603, -804, -1005, -1206, -1406, -1607, -1808, -2009, -2209, -2410, -2610, -2811, -3011, -3211, -3411, -3611, -3811, -4011, -4210, -4409, -4608, -4807, -5006, -5205, -5403, -5601, -5799, -5997, -6195, -6392, -6589, -6786, -6982, -7179, -7375, -7571, -7766, -7961, -8156, -8351, -8545, -8739, -8932, -9126, -9319, -9511, -9703, -9895, -10087, -10278, -10469, -10659, -10849, -11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353, -12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827, -14009, -14191, -14372, -14552, -14732, -14911, -15090, -15268, -15446, -15623, -15799, -15975, -16150, -16325, -16499, -16672, -16845, -17017, -17189, -17360, -17530, -17699, -17868, -18036, -18204, -18371, -18537, -18702, -18867, -19031, -19194, -19357, -19519, -19680, -19840, -20000, -20159, -20317, -20474, -20631, -20787, -20942, -21096, -21249, -21402, -21554, -21705, -21855, -22004, -22153, -22301, -22448, -22594, -22739, -22883, -23027, -23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143, -24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201, -25329, -25456, -25582, -25707, -25831, -25954, -26077, -26198, -26318, -26437, -26556, -26673, -26789, -26905, -27019, -27132, -27244, -27355, -27466, -27575, -27683, -27790, -27896, -28001, -28105, -28208, -28309, -28410, -28510, -28608, -28706, -28802, -28897, -28992, -29085, -29177, -29268, -29358, -29446, -29534, -29621, -29706, -29790, -29873, -29955, -30036, -30116, -30195, -30272, -30349, -30424, -30498, -30571, -30643, -30713, -30783, -30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297, -31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735, -31785, -31833, -31880, -31926, -31970, -32014, -32056, -32097, -32137, -32176, -32213, -32249, -32284, -32318, -32350, -32382, -32412, -32441, -32468, -32495, -32520, -32544, -32567, -32588, -32609, -32628, -32646, -32662, -32678, -32692, -32705, -32717, -32727, -32736, -32744, -32751, -32757, -32761, -32764, -32766, -32767, -32766, -32764, -32761, -32757, -32751, -32744, -32736, -32727, -32717, -32705, -32692, -32678, -32662, -32646, -32628, -32609, -32588, -32567, -32544, -32520, -32495, -32468, -32441, -32412, -32382, -32350, -32318, -32284, -32249, -32213, -32176, -32137, -32097, -32056, -32014, -31970, -31926, -31880, -31833, -31785, -31735, -31684, -31633, -31580, -31525, -31470, -31413, -31356, -31297, -31236, -31175, -31113, -31049, -30984, -30918, -30851, -30783, -30713, -30643, -30571, -30498, -30424, -30349, -30272, -30195, -30116, -30036, -29955, -29873, -29790, -29706, -29621, -29534, -29446, -29358, -29268, -29177, -29085, -28992, -28897, -28802, -28706, -28608, -28510, -28410, -28309, -28208, -28105, -28001, -27896, -27790, -27683, -27575, -27466, -27355, -27244, -27132, -27019, -26905, -26789, -26673, -26556, -26437, -26318, -26198, -26077, -25954, -25831, -25707, -25582, -25456, -25329, -25201, -25072, -24942, -24811, -24679, -24546, -24413, -24278, -24143, -24006, -23869, -23731, -23592, -23452, -23311, -23169, -23027, -22883, -22739, -22594, -22448, -22301, -22153, -22004, -21855, -21705, -21554, -21402, -21249, -21096, -20942, -20787, -20631, -20474, -20317, -20159, -20000, -19840, -19680, -19519, -19357, -19194, -19031, -18867, -18702, -18537, -18371, -18204, -18036, -17868, -17699, -17530, -17360, -17189, -17017, -16845, -16672, -16499, -16325, -16150, -15975, -15799, -15623, -15446, -15268, -15090, -14911, -14732, -14552, -14372, -14191, -14009, -13827, -13645, -13462, -13278, -13094, -12909, -12724, -12539, -12353, -12166, -11980, -11792, -11604, -11416, -11227, -11038, -10849, -10659, -10469, -10278, -10087, -9895, -9703, -9511, -9319, -9126, -8932, -8739, -8545, -8351, -8156, -7961, -7766, -7571, -7375, -7179, -6982, -6786, -6589, -6392, -6195, -5997, -5799, -5601, -5403, -5205, -5006, -4807, -4608, -4409, -4210, -4011, -3811, -3611, -3411, -3211, -3011, -2811, -2610, -2410, -2209, -2009, -1808, -1607, -1406, -1206, -1005, -804, -603, -402, -201}; #endif // COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/copy_set_operations.c0000664000175000017500000000406114475643423030573 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the implementation of functions * WebRtcSpl_MemSetW16() * WebRtcSpl_MemSetW32() * WebRtcSpl_MemCpyReversedOrder() * WebRtcSpl_CopyFromEndW16() * WebRtcSpl_ZerosArrayW16() * WebRtcSpl_ZerosArrayW32() * * The description header can be found in signal_processing_library.h * */ #include #include "common_audio/signal_processing/include/signal_processing_library.h" void WebRtcSpl_MemSetW16(int16_t *ptr, int16_t set_value, size_t length) { size_t j; int16_t *arrptr = ptr; for (j = length; j > 0; j--) { *arrptr++ = set_value; } } void WebRtcSpl_MemSetW32(int32_t *ptr, int32_t set_value, size_t length) { size_t j; int32_t *arrptr = ptr; for (j = length; j > 0; j--) { *arrptr++ = set_value; } } void WebRtcSpl_MemCpyReversedOrder(int16_t* dest, int16_t* source, size_t length) { size_t j; int16_t* destPtr = dest; int16_t* sourcePtr = source; for (j = 0; j < length; j++) { *destPtr-- = *sourcePtr++; } } void WebRtcSpl_CopyFromEndW16(const int16_t *vector_in, size_t length, size_t samples, int16_t *vector_out) { // Copy the last of the input vector to vector_out WEBRTC_SPL_MEMCPY_W16(vector_out, &vector_in[length - samples], samples); } void WebRtcSpl_ZerosArrayW16(int16_t *vector, size_t length) { WebRtcSpl_MemSetW16(vector, 0, length); } void WebRtcSpl_ZerosArrayW32(int32_t *vector, size_t length) { WebRtcSpl_MemSetW32(vector, 0, length); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/cross_correlation.c0000664000175000017500000000224314475643423030235 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/signal_processing/include/signal_processing_library.h" /* C version of WebRtcSpl_CrossCorrelation() for generic platforms. */ void WebRtcSpl_CrossCorrelationC(int32_t* cross_correlation, const int16_t* seq1, const int16_t* seq2, size_t dim_seq, size_t dim_cross_correlation, int right_shifts, int step_seq2) { size_t i = 0, j = 0; for (i = 0; i < dim_cross_correlation; i++) { int32_t corr = 0; for (j = 0; j < dim_seq; j++) corr += (seq1[j] * seq2[j]) >> right_shifts; seq2 += step_seq2; *cross_correlation++ = corr; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/cross_correlation_mips.c0000664000175000017500000001414014475643423031264 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/signal_processing/include/signal_processing_library.h" void WebRtcSpl_CrossCorrelation_mips(int32_t* cross_correlation, const int16_t* seq1, const int16_t* seq2, size_t dim_seq, size_t dim_cross_correlation, int right_shifts, int step_seq2) { int32_t t0 = 0, t1 = 0, t2 = 0, t3 = 0, sum = 0; int16_t *pseq2 = NULL; int16_t *pseq1 = NULL; int16_t *pseq1_0 = (int16_t*)&seq1[0]; int16_t *pseq2_0 = (int16_t*)&seq2[0]; int k = 0; __asm __volatile ( ".set push \n\t" ".set noreorder \n\t" "sll %[step_seq2], %[step_seq2], 1 \n\t" "andi %[t0], %[dim_seq], 1 \n\t" "bgtz %[t0], 3f \n\t" " nop \n\t" "1: \n\t" "move %[pseq1], %[pseq1_0] \n\t" "move %[pseq2], %[pseq2_0] \n\t" "sra %[k], %[dim_seq], 1 \n\t" "addiu %[dim_cc], %[dim_cc], -1 \n\t" "xor %[sum], %[sum], %[sum] \n\t" "2: \n\t" "lh %[t0], 0(%[pseq1]) \n\t" "lh %[t1], 0(%[pseq2]) \n\t" "lh %[t2], 2(%[pseq1]) \n\t" "lh %[t3], 2(%[pseq2]) \n\t" "mul %[t0], %[t0], %[t1] \n\t" "addiu %[k], %[k], -1 \n\t" "mul %[t2], %[t2], %[t3] \n\t" "addiu %[pseq1], %[pseq1], 4 \n\t" "addiu %[pseq2], %[pseq2], 4 \n\t" "srav %[t0], %[t0], %[right_shifts] \n\t" "addu %[sum], %[sum], %[t0] \n\t" "srav %[t2], %[t2], %[right_shifts] \n\t" "bgtz %[k], 2b \n\t" " addu %[sum], %[sum], %[t2] \n\t" "addu %[pseq2_0], %[pseq2_0], %[step_seq2] \n\t" "sw %[sum], 0(%[cc]) \n\t" "bgtz %[dim_cc], 1b \n\t" " addiu %[cc], %[cc], 4 \n\t" "b 6f \n\t" " nop \n\t" "3: \n\t" "move %[pseq1], %[pseq1_0] \n\t" "move %[pseq2], %[pseq2_0] \n\t" "sra %[k], %[dim_seq], 1 \n\t" "addiu %[dim_cc], %[dim_cc], -1 \n\t" "beqz %[k], 5f \n\t" " xor %[sum], %[sum], %[sum] \n\t" "4: \n\t" "lh %[t0], 0(%[pseq1]) \n\t" "lh %[t1], 0(%[pseq2]) \n\t" "lh %[t2], 2(%[pseq1]) \n\t" "lh %[t3], 2(%[pseq2]) \n\t" "mul %[t0], %[t0], %[t1] \n\t" "addiu %[k], %[k], -1 \n\t" "mul %[t2], %[t2], %[t3] \n\t" "addiu %[pseq1], %[pseq1], 4 \n\t" "addiu %[pseq2], %[pseq2], 4 \n\t" "srav %[t0], %[t0], %[right_shifts] \n\t" "addu %[sum], %[sum], %[t0] \n\t" "srav %[t2], %[t2], %[right_shifts] \n\t" "bgtz %[k], 4b \n\t" " addu %[sum], %[sum], %[t2] \n\t" "5: \n\t" "lh %[t0], 0(%[pseq1]) \n\t" "lh %[t1], 0(%[pseq2]) \n\t" "mul %[t0], %[t0], %[t1] \n\t" "srav %[t0], %[t0], %[right_shifts] \n\t" "addu %[sum], %[sum], %[t0] \n\t" "addu %[pseq2_0], %[pseq2_0], %[step_seq2] \n\t" "sw %[sum], 0(%[cc]) \n\t" "bgtz %[dim_cc], 3b \n\t" " addiu %[cc], %[cc], 4 \n\t" "6: \n\t" ".set pop \n\t" : [step_seq2] "+r" (step_seq2), [t0] "=&r" (t0), [t1] "=&r" (t1), [t2] "=&r" (t2), [t3] "=&r" (t3), [pseq1] "=&r" (pseq1), [pseq2] "=&r" (pseq2), [pseq1_0] "+r" (pseq1_0), [pseq2_0] "+r" (pseq2_0), [k] "=&r" (k), [dim_cc] "+r" (dim_cross_correlation), [sum] "=&r" (sum), [cc] "+r" (cross_correlation) : [dim_seq] "r" (dim_seq), [right_shifts] "r" (right_shifts) : "hi", "lo", "memory" ); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/cross_correlation_neon.c0000664000175000017500000000616514475643423031263 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/signal_processing/include/signal_processing_library.h" #include "rtc_base/system/arch.h" #include static inline void DotProductWithScaleNeon(int32_t* cross_correlation, const int16_t* vector1, const int16_t* vector2, size_t length, int scaling) { size_t i = 0; size_t len1 = length >> 3; size_t len2 = length & 7; int64x2_t sum0 = vdupq_n_s64(0); int64x2_t sum1 = vdupq_n_s64(0); for (i = len1; i > 0; i -= 1) { int16x8_t seq1_16x8 = vld1q_s16(vector1); int16x8_t seq2_16x8 = vld1q_s16(vector2); #if defined(WEBRTC_ARCH_ARM64) int32x4_t tmp0 = vmull_s16(vget_low_s16(seq1_16x8), vget_low_s16(seq2_16x8)); int32x4_t tmp1 = vmull_high_s16(seq1_16x8, seq2_16x8); #else int32x4_t tmp0 = vmull_s16(vget_low_s16(seq1_16x8), vget_low_s16(seq2_16x8)); int32x4_t tmp1 = vmull_s16(vget_high_s16(seq1_16x8), vget_high_s16(seq2_16x8)); #endif sum0 = vpadalq_s32(sum0, tmp0); sum1 = vpadalq_s32(sum1, tmp1); vector1 += 8; vector2 += 8; } // Calculate the rest of the samples. int64_t sum_res = 0; for (i = len2; i > 0; i -= 1) { sum_res += WEBRTC_SPL_MUL_16_16(*vector1, *vector2); vector1++; vector2++; } sum0 = vaddq_s64(sum0, sum1); #if defined(WEBRTC_ARCH_ARM64) int64_t sum2 = vaddvq_s64(sum0); *cross_correlation = (int32_t)((sum2 + sum_res) >> scaling); #else int64x1_t shift = vdup_n_s64(-scaling); int64x1_t sum2 = vadd_s64(vget_low_s64(sum0), vget_high_s64(sum0)); sum2 = vadd_s64(sum2, vdup_n_s64(sum_res)); sum2 = vshl_s64(sum2, shift); vst1_lane_s32(cross_correlation, vreinterpret_s32_s64(sum2), 0); #endif } /* NEON version of WebRtcSpl_CrossCorrelation() for ARM32/64 platforms. */ void WebRtcSpl_CrossCorrelationNeon(int32_t* cross_correlation, const int16_t* seq1, const int16_t* seq2, size_t dim_seq, size_t dim_cross_correlation, int right_shifts, int step_seq2) { size_t i = 0; for (i = 0; i < dim_cross_correlation; i++) { const int16_t* seq1_ptr = seq1; const int16_t* seq2_ptr = seq2 + (step_seq2 * i); DotProductWithScaleNeon(cross_correlation, seq1_ptr, seq2_ptr, dim_seq, right_shifts); cross_correlation++; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/division_operations.c0000664000175000017500000000666314475643423030604 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains implementations of the divisions * WebRtcSpl_DivU32U16() * WebRtcSpl_DivW32W16() * WebRtcSpl_DivW32W16ResW16() * WebRtcSpl_DivResultInQ31() * WebRtcSpl_DivW32HiLow() * * The description header can be found in signal_processing_library.h * */ #include "common_audio/signal_processing/include/signal_processing_library.h" #include "rtc_base/sanitizer.h" uint32_t WebRtcSpl_DivU32U16(uint32_t num, uint16_t den) { // Guard against division with 0 if (den != 0) { return (uint32_t)(num / den); } else { return (uint32_t)0xFFFFFFFF; } } int32_t WebRtcSpl_DivW32W16(int32_t num, int16_t den) { // Guard against division with 0 if (den != 0) { return (int32_t)(num / den); } else { return (int32_t)0x7FFFFFFF; } } int16_t WebRtcSpl_DivW32W16ResW16(int32_t num, int16_t den) { // Guard against division with 0 if (den != 0) { return (int16_t)(num / den); } else { return (int16_t)0x7FFF; } } int32_t WebRtcSpl_DivResultInQ31(int32_t num, int32_t den) { int32_t L_num = num; int32_t L_den = den; int32_t div = 0; int k = 31; int change_sign = 0; if (num == 0) return 0; if (num < 0) { change_sign++; L_num = -num; } if (den < 0) { change_sign++; L_den = -den; } while (k--) { div <<= 1; L_num <<= 1; if (L_num >= L_den) { L_num -= L_den; div++; } } if (change_sign == 1) { div = -div; } return div; } int32_t RTC_NO_SANITIZE("signed-integer-overflow") // bugs.webrtc.org/5486 WebRtcSpl_DivW32HiLow(int32_t num, int16_t den_hi, int16_t den_low) { int16_t approx, tmp_hi, tmp_low, num_hi, num_low; int32_t tmpW32; approx = (int16_t)WebRtcSpl_DivW32W16((int32_t)0x1FFFFFFF, den_hi); // result in Q14 (Note: 3FFFFFFF = 0.5 in Q30) // tmpW32 = 1/den = approx * (2.0 - den * approx) (in Q30) tmpW32 = (den_hi * approx << 1) + ((den_low * approx >> 15) << 1); // tmpW32 = den * approx tmpW32 = (int32_t)0x7fffffffL - tmpW32; // result in Q30 (tmpW32 = 2.0-(den*approx)) // UBSan: 2147483647 - -2 cannot be represented in type 'int' // Store tmpW32 in hi and low format tmp_hi = (int16_t)(tmpW32 >> 16); tmp_low = (int16_t)((tmpW32 - ((int32_t)tmp_hi << 16)) >> 1); // tmpW32 = 1/den in Q29 tmpW32 = (tmp_hi * approx + (tmp_low * approx >> 15)) << 1; // 1/den in hi and low format tmp_hi = (int16_t)(tmpW32 >> 16); tmp_low = (int16_t)((tmpW32 - ((int32_t)tmp_hi << 16)) >> 1); // Store num in hi and low format num_hi = (int16_t)(num >> 16); num_low = (int16_t)((num - ((int32_t)num_hi << 16)) >> 1); // num * (1/den) by 32 bit multiplication (result in Q28) tmpW32 = num_hi * tmp_hi + (num_hi * tmp_low >> 15) + (num_low * tmp_hi >> 15); // Put result in Q31 (convert from Q28) tmpW32 = WEBRTC_SPL_LSHIFT_W32(tmpW32, 3); return tmpW32; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/dot_product_with_scale.cc0000664000175000017500000000233514475643423031400 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/signal_processing/dot_product_with_scale.h" #include "rtc_base/numerics/safe_conversions.h" int32_t WebRtcSpl_DotProductWithScale(const int16_t* vector1, const int16_t* vector2, size_t length, int scaling) { int64_t sum = 0; size_t i = 0; /* Unroll the loop to improve performance. */ for (i = 0; i + 3 < length; i += 4) { sum += (vector1[i + 0] * vector2[i + 0]) >> scaling; sum += (vector1[i + 1] * vector2[i + 1]) >> scaling; sum += (vector1[i + 2] * vector2[i + 2]) >> scaling; sum += (vector1[i + 3] * vector2[i + 3]) >> scaling; } for (; i < length; i++) { sum += (vector1[i] * vector2[i]) >> scaling; } return rtc::saturated_cast(sum); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/dot_product_with_scale.h0000664000175000017500000000265314475643423031245 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_DOT_PRODUCT_WITH_SCALE_H_ #define COMMON_AUDIO_SIGNAL_PROCESSING_DOT_PRODUCT_WITH_SCALE_H_ #include #include #ifdef __cplusplus extern "C" { #endif // Calculates the dot product between two (int16_t) vectors. // // Input: // - vector1 : Vector 1 // - vector2 : Vector 2 // - vector_length : Number of samples used in the dot product // - scaling : The number of right bit shifts to apply on each term // during calculation to avoid overflow, i.e., the // output will be in Q(-|scaling|) // // Return value : The dot product in Q(-scaling) int32_t WebRtcSpl_DotProductWithScale(const int16_t* vector1, const int16_t* vector2, size_t length, int scaling); #ifdef __cplusplus } #endif // __cplusplus #endif // COMMON_AUDIO_SIGNAL_PROCESSING_DOT_PRODUCT_WITH_SCALE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/downsample_fast.c0000664000175000017500000000466614475643423027704 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/signal_processing/include/signal_processing_library.h" #include "rtc_base/checks.h" #include "rtc_base/sanitizer.h" // TODO(Bjornv): Change the function parameter order to WebRTC code style. // C version of WebRtcSpl_DownsampleFast() for generic platforms. int WebRtcSpl_DownsampleFastC(const int16_t* data_in, size_t data_in_length, int16_t* data_out, size_t data_out_length, const int16_t* __restrict coefficients, size_t coefficients_length, int factor, size_t delay) { int16_t* const original_data_out = data_out; size_t i = 0; size_t j = 0; int32_t out_s32 = 0; size_t endpos = delay + factor * (data_out_length - 1) + 1; // Return error if any of the running conditions doesn't meet. if (data_out_length == 0 || coefficients_length == 0 || data_in_length < endpos) { return -1; } rtc_MsanCheckInitialized(coefficients, sizeof(coefficients[0]), coefficients_length); for (i = delay; i < endpos; i += factor) { out_s32 = 2048; // Round value, 0.5 in Q12. for (j = 0; j < coefficients_length; j++) { // Negative overflow is permitted here, because this is // auto-regressive filters, and the state for each batch run is // stored in the "negative" positions of the output vector. rtc_MsanCheckInitialized(&data_in[(ptrdiff_t) i - (ptrdiff_t) j], sizeof(data_in[0]), 1); // out_s32 is in Q12 domain. out_s32 += coefficients[j] * data_in[(ptrdiff_t) i - (ptrdiff_t) j]; } out_s32 >>= 12; // Q0. // Saturate and store the output. *data_out++ = WebRtcSpl_SatW32ToW16(out_s32); } RTC_DCHECK_EQ(original_data_out + data_out_length, data_out); rtc_MsanCheckInitialized(original_data_out, sizeof(original_data_out[0]), data_out_length); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/downsample_fast_mips.c0000664000175000017500000002365314475643423030731 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/signal_processing/include/signal_processing_library.h" // Version of WebRtcSpl_DownsampleFast() for MIPS platforms. int WebRtcSpl_DownsampleFast_mips(const int16_t* data_in, size_t data_in_length, int16_t* data_out, size_t data_out_length, const int16_t* __restrict coefficients, size_t coefficients_length, int factor, size_t delay) { int i; int j; int k; int32_t out_s32 = 0; size_t endpos = delay + factor * (data_out_length - 1) + 1; int32_t tmp1, tmp2, tmp3, tmp4, factor_2; int16_t* p_coefficients; int16_t* p_data_in; int16_t* p_data_in_0 = (int16_t*)&data_in[delay]; int16_t* p_coefficients_0 = (int16_t*)&coefficients[0]; #if !defined(MIPS_DSP_R1_LE) int32_t max_16 = 0x7FFF; int32_t min_16 = 0xFFFF8000; #endif // #if !defined(MIPS_DSP_R1_LE) // Return error if any of the running conditions doesn't meet. if (data_out_length == 0 || coefficients_length == 0 || data_in_length < endpos) { return -1; } #if defined(MIPS_DSP_R2_LE) __asm __volatile ( ".set push \n\t" ".set noreorder \n\t" "subu %[i], %[endpos], %[delay] \n\t" "sll %[factor_2], %[factor], 1 \n\t" "1: \n\t" "move %[p_data_in], %[p_data_in_0] \n\t" "mult $zero, $zero \n\t" "move %[p_coefs], %[p_coefs_0] \n\t" "sra %[j], %[coef_length], 2 \n\t" "beq %[j], $zero, 3f \n\t" " andi %[k], %[coef_length], 3 \n\t" "2: \n\t" "lwl %[tmp1], 1(%[p_data_in]) \n\t" "lwl %[tmp2], 3(%[p_coefs]) \n\t" "lwl %[tmp3], -3(%[p_data_in]) \n\t" "lwl %[tmp4], 7(%[p_coefs]) \n\t" "lwr %[tmp1], -2(%[p_data_in]) \n\t" "lwr %[tmp2], 0(%[p_coefs]) \n\t" "lwr %[tmp3], -6(%[p_data_in]) \n\t" "lwr %[tmp4], 4(%[p_coefs]) \n\t" "packrl.ph %[tmp1], %[tmp1], %[tmp1] \n\t" "packrl.ph %[tmp3], %[tmp3], %[tmp3] \n\t" "dpa.w.ph $ac0, %[tmp1], %[tmp2] \n\t" "dpa.w.ph $ac0, %[tmp3], %[tmp4] \n\t" "addiu %[j], %[j], -1 \n\t" "addiu %[p_data_in], %[p_data_in], -8 \n\t" "bgtz %[j], 2b \n\t" " addiu %[p_coefs], %[p_coefs], 8 \n\t" "3: \n\t" "beq %[k], $zero, 5f \n\t" " nop \n\t" "4: \n\t" "lhu %[tmp1], 0(%[p_data_in]) \n\t" "lhu %[tmp2], 0(%[p_coefs]) \n\t" "addiu %[p_data_in], %[p_data_in], -2 \n\t" "addiu %[k], %[k], -1 \n\t" "dpa.w.ph $ac0, %[tmp1], %[tmp2] \n\t" "bgtz %[k], 4b \n\t" " addiu %[p_coefs], %[p_coefs], 2 \n\t" "5: \n\t" "extr_r.w %[out_s32], $ac0, 12 \n\t" "addu %[p_data_in_0], %[p_data_in_0], %[factor_2] \n\t" "subu %[i], %[i], %[factor] \n\t" "shll_s.w %[out_s32], %[out_s32], 16 \n\t" "sra %[out_s32], %[out_s32], 16 \n\t" "sh %[out_s32], 0(%[data_out]) \n\t" "bgtz %[i], 1b \n\t" " addiu %[data_out], %[data_out], 2 \n\t" ".set pop \n\t" : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3), [tmp4] "=&r" (tmp4), [p_data_in] "=&r" (p_data_in), [p_data_in_0] "+r" (p_data_in_0), [p_coefs] "=&r" (p_coefficients), [j] "=&r" (j), [out_s32] "=&r" (out_s32), [factor_2] "=&r" (factor_2), [i] "=&r" (i), [k] "=&r" (k) : [coef_length] "r" (coefficients_length), [data_out] "r" (data_out), [p_coefs_0] "r" (p_coefficients_0), [endpos] "r" (endpos), [delay] "r" (delay), [factor] "r" (factor) : "memory", "hi", "lo" ); #else // #if defined(MIPS_DSP_R2_LE) __asm __volatile ( ".set push \n\t" ".set noreorder \n\t" "sll %[factor_2], %[factor], 1 \n\t" "subu %[i], %[endpos], %[delay] \n\t" "1: \n\t" "move %[p_data_in], %[p_data_in_0] \n\t" "addiu %[out_s32], $zero, 2048 \n\t" "move %[p_coefs], %[p_coefs_0] \n\t" "sra %[j], %[coef_length], 1 \n\t" "beq %[j], $zero, 3f \n\t" " andi %[k], %[coef_length], 1 \n\t" "2: \n\t" "lh %[tmp1], 0(%[p_data_in]) \n\t" "lh %[tmp2], 0(%[p_coefs]) \n\t" "lh %[tmp3], -2(%[p_data_in]) \n\t" "lh %[tmp4], 2(%[p_coefs]) \n\t" "mul %[tmp1], %[tmp1], %[tmp2] \n\t" "addiu %[p_coefs], %[p_coefs], 4 \n\t" "mul %[tmp3], %[tmp3], %[tmp4] \n\t" "addiu %[j], %[j], -1 \n\t" "addiu %[p_data_in], %[p_data_in], -4 \n\t" "addu %[tmp1], %[tmp1], %[tmp3] \n\t" "bgtz %[j], 2b \n\t" " addu %[out_s32], %[out_s32], %[tmp1] \n\t" "3: \n\t" "beq %[k], $zero, 4f \n\t" " nop \n\t" "lh %[tmp1], 0(%[p_data_in]) \n\t" "lh %[tmp2], 0(%[p_coefs]) \n\t" "mul %[tmp1], %[tmp1], %[tmp2] \n\t" "addu %[out_s32], %[out_s32], %[tmp1] \n\t" "4: \n\t" "sra %[out_s32], %[out_s32], 12 \n\t" "addu %[p_data_in_0], %[p_data_in_0], %[factor_2] \n\t" #if defined(MIPS_DSP_R1_LE) "shll_s.w %[out_s32], %[out_s32], 16 \n\t" "sra %[out_s32], %[out_s32], 16 \n\t" #else // #if defined(MIPS_DSP_R1_LE) "slt %[tmp1], %[max_16], %[out_s32] \n\t" "movn %[out_s32], %[max_16], %[tmp1] \n\t" "slt %[tmp1], %[out_s32], %[min_16] \n\t" "movn %[out_s32], %[min_16], %[tmp1] \n\t" #endif // #if defined(MIPS_DSP_R1_LE) "subu %[i], %[i], %[factor] \n\t" "sh %[out_s32], 0(%[data_out]) \n\t" "bgtz %[i], 1b \n\t" " addiu %[data_out], %[data_out], 2 \n\t" ".set pop \n\t" : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3), [tmp4] "=&r" (tmp4), [p_data_in] "=&r" (p_data_in), [k] "=&r" (k), [p_data_in_0] "+r" (p_data_in_0), [p_coefs] "=&r" (p_coefficients), [j] "=&r" (j), [out_s32] "=&r" (out_s32), [factor_2] "=&r" (factor_2), [i] "=&r" (i) : [coef_length] "r" (coefficients_length), [data_out] "r" (data_out), [p_coefs_0] "r" (p_coefficients_0), [endpos] "r" (endpos), #if !defined(MIPS_DSP_R1_LE) [max_16] "r" (max_16), [min_16] "r" (min_16), #endif // #if !defined(MIPS_DSP_R1_LE) [delay] "r" (delay), [factor] "r" (factor) : "memory", "hi", "lo" ); #endif // #if defined(MIPS_DSP_R2_LE) return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/downsample_fast_neon.c0000664000175000017500000002235714475643423030720 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/signal_processing/include/signal_processing_library.h" #include // NEON intrinsics version of WebRtcSpl_DownsampleFast() // for ARM 32-bit/64-bit platforms. int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in, size_t data_in_length, int16_t* data_out, size_t data_out_length, const int16_t* __restrict coefficients, size_t coefficients_length, int factor, size_t delay) { size_t i = 0; size_t j = 0; int32_t out_s32 = 0; size_t endpos = delay + factor * (data_out_length - 1) + 1; size_t res = data_out_length & 0x7; size_t endpos1 = endpos - factor * res; // Return error if any of the running conditions doesn't meet. if (data_out_length == 0 || coefficients_length == 0 || data_in_length < endpos) { return -1; } // First part, unroll the loop 8 times, with 3 subcases // (factor == 2, 4, others). switch (factor) { case 2: { for (i = delay; i < endpos1; i += 16) { // Round value, 0.5 in Q12. int32x4_t out32x4_0 = vdupq_n_s32(2048); int32x4_t out32x4_1 = vdupq_n_s32(2048); #if defined(WEBRTC_ARCH_ARM64) // Unroll the loop 2 times. for (j = 0; j < coefficients_length - 1; j += 2) { int32x2_t coeff32 = vld1_dup_s32((int32_t*)&coefficients[j]); int16x4_t coeff16x4 = vreinterpret_s16_s32(coeff32); int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j - 1]); // Mul and accumulate low 64-bit data. int16x4_t in16x4_0 = vget_low_s16(in16x8x2.val[0]); int16x4_t in16x4_1 = vget_low_s16(in16x8x2.val[1]); out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_0, coeff16x4, 1); out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_1, coeff16x4, 0); // Mul and accumulate high 64-bit data. // TODO: vget_high_s16 need extra cost on ARM64. This could be // replaced by vmlal_high_lane_s16. But for the interface of // vmlal_high_lane_s16, there is a bug in gcc 4.9. // This issue need to be tracked in the future. int16x4_t in16x4_2 = vget_high_s16(in16x8x2.val[0]); int16x4_t in16x4_3 = vget_high_s16(in16x8x2.val[1]); out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_2, coeff16x4, 1); out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_3, coeff16x4, 0); } for (; j < coefficients_length; j++) { int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]); int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j]); // Mul and accumulate low 64-bit data. int16x4_t in16x4_0 = vget_low_s16(in16x8x2.val[0]); out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_0, coeff16x4, 0); // Mul and accumulate high 64-bit data. // TODO: vget_high_s16 need extra cost on ARM64. This could be // replaced by vmlal_high_lane_s16. But for the interface of // vmlal_high_lane_s16, there is a bug in gcc 4.9. // This issue need to be tracked in the future. int16x4_t in16x4_1 = vget_high_s16(in16x8x2.val[0]); out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_1, coeff16x4, 0); } #else // On ARMv7, the loop unrolling 2 times results in performance // regression. for (j = 0; j < coefficients_length; j++) { int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]); int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j]); // Mul and accumulate. int16x4_t in16x4_0 = vget_low_s16(in16x8x2.val[0]); int16x4_t in16x4_1 = vget_high_s16(in16x8x2.val[0]); out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_0, coeff16x4, 0); out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_1, coeff16x4, 0); } #endif // Saturate and store the output. int16x4_t out16x4_0 = vqshrn_n_s32(out32x4_0, 12); int16x4_t out16x4_1 = vqshrn_n_s32(out32x4_1, 12); vst1q_s16(data_out, vcombine_s16(out16x4_0, out16x4_1)); data_out += 8; } break; } case 4: { for (i = delay; i < endpos1; i += 32) { // Round value, 0.5 in Q12. int32x4_t out32x4_0 = vdupq_n_s32(2048); int32x4_t out32x4_1 = vdupq_n_s32(2048); // Unroll the loop 4 times. for (j = 0; j < coefficients_length - 3; j += 4) { int16x4_t coeff16x4 = vld1_s16(&coefficients[j]); int16x8x4_t in16x8x4 = vld4q_s16(&data_in[i - j - 3]); // Mul and accumulate low 64-bit data. int16x4_t in16x4_0 = vget_low_s16(in16x8x4.val[0]); int16x4_t in16x4_2 = vget_low_s16(in16x8x4.val[1]); int16x4_t in16x4_4 = vget_low_s16(in16x8x4.val[2]); int16x4_t in16x4_6 = vget_low_s16(in16x8x4.val[3]); out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_0, coeff16x4, 3); out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_2, coeff16x4, 2); out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_4, coeff16x4, 1); out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_6, coeff16x4, 0); // Mul and accumulate high 64-bit data. // TODO: vget_high_s16 need extra cost on ARM64. This could be // replaced by vmlal_high_lane_s16. But for the interface of // vmlal_high_lane_s16, there is a bug in gcc 4.9. // This issue need to be tracked in the future. int16x4_t in16x4_1 = vget_high_s16(in16x8x4.val[0]); int16x4_t in16x4_3 = vget_high_s16(in16x8x4.val[1]); int16x4_t in16x4_5 = vget_high_s16(in16x8x4.val[2]); int16x4_t in16x4_7 = vget_high_s16(in16x8x4.val[3]); out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_1, coeff16x4, 3); out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_3, coeff16x4, 2); out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_5, coeff16x4, 1); out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_7, coeff16x4, 0); } for (; j < coefficients_length; j++) { int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]); int16x8x4_t in16x8x4 = vld4q_s16(&data_in[i - j]); // Mul and accumulate low 64-bit data. int16x4_t in16x4_0 = vget_low_s16(in16x8x4.val[0]); out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_0, coeff16x4, 0); // Mul and accumulate high 64-bit data. // TODO: vget_high_s16 need extra cost on ARM64. This could be // replaced by vmlal_high_lane_s16. But for the interface of // vmlal_high_lane_s16, there is a bug in gcc 4.9. // This issue need to be tracked in the future. int16x4_t in16x4_1 = vget_high_s16(in16x8x4.val[0]); out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_1, coeff16x4, 0); } // Saturate and store the output. int16x4_t out16x4_0 = vqshrn_n_s32(out32x4_0, 12); int16x4_t out16x4_1 = vqshrn_n_s32(out32x4_1, 12); vst1q_s16(data_out, vcombine_s16(out16x4_0, out16x4_1)); data_out += 8; } break; } default: { for (i = delay; i < endpos1; i += factor * 8) { // Round value, 0.5 in Q12. int32x4_t out32x4_0 = vdupq_n_s32(2048); int32x4_t out32x4_1 = vdupq_n_s32(2048); for (j = 0; j < coefficients_length; j++) { int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]); int16x4_t in16x4_0 = vld1_dup_s16(&data_in[i - j]); in16x4_0 = vld1_lane_s16(&data_in[i + factor - j], in16x4_0, 1); in16x4_0 = vld1_lane_s16(&data_in[i + factor * 2 - j], in16x4_0, 2); in16x4_0 = vld1_lane_s16(&data_in[i + factor * 3 - j], in16x4_0, 3); int16x4_t in16x4_1 = vld1_dup_s16(&data_in[i + factor * 4 - j]); in16x4_1 = vld1_lane_s16(&data_in[i + factor * 5 - j], in16x4_1, 1); in16x4_1 = vld1_lane_s16(&data_in[i + factor * 6 - j], in16x4_1, 2); in16x4_1 = vld1_lane_s16(&data_in[i + factor * 7 - j], in16x4_1, 3); // Mul and accumulate. out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_0, coeff16x4, 0); out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_1, coeff16x4, 0); } // Saturate and store the output. int16x4_t out16x4_0 = vqshrn_n_s32(out32x4_0, 12); int16x4_t out16x4_1 = vqshrn_n_s32(out32x4_1, 12); vst1q_s16(data_out, vcombine_s16(out16x4_0, out16x4_1)); data_out += 8; } break; } } // Second part, do the rest iterations (if any). for (; i < endpos; i += factor) { out_s32 = 2048; // Round value, 0.5 in Q12. for (j = 0; j < coefficients_length; j++) { out_s32 = WebRtc_MulAccumW16(coefficients[j], data_in[i - j], out_s32); } // Saturate and store the output. out_s32 >>= 12; *data_out++ = WebRtcSpl_SatW32ToW16(out_s32); } return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/energy.c0000664000175000017500000000214714475643423025777 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the function WebRtcSpl_Energy(). * The description header can be found in signal_processing_library.h * */ #include "common_audio/signal_processing/include/signal_processing_library.h" int32_t WebRtcSpl_Energy(int16_t* vector, size_t vector_length, int* scale_factor) { int32_t en = 0; size_t i; int scaling = WebRtcSpl_GetScalingSquare(vector, vector_length, vector_length); size_t looptimes = vector_length; int16_t *vectorptr = vector; for (i = 0; i < looptimes; i++) { en += (*vectorptr * *vectorptr) >> scaling; vectorptr++; } *scale_factor = scaling; return en; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/filter_ar.c0000664000175000017500000000614314475643423026455 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the function WebRtcSpl_FilterAR(). * The description header can be found in signal_processing_library.h * */ #include "common_audio/signal_processing/include/signal_processing_library.h" #include "rtc_base/checks.h" size_t WebRtcSpl_FilterAR(const int16_t* a, size_t a_length, const int16_t* x, size_t x_length, int16_t* state, size_t state_length, int16_t* state_low, size_t state_low_length, int16_t* filtered, int16_t* filtered_low, size_t filtered_low_length) { int64_t o; int32_t oLOW; size_t i, j, stop; const int16_t* x_ptr = &x[0]; int16_t* filteredFINAL_ptr = filtered; int16_t* filteredFINAL_LOW_ptr = filtered_low; for (i = 0; i < x_length; i++) { // Calculate filtered[i] and filtered_low[i] const int16_t* a_ptr = &a[1]; // The index can become negative, but the arrays will never be indexed // with it when negative. Nevertheless, the index cannot be a size_t // because of this. int filtered_ix = (int)i - 1; int16_t* state_ptr = &state[state_length - 1]; int16_t* state_low_ptr = &state_low[state_length - 1]; o = (int32_t)(*x_ptr++) * (1 << 12); oLOW = (int32_t)0; stop = (i < a_length) ? i + 1 : a_length; for (j = 1; j < stop; j++) { RTC_DCHECK_GE(filtered_ix, 0); o -= *a_ptr * filtered[filtered_ix]; oLOW -= *a_ptr++ * filtered_low[filtered_ix]; --filtered_ix; } for (j = i + 1; j < a_length; j++) { o -= *a_ptr * *state_ptr--; oLOW -= *a_ptr++ * *state_low_ptr--; } o += (oLOW >> 12); *filteredFINAL_ptr = (int16_t)((o + (int32_t)2048) >> 12); *filteredFINAL_LOW_ptr++ = (int16_t)(o - ((int32_t)(*filteredFINAL_ptr++) * (1 << 12))); } // Save the filter state if (x_length >= state_length) { WebRtcSpl_CopyFromEndW16(filtered, x_length, a_length - 1, state); WebRtcSpl_CopyFromEndW16(filtered_low, x_length, a_length - 1, state_low); } else { for (i = 0; i < state_length - x_length; i++) { state[i] = state[i + x_length]; state_low[i] = state_low[i + x_length]; } for (i = 0; i < x_length; i++) { state[state_length - x_length + i] = filtered[i]; state_low[state_length - x_length + i] = filtered_low[i]; } } return x_length; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/filter_ar_fast_q12.c0000664000175000017500000000313614475643423030154 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "stddef.h" #include "rtc_base/checks.h" #include "common_audio/signal_processing/include/signal_processing_library.h" // TODO(bjornv): Change the return type to report errors. void WebRtcSpl_FilterARFastQ12(const int16_t* data_in, int16_t* data_out, const int16_t* __restrict coefficients, size_t coefficients_length, size_t data_length) { size_t i = 0; size_t j = 0; RTC_DCHECK_GT(data_length, 0); RTC_DCHECK_GT(coefficients_length, 1); for (i = 0; i < data_length; i++) { int64_t output = 0; int64_t sum = 0; for (j = coefficients_length - 1; j > 0; j--) { // Negative overflow is permitted here, because this is // auto-regressive filters, and the state for each batch run is // stored in the "negative" positions of the output vector. sum += coefficients[j] * data_out[(ptrdiff_t) i - (ptrdiff_t) j]; } output = coefficients[0] * data_in[i]; output -= sum; // Saturate and store the output. output = WEBRTC_SPL_SAT(134215679, output, -134217728); data_out[i] = (int16_t)((output + 2048) >> 12); } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S0000664000175000017500000001676514475643423031264 0ustar00arunarun@ @ Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. @ @ Use of this source code is governed by a BSD-style license @ that can be found in the LICENSE file in the root of the source @ tree. An additional intellectual property rights grant can be found @ in the file PATENTS. All contributing project authors may @ be found in the AUTHORS file in the root of the source tree. @ @ This file contains the function WebRtcSpl_FilterARFastQ12(), optimized for @ ARMv7 platform. The description header can be found in @ signal_processing_library.h @ @ Output is bit-exact with the generic C code as in filter_ar_fast_q12.c, and @ the reference C code at end of this file. @ Assumptions: @ (1) data_length > 0 @ (2) coefficients_length > 1 @ Register usage: @ @ r0: &data_in[i] @ r1: &data_out[i], for result ouput @ r2: &coefficients[0] @ r3: coefficients_length @ r4: Iteration counter for the outer loop. @ r5: data_out[j] as multiplication inputs @ r6: Calculated value for output data_out[]; interation counter for inner loop @ r7: Partial sum of a filtering multiplication results @ r8: Partial sum of a filtering multiplication results @ r9: &data_out[], for filtering input; data_in[i] @ r10: coefficients[j] @ r11: Scratch @ r12: &coefficients[j] #include "rtc_base/system/asm_defines.h" GLOBAL_FUNCTION WebRtcSpl_FilterARFastQ12 .align 2 DEFINE_FUNCTION WebRtcSpl_FilterARFastQ12 push {r4-r11} ldrsh r12, [sp, #32] @ data_length subs r4, r12, #1 beq ODD_LENGTH @ jump if data_length == 1 LOOP_LENGTH: add r12, r2, r3, lsl #1 sub r12, #4 @ &coefficients[coefficients_length - 2] sub r9, r1, r3, lsl #1 add r9, #2 @ &data_out[i - coefficients_length + 1] ldr r5, [r9], #4 @ data_out[i - coefficients_length + {1,2}] mov r7, #0 @ sum1 mov r8, #0 @ sum2 subs r6, r3, #3 @ Iteration counter for inner loop. beq ODD_A_LENGTH @ branch if coefficients_length == 3 blt POST_LOOP_A_LENGTH @ branch if coefficients_length == 2 LOOP_A_LENGTH: ldr r10, [r12], #-4 @ coefficients[j - 1], coefficients[j] subs r6, #2 smlatt r8, r10, r5, r8 @ sum2 += coefficients[j] * data_out[i - j + 1]; smlatb r7, r10, r5, r7 @ sum1 += coefficients[j] * data_out[i - j]; smlabt r7, r10, r5, r7 @ coefficients[j - 1] * data_out[i - j + 1]; ldr r5, [r9], #4 @ data_out[i - j + 2], data_out[i - j + 3] smlabb r8, r10, r5, r8 @ coefficients[j - 1] * data_out[i - j + 2]; bgt LOOP_A_LENGTH blt POST_LOOP_A_LENGTH ODD_A_LENGTH: ldrsh r10, [r12, #2] @ Filter coefficients coefficients[2] sub r12, #2 @ &coefficients[0] smlabb r7, r10, r5, r7 @ sum1 += coefficients[2] * data_out[i - 2]; smlabt r8, r10, r5, r8 @ sum2 += coefficients[2] * data_out[i - 1]; ldr r5, [r9, #-2] @ data_out[i - 1], data_out[i] POST_LOOP_A_LENGTH: ldr r10, [r12] @ coefficients[0], coefficients[1] smlatb r7, r10, r5, r7 @ sum1 += coefficients[1] * data_out[i - 1]; ldr r9, [r0], #4 @ data_in[i], data_in[i + 1] smulbb r6, r10, r9 @ output1 = coefficients[0] * data_in[i]; sub r6, r7 @ output1 -= sum1; sbfx r11, r6, #12, #16 ssat r7, #16, r6, asr #12 cmp r7, r11 addeq r6, r6, #2048 ssat r6, #16, r6, asr #12 strh r6, [r1], #2 @ Store data_out[i] smlatb r8, r10, r6, r8 @ sum2 += coefficients[1] * data_out[i]; smulbt r6, r10, r9 @ output2 = coefficients[0] * data_in[i + 1]; sub r6, r8 @ output1 -= sum1; sbfx r11, r6, #12, #16 ssat r7, #16, r6, asr #12 cmp r7, r11 addeq r6, r6, #2048 ssat r6, #16, r6, asr #12 strh r6, [r1], #2 @ Store data_out[i + 1] subs r4, #2 bgt LOOP_LENGTH blt END @ For even data_length, it's done. Jump to END. @ Process i = data_length -1, for the case of an odd length. ODD_LENGTH: add r12, r2, r3, lsl #1 sub r12, #4 @ &coefficients[coefficients_length - 2] sub r9, r1, r3, lsl #1 add r9, #2 @ &data_out[i - coefficients_length + 1] mov r7, #0 @ sum1 mov r8, #0 @ sum1 subs r6, r3, #2 @ inner loop counter beq EVEN_A_LENGTH @ branch if coefficients_length == 2 LOOP2_A_LENGTH: ldr r10, [r12], #-4 @ coefficients[j - 1], coefficients[j] ldr r5, [r9], #4 @ data_out[i - j], data_out[i - j + 1] subs r6, #2 smlatb r7, r10, r5, r7 @ sum1 += coefficients[j] * data_out[i - j]; smlabt r8, r10, r5, r8 @ coefficients[j - 1] * data_out[i - j + 1]; bgt LOOP2_A_LENGTH addlt r12, #2 blt POST_LOOP2_A_LENGTH EVEN_A_LENGTH: ldrsh r10, [r12, #2] @ Filter coefficients coefficients[1] ldrsh r5, [r9] @ data_out[i - 1] smlabb r7, r10, r5, r7 @ sum1 += coefficients[1] * data_out[i - 1]; POST_LOOP2_A_LENGTH: ldrsh r10, [r12] @ Filter coefficients coefficients[0] ldrsh r9, [r0] @ data_in[i] smulbb r6, r10, r9 @ output1 = coefficients[0] * data_in[i]; sub r6, r7 @ output1 -= sum1; sub r6, r8 @ output1 -= sum1; sbfx r8, r6, #12, #16 ssat r7, #16, r6, asr #12 cmp r7, r8 addeq r6, r6, #2048 ssat r6, #16, r6, asr #12 strh r6, [r1] @ Store the data_out[i] END: pop {r4-r11} bx lr @Reference C code: @ @void WebRtcSpl_FilterARFastQ12(int16_t* data_in, @ int16_t* data_out, @ int16_t* __restrict coefficients, @ size_t coefficients_length, @ size_t data_length) { @ size_t i = 0; @ size_t j = 0; @ @ assert(data_length > 0); @ assert(coefficients_length > 1); @ @ for (i = 0; i < data_length - 1; i += 2) { @ int32_t output1 = 0; @ int32_t sum1 = 0; @ int32_t output2 = 0; @ int32_t sum2 = 0; @ @ for (j = coefficients_length - 1; j > 2; j -= 2) { @ sum1 += coefficients[j] * data_out[i - j]; @ sum1 += coefficients[j - 1] * data_out[i - j + 1]; @ sum2 += coefficients[j] * data_out[i - j + 1]; @ sum2 += coefficients[j - 1] * data_out[i - j + 2]; @ } @ @ if (j == 2) { @ sum1 += coefficients[2] * data_out[i - 2]; @ sum2 += coefficients[2] * data_out[i - 1]; @ } @ @ sum1 += coefficients[1] * data_out[i - 1]; @ output1 = coefficients[0] * data_in[i]; @ output1 -= sum1; @ // Saturate and store the output. @ output1 = WEBRTC_SPL_SAT(134215679, output1, -134217728); @ data_out[i] = (int16_t)((output1 + 2048) >> 12); @ @ sum2 += coefficients[1] * data_out[i]; @ output2 = coefficients[0] * data_in[i + 1]; @ output2 -= sum2; @ // Saturate and store the output. @ output2 = WEBRTC_SPL_SAT(134215679, output2, -134217728); @ data_out[i + 1] = (int16_t)((output2 + 2048) >> 12); @ } @ @ if (i == data_length - 1) { @ int32_t output1 = 0; @ int32_t sum1 = 0; @ @ for (j = coefficients_length - 1; j > 1; j -= 2) { @ sum1 += coefficients[j] * data_out[i - j]; @ sum1 += coefficients[j - 1] * data_out[i - j + 1]; @ } @ @ if (j == 1) { @ sum1 += coefficients[1] * data_out[i - 1]; @ } @ @ output1 = coefficients[0] * data_in[i]; @ output1 -= sum1; @ // Saturate and store the output. @ output1 = WEBRTC_SPL_SAT(134215679, output1, -134217728); @ data_out[i] = (int16_t)((output1 + 2048) >> 12); @ } @} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/filter_ar_fast_q12_mips.c0000664000175000017500000001742514475643423031212 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/checks.h" #include "common_audio/signal_processing/include/signal_processing_library.h" void WebRtcSpl_FilterARFastQ12(const int16_t* data_in, int16_t* data_out, const int16_t* __restrict coefficients, size_t coefficients_length, size_t data_length) { int r0, r1, r2, r3; int coef0, offset; int i, j, k; int coefptr, outptr, tmpout, inptr; #if !defined(MIPS_DSP_R1_LE) int max16 = 0x7FFF; int min16 = 0xFFFF8000; #endif // #if !defined(MIPS_DSP_R1_LE) RTC_DCHECK_GT(data_length, 0); RTC_DCHECK_GT(coefficients_length, 1); __asm __volatile ( ".set push \n\t" ".set noreorder \n\t" "addiu %[i], %[data_length], 0 \n\t" "lh %[coef0], 0(%[coefficients]) \n\t" "addiu %[j], %[coefficients_length], -1 \n\t" "andi %[k], %[j], 1 \n\t" "sll %[offset], %[j], 1 \n\t" "subu %[outptr], %[data_out], %[offset] \n\t" "addiu %[inptr], %[data_in], 0 \n\t" "bgtz %[k], 3f \n\t" " addu %[coefptr], %[coefficients], %[offset] \n\t" "1: \n\t" "lh %[r0], 0(%[inptr]) \n\t" "addiu %[i], %[i], -1 \n\t" "addiu %[tmpout], %[outptr], 0 \n\t" "mult %[r0], %[coef0] \n\t" "2: \n\t" "lh %[r0], 0(%[tmpout]) \n\t" "lh %[r1], 0(%[coefptr]) \n\t" "lh %[r2], 2(%[tmpout]) \n\t" "lh %[r3], -2(%[coefptr]) \n\t" "addiu %[tmpout], %[tmpout], 4 \n\t" "msub %[r0], %[r1] \n\t" "msub %[r2], %[r3] \n\t" "addiu %[j], %[j], -2 \n\t" "bgtz %[j], 2b \n\t" " addiu %[coefptr], %[coefptr], -4 \n\t" #if defined(MIPS_DSP_R1_LE) "extr_r.w %[r0], $ac0, 12 \n\t" #else // #if defined(MIPS_DSP_R1_LE) "mflo %[r0] \n\t" #endif // #if defined(MIPS_DSP_R1_LE) "addu %[coefptr], %[coefficients], %[offset] \n\t" "addiu %[inptr], %[inptr], 2 \n\t" "addiu %[j], %[coefficients_length], -1 \n\t" #if defined(MIPS_DSP_R1_LE) "shll_s.w %[r0], %[r0], 16 \n\t" "sra %[r0], %[r0], 16 \n\t" #else // #if defined(MIPS_DSP_R1_LE) "addiu %[r0], %[r0], 2048 \n\t" "sra %[r0], %[r0], 12 \n\t" "slt %[r1], %[max16], %[r0] \n\t" "movn %[r0], %[max16], %[r1] \n\t" "slt %[r1], %[r0], %[min16] \n\t" "movn %[r0], %[min16], %[r1] \n\t" #endif // #if defined(MIPS_DSP_R1_LE) "sh %[r0], 0(%[tmpout]) \n\t" "bgtz %[i], 1b \n\t" " addiu %[outptr], %[outptr], 2 \n\t" "b 5f \n\t" " nop \n\t" "3: \n\t" "lh %[r0], 0(%[inptr]) \n\t" "addiu %[i], %[i], -1 \n\t" "addiu %[tmpout], %[outptr], 0 \n\t" "mult %[r0], %[coef0] \n\t" "4: \n\t" "lh %[r0], 0(%[tmpout]) \n\t" "lh %[r1], 0(%[coefptr]) \n\t" "lh %[r2], 2(%[tmpout]) \n\t" "lh %[r3], -2(%[coefptr]) \n\t" "addiu %[tmpout], %[tmpout], 4 \n\t" "msub %[r0], %[r1] \n\t" "msub %[r2], %[r3] \n\t" "addiu %[j], %[j], -2 \n\t" "bgtz %[j], 4b \n\t" " addiu %[coefptr], %[coefptr], -4 \n\t" "lh %[r0], 0(%[tmpout]) \n\t" "lh %[r1], 0(%[coefptr]) \n\t" "msub %[r0], %[r1] \n\t" #if defined(MIPS_DSP_R1_LE) "extr_r.w %[r0], $ac0, 12 \n\t" #else // #if defined(MIPS_DSP_R1_LE) "mflo %[r0] \n\t" #endif // #if defined(MIPS_DSP_R1_LE) "addu %[coefptr], %[coefficients], %[offset] \n\t" "addiu %[inptr], %[inptr], 2 \n\t" "addiu %[j], %[coefficients_length], -1 \n\t" #if defined(MIPS_DSP_R1_LE) "shll_s.w %[r0], %[r0], 16 \n\t" "sra %[r0], %[r0], 16 \n\t" #else // #if defined(MIPS_DSP_R1_LE) "addiu %[r0], %[r0], 2048 \n\t" "sra %[r0], %[r0], 12 \n\t" "slt %[r1], %[max16], %[r0] \n\t" "movn %[r0], %[max16], %[r1] \n\t" "slt %[r1], %[r0], %[min16] \n\t" "movn %[r0], %[min16], %[r1] \n\t" #endif // #if defined(MIPS_DSP_R1_LE) "sh %[r0], 2(%[tmpout]) \n\t" "bgtz %[i], 3b \n\t" " addiu %[outptr], %[outptr], 2 \n\t" "5: \n\t" ".set pop \n\t" : [i] "=&r" (i), [j] "=&r" (j), [k] "=&r" (k), [r0] "=&r" (r0), [r1] "=&r" (r1), [r2] "=&r" (r2), [r3] "=&r" (r3), [coef0] "=&r" (coef0), [offset] "=&r" (offset), [outptr] "=&r" (outptr), [inptr] "=&r" (inptr), [coefptr] "=&r" (coefptr), [tmpout] "=&r" (tmpout) : [coefficients] "r" (coefficients), [data_length] "r" (data_length), [coefficients_length] "r" (coefficients_length), #if !defined(MIPS_DSP_R1_LE) [max16] "r" (max16), [min16] "r" (min16), #endif [data_out] "r" (data_out), [data_in] "r" (data_in) : "hi", "lo", "memory" ); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/filter_ma_fast_q12.c0000664000175000017500000000346114475643423030150 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the function WebRtcSpl_FilterMAFastQ12(). * The description header can be found in signal_processing_library.h * */ #include "common_audio/signal_processing/include/signal_processing_library.h" #include "rtc_base/sanitizer.h" void WebRtcSpl_FilterMAFastQ12(const int16_t* in_ptr, int16_t* out_ptr, const int16_t* B, size_t B_length, size_t length) { size_t i, j; rtc_MsanCheckInitialized(B, sizeof(B[0]), B_length); rtc_MsanCheckInitialized(in_ptr - B_length + 1, sizeof(in_ptr[0]), B_length + length - 1); for (i = 0; i < length; i++) { int32_t o = 0; for (j = 0; j < B_length; j++) { // Negative overflow is permitted here, because this is // auto-regressive filters, and the state for each batch run is // stored in the "negative" positions of the output vector. o += B[j] * in_ptr[(ptrdiff_t) i - (ptrdiff_t) j]; } // If output is higher than 32768, saturate it. Same with negative side // 2^27 = 134217728, which corresponds to 32768 in Q12 // Saturate the output o = WEBRTC_SPL_SAT((int32_t)134215679, o, (int32_t)-134217728); *out_ptr++ = (int16_t)((o + (int32_t)2048) >> 12); } return; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/get_hanning_window.c0000664000175000017500000000616614475643423030363 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the function WebRtcSpl_GetHanningWindow(). * The description header can be found in signal_processing_library.h * */ #include "common_audio/signal_processing/include/signal_processing_library.h" // Hanning table with 256 entries static const int16_t kHanningTable[] = { 1, 2, 6, 10, 15, 22, 30, 39, 50, 62, 75, 89, 104, 121, 138, 157, 178, 199, 222, 246, 271, 297, 324, 353, 383, 413, 446, 479, 513, 549, 586, 624, 663, 703, 744, 787, 830, 875, 920, 967, 1015, 1064, 1114, 1165, 1218, 1271, 1325, 1381, 1437, 1494, 1553, 1612, 1673, 1734, 1796, 1859, 1924, 1989, 2055, 2122, 2190, 2259, 2329, 2399, 2471, 2543, 2617, 2691, 2765, 2841, 2918, 2995, 3073, 3152, 3232, 3312, 3393, 3475, 3558, 3641, 3725, 3809, 3895, 3980, 4067, 4154, 4242, 4330, 4419, 4509, 4599, 4689, 4781, 4872, 4964, 5057, 5150, 5244, 5338, 5432, 5527, 5622, 5718, 5814, 5910, 6007, 6104, 6202, 6299, 6397, 6495, 6594, 6693, 6791, 6891, 6990, 7090, 7189, 7289, 7389, 7489, 7589, 7690, 7790, 7890, 7991, 8091, 8192, 8293, 8393, 8494, 8594, 8694, 8795, 8895, 8995, 9095, 9195, 9294, 9394, 9493, 9593, 9691, 9790, 9889, 9987, 10085, 10182, 10280, 10377, 10474, 10570, 10666, 10762, 10857, 10952, 11046, 11140, 11234, 11327, 11420, 11512, 11603, 11695, 11785, 11875, 11965, 12054, 12142, 12230, 12317, 12404, 12489, 12575, 12659, 12743, 12826, 12909, 12991, 13072, 13152, 13232, 13311, 13389, 13466, 13543, 13619, 13693, 13767, 13841, 13913, 13985, 14055, 14125, 14194, 14262, 14329, 14395, 14460, 14525, 14588, 14650, 14711, 14772, 14831, 14890, 14947, 15003, 15059, 15113, 15166, 15219, 15270, 15320, 15369, 15417, 15464, 15509, 15554, 15597, 15640, 15681, 15721, 15760, 15798, 15835, 15871, 15905, 15938, 15971, 16001, 16031, 16060, 16087, 16113, 16138, 16162, 16185, 16206, 16227, 16246, 16263, 16280, 16295, 16309, 16322, 16334, 16345, 16354, 16362, 16369, 16374, 16378, 16382, 16383, 16384 }; void WebRtcSpl_GetHanningWindow(int16_t *v, size_t size) { size_t jj; int16_t *vptr1; int32_t index; int32_t factor = ((int32_t)0x40000000); factor = WebRtcSpl_DivW32W16(factor, (int16_t)size); if (size < 513) index = (int32_t)-0x200000; else index = (int32_t)-0x100000; vptr1 = v; for (jj = 0; jj < size; jj++) { index += factor; (*vptr1++) = kHanningTable[index >> 22]; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/get_scaling_square.c0000664000175000017500000000250314475643423030341 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the function WebRtcSpl_GetScalingSquare(). * The description header can be found in signal_processing_library.h * */ #include "common_audio/signal_processing/include/signal_processing_library.h" int16_t WebRtcSpl_GetScalingSquare(int16_t* in_vector, size_t in_vector_length, size_t times) { int16_t nbits = WebRtcSpl_GetSizeInBits((uint32_t)times); size_t i; int16_t smax = -1; int16_t sabs; int16_t *sptr = in_vector; int16_t t; size_t looptimes = in_vector_length; for (i = looptimes; i > 0; i--) { sabs = (*sptr > 0 ? *sptr++ : -*sptr++); smax = (sabs > smax ? sabs : smax); } t = WebRtcSpl_NormW32(WEBRTC_SPL_MUL(smax, smax)); if (smax == 0) { return 0; // Since norm(0) returns 0 } else { return (t > nbits) ? 0 : nbits - t; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/ilbc_specific_functions.c0000664000175000017500000000557214475643423031361 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains implementations of the iLBC specific functions * WebRtcSpl_ReverseOrderMultArrayElements() * WebRtcSpl_ElementwiseVectorMult() * WebRtcSpl_AddVectorsAndShift() * WebRtcSpl_AddAffineVectorToVector() * WebRtcSpl_AffineTransformVector() * */ #include "common_audio/signal_processing/include/signal_processing_library.h" void WebRtcSpl_ReverseOrderMultArrayElements(int16_t *out, const int16_t *in, const int16_t *win, size_t vector_length, int16_t right_shifts) { size_t i; int16_t *outptr = out; const int16_t *inptr = in; const int16_t *winptr = win; for (i = 0; i < vector_length; i++) { *outptr++ = (int16_t)((*inptr++ * *winptr--) >> right_shifts); } } void WebRtcSpl_ElementwiseVectorMult(int16_t *out, const int16_t *in, const int16_t *win, size_t vector_length, int16_t right_shifts) { size_t i; int16_t *outptr = out; const int16_t *inptr = in; const int16_t *winptr = win; for (i = 0; i < vector_length; i++) { *outptr++ = (int16_t)((*inptr++ * *winptr++) >> right_shifts); } } void WebRtcSpl_AddVectorsAndShift(int16_t *out, const int16_t *in1, const int16_t *in2, size_t vector_length, int16_t right_shifts) { size_t i; int16_t *outptr = out; const int16_t *in1ptr = in1; const int16_t *in2ptr = in2; for (i = vector_length; i > 0; i--) { (*outptr++) = (int16_t)(((*in1ptr++) + (*in2ptr++)) >> right_shifts); } } void WebRtcSpl_AddAffineVectorToVector(int16_t *out, const int16_t *in, int16_t gain, int32_t add_constant, int16_t right_shifts, size_t vector_length) { size_t i; for (i = 0; i < vector_length; i++) { out[i] += (int16_t)((in[i] * gain + add_constant) >> right_shifts); } } void WebRtcSpl_AffineTransformVector(int16_t *out, const int16_t *in, int16_t gain, int32_t add_constant, int16_t right_shifts, size_t vector_length) { size_t i; for (i = 0; i < vector_length; i++) { out[i] = (int16_t)((in[i] * gain + add_constant) >> right_shifts); } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/include/0000775000175000017500000000000014475643423025761 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/include/real_fft.h0000664000175000017500000001011314475643423027710 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_ #define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_ #include // For ComplexFFT(), the maximum fft order is 10; // WebRTC APM uses orders of only 7 and 8. enum { kMaxFFTOrder = 10 }; struct RealFFT; #ifdef __cplusplus extern "C" { #endif struct RealFFT* WebRtcSpl_CreateRealFFT(int order); void WebRtcSpl_FreeRealFFT(struct RealFFT* self); // Compute an FFT for a real-valued signal of length of 2^order, // where 1 < order <= MAX_FFT_ORDER. Transform length is determined by the // specification structure, which must be initialized prior to calling the FFT // function with WebRtcSpl_CreateRealFFT(). // The relationship between the input and output sequences can // be expressed in terms of the DFT, i.e.: // x[n] = (2^(-scalefactor)/N) . SUM[k=0,...,N-1] X[k].e^(jnk.2.pi/N) // n=0,1,2,...N-1 // N=2^order. // The conjugate-symmetric output sequence is represented using a CCS vector, // which is of length N+2, and is organized as follows: // Index: 0 1 2 3 4 5 . . . N-2 N-1 N N+1 // Component: R0 0 R1 I1 R2 I2 . . . R[N/2-1] I[N/2-1] R[N/2] 0 // where R[n] and I[n], respectively, denote the real and imaginary components // for FFT bin 'n'. Bins are numbered from 0 to N/2, where N is the FFT length. // Bin index 0 corresponds to the DC component, and bin index N/2 corresponds to // the foldover frequency. // // Input Arguments: // self - pointer to preallocated and initialized FFT specification structure. // real_data_in - the input signal. For an ARM Neon platform, it must be // aligned on a 32-byte boundary. // // Output Arguments: // complex_data_out - the output complex signal with (2^order + 2) 16-bit // elements. For an ARM Neon platform, it must be different // from real_data_in, and aligned on a 32-byte boundary. // // Return Value: // 0 - FFT calculation is successful. // -1 - Error with bad arguments (null pointers). int WebRtcSpl_RealForwardFFT(struct RealFFT* self, const int16_t* real_data_in, int16_t* complex_data_out); // Compute the inverse FFT for a conjugate-symmetric input sequence of length of // 2^order, where 1 < order <= MAX_FFT_ORDER. Transform length is determined by // the specification structure, which must be initialized prior to calling the // FFT function with WebRtcSpl_CreateRealFFT(). // For a transform of length M, the input sequence is represented using a packed // CCS vector of length M+2, which is explained in the comments for // WebRtcSpl_RealForwardFFTC above. // // Input Arguments: // self - pointer to preallocated and initialized FFT specification structure. // complex_data_in - the input complex signal with (2^order + 2) 16-bit // elements. For an ARM Neon platform, it must be aligned on // a 32-byte boundary. // // Output Arguments: // real_data_out - the output real signal. For an ARM Neon platform, it must // be different to complex_data_in, and aligned on a 32-byte // boundary. // // Return Value: // 0 or a positive number - a value that the elements in the |real_data_out| // should be shifted left with in order to get // correct physical values. // -1 - Error with bad arguments (null pointers). int WebRtcSpl_RealInverseFFT(struct RealFFT* self, const int16_t* complex_data_in, int16_t* real_data_out); #ifdef __cplusplus } #endif #endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_ ././@PaxHeader0000000000000000000000000000020500000000000010212 xustar00111 path=webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/include/signal_processing_library.h 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/include/signal_processing_library.0000664000175000017500000016375314475643423033236 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This header file includes all of the fix point signal processing library * (SPL) function descriptions and declarations. For specific function calls, * see bottom of file. */ #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SIGNAL_PROCESSING_LIBRARY_H_ #define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SIGNAL_PROCESSING_LIBRARY_H_ #include #include "common_audio/signal_processing/dot_product_with_scale.h" // Macros specific for the fixed point implementation #define WEBRTC_SPL_WORD16_MAX 32767 #define WEBRTC_SPL_WORD16_MIN -32768 #define WEBRTC_SPL_WORD32_MAX (int32_t)0x7fffffff #define WEBRTC_SPL_WORD32_MIN (int32_t)0x80000000 #define WEBRTC_SPL_MAX_LPC_ORDER 14 #define WEBRTC_SPL_MIN(A, B) (A < B ? A : B) // Get min value #define WEBRTC_SPL_MAX(A, B) (A > B ? A : B) // Get max value // TODO(kma/bjorn): For the next two macros, investigate how to correct the code // for inputs of a = WEBRTC_SPL_WORD16_MIN or WEBRTC_SPL_WORD32_MIN. #define WEBRTC_SPL_ABS_W16(a) (((int16_t)a >= 0) ? ((int16_t)a) : -((int16_t)a)) #define WEBRTC_SPL_ABS_W32(a) (((int32_t)a >= 0) ? ((int32_t)a) : -((int32_t)a)) #define WEBRTC_SPL_MUL(a, b) ((int32_t)((int32_t)(a) * (int32_t)(b))) #define WEBRTC_SPL_UMUL(a, b) ((uint32_t)((uint32_t)(a) * (uint32_t)(b))) #define WEBRTC_SPL_UMUL_32_16(a, b) ((uint32_t)((uint32_t)(a) * (uint16_t)(b))) #define WEBRTC_SPL_MUL_16_U16(a, b) ((int32_t)(int16_t)(a) * (uint16_t)(b)) // clang-format off // clang-format would choose some identation // leading to presubmit error (cpplint.py) #ifndef WEBRTC_ARCH_ARM_V7 // For ARMv7 platforms, these are inline functions in spl_inl_armv7.h #ifndef MIPS32_LE // For MIPS platforms, these are inline functions in spl_inl_mips.h #define WEBRTC_SPL_MUL_16_16(a, b) ((int32_t)(((int16_t)(a)) * ((int16_t)(b)))) #define WEBRTC_SPL_MUL_16_32_RSFT16(a, b) \ (WEBRTC_SPL_MUL_16_16(a, b >> 16) + \ ((WEBRTC_SPL_MUL_16_16(a, (b & 0xffff) >> 1) + 0x4000) >> 15)) #endif #endif #define WEBRTC_SPL_MUL_16_32_RSFT11(a, b) \ (WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 5) + \ (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x0200) >> 10)) #define WEBRTC_SPL_MUL_16_32_RSFT14(a, b) \ (WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 2) + \ (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x1000) >> 13)) #define WEBRTC_SPL_MUL_16_32_RSFT15(a, b) \ ((WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 1)) + \ (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x2000) >> 14)) // clang-format on #define WEBRTC_SPL_MUL_16_16_RSFT(a, b, c) (WEBRTC_SPL_MUL_16_16(a, b) >> (c)) #define WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(a, b, c) \ ((WEBRTC_SPL_MUL_16_16(a, b) + ((int32_t)(((int32_t)1) << ((c)-1)))) >> (c)) // C + the 32 most significant bits of A * B #define WEBRTC_SPL_SCALEDIFF32(A, B, C) \ (C + (B >> 16) * A + (((uint32_t)(B & 0x0000FFFF) * A) >> 16)) #define WEBRTC_SPL_SAT(a, b, c) (b > a ? a : b < c ? c : b) // Shifting with negative numbers allowed // Positive means left shift #define WEBRTC_SPL_SHIFT_W32(x, c) ((c) >= 0 ? (x) * (1 << (c)) : (x) >> -(c)) // Shifting with negative numbers not allowed // We cannot do casting here due to signed/unsigned problem #define WEBRTC_SPL_LSHIFT_W32(x, c) ((x) << (c)) #define WEBRTC_SPL_RSHIFT_U32(x, c) ((uint32_t)(x) >> (c)) #define WEBRTC_SPL_RAND(a) ((int16_t)((((int16_t)a * 18816) >> 7) & 0x00007fff)) #ifdef __cplusplus extern "C" { #endif #define WEBRTC_SPL_MEMCPY_W16(v1, v2, length) \ memcpy(v1, v2, (length) * sizeof(int16_t)) // inline functions: #include "common_audio/signal_processing/include/spl_inl.h" // third party math functions #include "common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h" int16_t WebRtcSpl_GetScalingSquare(int16_t* in_vector, size_t in_vector_length, size_t times); // Copy and set operations. Implementation in copy_set_operations.c. // Descriptions at bottom of file. void WebRtcSpl_MemSetW16(int16_t* vector, int16_t set_value, size_t vector_length); void WebRtcSpl_MemSetW32(int32_t* vector, int32_t set_value, size_t vector_length); void WebRtcSpl_MemCpyReversedOrder(int16_t* out_vector, int16_t* in_vector, size_t vector_length); void WebRtcSpl_CopyFromEndW16(const int16_t* in_vector, size_t in_vector_length, size_t samples, int16_t* out_vector); void WebRtcSpl_ZerosArrayW16(int16_t* vector, size_t vector_length); void WebRtcSpl_ZerosArrayW32(int32_t* vector, size_t vector_length); // End: Copy and set operations. // Minimum and maximum operation functions and their pointers. // Implementation in min_max_operations.c. // Returns the largest absolute value in a signed 16-bit vector. // // Input: // - vector : 16-bit input vector. // - length : Number of samples in vector. // // Return value : Maximum absolute value in vector. typedef int16_t (*MaxAbsValueW16)(const int16_t* vector, size_t length); extern const MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16; int16_t WebRtcSpl_MaxAbsValueW16C(const int16_t* vector, size_t length); #if defined(WEBRTC_HAS_NEON) int16_t WebRtcSpl_MaxAbsValueW16Neon(const int16_t* vector, size_t length); #endif #if defined(MIPS32_LE) int16_t WebRtcSpl_MaxAbsValueW16_mips(const int16_t* vector, size_t length); #endif // Returns the largest absolute value in a signed 32-bit vector. // // Input: // - vector : 32-bit input vector. // - length : Number of samples in vector. // // Return value : Maximum absolute value in vector. typedef int32_t (*MaxAbsValueW32)(const int32_t* vector, size_t length); extern const MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32; int32_t WebRtcSpl_MaxAbsValueW32C(const int32_t* vector, size_t length); #if defined(WEBRTC_HAS_NEON) int32_t WebRtcSpl_MaxAbsValueW32Neon(const int32_t* vector, size_t length); #endif #if defined(MIPS_DSP_R1_LE) int32_t WebRtcSpl_MaxAbsValueW32_mips(const int32_t* vector, size_t length); #endif // Returns the maximum value of a 16-bit vector. // // Input: // - vector : 16-bit input vector. // - length : Number of samples in vector. // // Return value : Maximum sample value in |vector|. typedef int16_t (*MaxValueW16)(const int16_t* vector, size_t length); extern const MaxValueW16 WebRtcSpl_MaxValueW16; int16_t WebRtcSpl_MaxValueW16C(const int16_t* vector, size_t length); #if defined(WEBRTC_HAS_NEON) int16_t WebRtcSpl_MaxValueW16Neon(const int16_t* vector, size_t length); #endif #if defined(MIPS32_LE) int16_t WebRtcSpl_MaxValueW16_mips(const int16_t* vector, size_t length); #endif // Returns the maximum value of a 32-bit vector. // // Input: // - vector : 32-bit input vector. // - length : Number of samples in vector. // // Return value : Maximum sample value in |vector|. typedef int32_t (*MaxValueW32)(const int32_t* vector, size_t length); extern const MaxValueW32 WebRtcSpl_MaxValueW32; int32_t WebRtcSpl_MaxValueW32C(const int32_t* vector, size_t length); #if defined(WEBRTC_HAS_NEON) int32_t WebRtcSpl_MaxValueW32Neon(const int32_t* vector, size_t length); #endif #if defined(MIPS32_LE) int32_t WebRtcSpl_MaxValueW32_mips(const int32_t* vector, size_t length); #endif // Returns the minimum value of a 16-bit vector. // // Input: // - vector : 16-bit input vector. // - length : Number of samples in vector. // // Return value : Minimum sample value in |vector|. typedef int16_t (*MinValueW16)(const int16_t* vector, size_t length); extern const MinValueW16 WebRtcSpl_MinValueW16; int16_t WebRtcSpl_MinValueW16C(const int16_t* vector, size_t length); #if defined(WEBRTC_HAS_NEON) int16_t WebRtcSpl_MinValueW16Neon(const int16_t* vector, size_t length); #endif #if defined(MIPS32_LE) int16_t WebRtcSpl_MinValueW16_mips(const int16_t* vector, size_t length); #endif // Returns the minimum value of a 32-bit vector. // // Input: // - vector : 32-bit input vector. // - length : Number of samples in vector. // // Return value : Minimum sample value in |vector|. typedef int32_t (*MinValueW32)(const int32_t* vector, size_t length); extern const MinValueW32 WebRtcSpl_MinValueW32; int32_t WebRtcSpl_MinValueW32C(const int32_t* vector, size_t length); #if defined(WEBRTC_HAS_NEON) int32_t WebRtcSpl_MinValueW32Neon(const int32_t* vector, size_t length); #endif #if defined(MIPS32_LE) int32_t WebRtcSpl_MinValueW32_mips(const int32_t* vector, size_t length); #endif // Returns the vector index to the largest absolute value of a 16-bit vector. // // Input: // - vector : 16-bit input vector. // - length : Number of samples in vector. // // Return value : Index to the maximum absolute value in vector. // If there are multiple equal maxima, return the index of the // first. -32768 will always have precedence over 32767 (despite // -32768 presenting an int16 absolute value of 32767). size_t WebRtcSpl_MaxAbsIndexW16(const int16_t* vector, size_t length); // Returns the vector index to the maximum sample value of a 16-bit vector. // // Input: // - vector : 16-bit input vector. // - length : Number of samples in vector. // // Return value : Index to the maximum value in vector (if multiple // indexes have the maximum, return the first). size_t WebRtcSpl_MaxIndexW16(const int16_t* vector, size_t length); // Returns the vector index to the maximum sample value of a 32-bit vector. // // Input: // - vector : 32-bit input vector. // - length : Number of samples in vector. // // Return value : Index to the maximum value in vector (if multiple // indexes have the maximum, return the first). size_t WebRtcSpl_MaxIndexW32(const int32_t* vector, size_t length); // Returns the vector index to the minimum sample value of a 16-bit vector. // // Input: // - vector : 16-bit input vector. // - length : Number of samples in vector. // // Return value : Index to the mimimum value in vector (if multiple // indexes have the minimum, return the first). size_t WebRtcSpl_MinIndexW16(const int16_t* vector, size_t length); // Returns the vector index to the minimum sample value of a 32-bit vector. // // Input: // - vector : 32-bit input vector. // - length : Number of samples in vector. // // Return value : Index to the mimimum value in vector (if multiple // indexes have the minimum, return the first). size_t WebRtcSpl_MinIndexW32(const int32_t* vector, size_t length); // End: Minimum and maximum operations. // Vector scaling operations. Implementation in vector_scaling_operations.c. // Description at bottom of file. void WebRtcSpl_VectorBitShiftW16(int16_t* out_vector, size_t vector_length, const int16_t* in_vector, int16_t right_shifts); void WebRtcSpl_VectorBitShiftW32(int32_t* out_vector, size_t vector_length, const int32_t* in_vector, int16_t right_shifts); void WebRtcSpl_VectorBitShiftW32ToW16(int16_t* out_vector, size_t vector_length, const int32_t* in_vector, int right_shifts); void WebRtcSpl_ScaleVector(const int16_t* in_vector, int16_t* out_vector, int16_t gain, size_t vector_length, int16_t right_shifts); void WebRtcSpl_ScaleVectorWithSat(const int16_t* in_vector, int16_t* out_vector, int16_t gain, size_t vector_length, int16_t right_shifts); void WebRtcSpl_ScaleAndAddVectors(const int16_t* in_vector1, int16_t gain1, int right_shifts1, const int16_t* in_vector2, int16_t gain2, int right_shifts2, int16_t* out_vector, size_t vector_length); // The functions (with related pointer) perform the vector operation: // out_vector[k] = ((scale1 * in_vector1[k]) + (scale2 * in_vector2[k]) // + round_value) >> right_shifts, // where round_value = (1 << right_shifts) >> 1. // // Input: // - in_vector1 : Input vector 1 // - in_vector1_scale : Gain to be used for vector 1 // - in_vector2 : Input vector 2 // - in_vector2_scale : Gain to be used for vector 2 // - right_shifts : Number of right bit shifts to be applied // - length : Number of elements in the input vectors // // Output: // - out_vector : Output vector // Return value : 0 if OK, -1 if (in_vector1 == null // || in_vector2 == null || out_vector == null // || length <= 0 || right_shift < 0). typedef int (*ScaleAndAddVectorsWithRound)(const int16_t* in_vector1, int16_t in_vector1_scale, const int16_t* in_vector2, int16_t in_vector2_scale, int right_shifts, int16_t* out_vector, size_t length); extern const ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound; int WebRtcSpl_ScaleAndAddVectorsWithRoundC(const int16_t* in_vector1, int16_t in_vector1_scale, const int16_t* in_vector2, int16_t in_vector2_scale, int right_shifts, int16_t* out_vector, size_t length); #if defined(MIPS_DSP_R1_LE) int WebRtcSpl_ScaleAndAddVectorsWithRound_mips(const int16_t* in_vector1, int16_t in_vector1_scale, const int16_t* in_vector2, int16_t in_vector2_scale, int right_shifts, int16_t* out_vector, size_t length); #endif // End: Vector scaling operations. // iLBC specific functions. Implementations in ilbc_specific_functions.c. // Description at bottom of file. void WebRtcSpl_ReverseOrderMultArrayElements(int16_t* out_vector, const int16_t* in_vector, const int16_t* window, size_t vector_length, int16_t right_shifts); void WebRtcSpl_ElementwiseVectorMult(int16_t* out_vector, const int16_t* in_vector, const int16_t* window, size_t vector_length, int16_t right_shifts); void WebRtcSpl_AddVectorsAndShift(int16_t* out_vector, const int16_t* in_vector1, const int16_t* in_vector2, size_t vector_length, int16_t right_shifts); void WebRtcSpl_AddAffineVectorToVector(int16_t* out_vector, const int16_t* in_vector, int16_t gain, int32_t add_constant, int16_t right_shifts, size_t vector_length); void WebRtcSpl_AffineTransformVector(int16_t* out_vector, const int16_t* in_vector, int16_t gain, int32_t add_constant, int16_t right_shifts, size_t vector_length); // End: iLBC specific functions. // Signal processing operations. // A 32-bit fix-point implementation of auto-correlation computation // // Input: // - in_vector : Vector to calculate autocorrelation upon // - in_vector_length : Length (in samples) of |vector| // - order : The order up to which the autocorrelation should be // calculated // // Output: // - result : auto-correlation values (values should be seen // relative to each other since the absolute values // might have been down shifted to avoid overflow) // // - scale : The number of left shifts required to obtain the // auto-correlation in Q0 // // Return value : Number of samples in |result|, i.e. (order+1) size_t WebRtcSpl_AutoCorrelation(const int16_t* in_vector, size_t in_vector_length, size_t order, int32_t* result, int* scale); // A 32-bit fix-point implementation of the Levinson-Durbin algorithm that // does NOT use the 64 bit class // // Input: // - auto_corr : Vector with autocorrelation values of length >= |order|+1 // - order : The LPC filter order (support up to order 20) // // Output: // - lpc_coef : lpc_coef[0..order] LPC coefficients in Q12 // - refl_coef : refl_coef[0...order-1]| Reflection coefficients in Q15 // // Return value : 1 for stable 0 for unstable int16_t WebRtcSpl_LevinsonDurbin(const int32_t* auto_corr, int16_t* lpc_coef, int16_t* refl_coef, size_t order); // Converts reflection coefficients |refl_coef| to LPC coefficients |lpc_coef|. // This version is a 16 bit operation. // // NOTE: The 16 bit refl_coef -> lpc_coef conversion might result in a // "slightly unstable" filter (i.e., a pole just outside the unit circle) in // "rare" cases even if the reflection coefficients are stable. // // Input: // - refl_coef : Reflection coefficients in Q15 that should be converted // to LPC coefficients // - use_order : Number of coefficients in |refl_coef| // // Output: // - lpc_coef : LPC coefficients in Q12 void WebRtcSpl_ReflCoefToLpc(const int16_t* refl_coef, int use_order, int16_t* lpc_coef); // Converts LPC coefficients |lpc_coef| to reflection coefficients |refl_coef|. // This version is a 16 bit operation. // The conversion is implemented by the step-down algorithm. // // Input: // - lpc_coef : LPC coefficients in Q12, that should be converted to // reflection coefficients // - use_order : Number of coefficients in |lpc_coef| // // Output: // - refl_coef : Reflection coefficients in Q15. void WebRtcSpl_LpcToReflCoef(int16_t* lpc_coef, int use_order, int16_t* refl_coef); // Calculates reflection coefficients (16 bit) from auto-correlation values // // Input: // - auto_corr : Auto-correlation values // - use_order : Number of coefficients wanted be calculated // // Output: // - refl_coef : Reflection coefficients in Q15. void WebRtcSpl_AutoCorrToReflCoef(const int32_t* auto_corr, int use_order, int16_t* refl_coef); // The functions (with related pointer) calculate the cross-correlation between // two sequences |seq1| and |seq2|. // |seq1| is fixed and |seq2| slides as the pointer is increased with the // amount |step_seq2|. Note the arguments should obey the relationship: // |dim_seq| - 1 + |step_seq2| * (|dim_cross_correlation| - 1) < // buffer size of |seq2| // // Input: // - seq1 : First sequence (fixed throughout the correlation) // - seq2 : Second sequence (slides |step_vector2| for each // new correlation) // - dim_seq : Number of samples to use in the cross-correlation // - dim_cross_correlation : Number of cross-correlations to calculate (the // start position for |vector2| is updated for each // new one) // - right_shifts : Number of right bit shifts to use. This will // become the output Q-domain. // - step_seq2 : How many (positive or negative) steps the // |vector2| pointer should be updated for each new // cross-correlation value. // // Output: // - cross_correlation : The cross-correlation in Q(-right_shifts) typedef void (*CrossCorrelation)(int32_t* cross_correlation, const int16_t* seq1, const int16_t* seq2, size_t dim_seq, size_t dim_cross_correlation, int right_shifts, int step_seq2); extern const CrossCorrelation WebRtcSpl_CrossCorrelation; void WebRtcSpl_CrossCorrelationC(int32_t* cross_correlation, const int16_t* seq1, const int16_t* seq2, size_t dim_seq, size_t dim_cross_correlation, int right_shifts, int step_seq2); #if defined(WEBRTC_HAS_NEON) void WebRtcSpl_CrossCorrelationNeon(int32_t* cross_correlation, const int16_t* seq1, const int16_t* seq2, size_t dim_seq, size_t dim_cross_correlation, int right_shifts, int step_seq2); #endif #if defined(MIPS32_LE) void WebRtcSpl_CrossCorrelation_mips(int32_t* cross_correlation, const int16_t* seq1, const int16_t* seq2, size_t dim_seq, size_t dim_cross_correlation, int right_shifts, int step_seq2); #endif // Creates (the first half of) a Hanning window. Size must be at least 1 and // at most 512. // // Input: // - size : Length of the requested Hanning window (1 to 512) // // Output: // - window : Hanning vector in Q14. void WebRtcSpl_GetHanningWindow(int16_t* window, size_t size); // Calculates y[k] = sqrt(1 - x[k]^2) for each element of the input vector // |in_vector|. Input and output values are in Q15. // // Inputs: // - in_vector : Values to calculate sqrt(1 - x^2) of // - vector_length : Length of vector |in_vector| // // Output: // - out_vector : Output values in Q15 void WebRtcSpl_SqrtOfOneMinusXSquared(int16_t* in_vector, size_t vector_length, int16_t* out_vector); // End: Signal processing operations. // Randomization functions. Implementations collected in // randomization_functions.c and descriptions at bottom of this file. int16_t WebRtcSpl_RandU(uint32_t* seed); int16_t WebRtcSpl_RandN(uint32_t* seed); int16_t WebRtcSpl_RandUArray(int16_t* vector, int16_t vector_length, uint32_t* seed); // End: Randomization functions. // Math functions int32_t WebRtcSpl_Sqrt(int32_t value); // Divisions. Implementations collected in division_operations.c and // descriptions at bottom of this file. uint32_t WebRtcSpl_DivU32U16(uint32_t num, uint16_t den); int32_t WebRtcSpl_DivW32W16(int32_t num, int16_t den); int16_t WebRtcSpl_DivW32W16ResW16(int32_t num, int16_t den); int32_t WebRtcSpl_DivResultInQ31(int32_t num, int32_t den); int32_t WebRtcSpl_DivW32HiLow(int32_t num, int16_t den_hi, int16_t den_low); // End: Divisions. int32_t WebRtcSpl_Energy(int16_t* vector, size_t vector_length, int* scale_factor); // Filter operations. size_t WebRtcSpl_FilterAR(const int16_t* ar_coef, size_t ar_coef_length, const int16_t* in_vector, size_t in_vector_length, int16_t* filter_state, size_t filter_state_length, int16_t* filter_state_low, size_t filter_state_low_length, int16_t* out_vector, int16_t* out_vector_low, size_t out_vector_low_length); // WebRtcSpl_FilterMAFastQ12(...) // // Performs a MA filtering on a vector in Q12 // // Input: // - in_vector : Input samples (state in positions // in_vector[-order] .. in_vector[-1]) // - ma_coef : Filter coefficients (in Q12) // - ma_coef_length : Number of B coefficients (order+1) // - vector_length : Number of samples to be filtered // // Output: // - out_vector : Filtered samples // void WebRtcSpl_FilterMAFastQ12(const int16_t* in_vector, int16_t* out_vector, const int16_t* ma_coef, size_t ma_coef_length, size_t vector_length); // Performs a AR filtering on a vector in Q12 // Input: // - data_in : Input samples // - data_out : State information in positions // data_out[-order] .. data_out[-1] // - coefficients : Filter coefficients (in Q12) // - coefficients_length: Number of coefficients (order+1) // - data_length : Number of samples to be filtered // Output: // - data_out : Filtered samples void WebRtcSpl_FilterARFastQ12(const int16_t* data_in, int16_t* data_out, const int16_t* __restrict coefficients, size_t coefficients_length, size_t data_length); // The functions (with related pointer) perform a MA down sampling filter // on a vector. // Input: // - data_in : Input samples (state in positions // data_in[-order] .. data_in[-1]) // - data_in_length : Number of samples in |data_in| to be filtered. // This must be at least // |delay| + |factor|*(|out_vector_length|-1) + 1) // - data_out_length : Number of down sampled samples desired // - coefficients : Filter coefficients (in Q12) // - coefficients_length: Number of coefficients (order+1) // - factor : Decimation factor // - delay : Delay of filter (compensated for in out_vector) // Output: // - data_out : Filtered samples // Return value : 0 if OK, -1 if |in_vector| is too short typedef int (*DownsampleFast)(const int16_t* data_in, size_t data_in_length, int16_t* data_out, size_t data_out_length, const int16_t* __restrict coefficients, size_t coefficients_length, int factor, size_t delay); extern const DownsampleFast WebRtcSpl_DownsampleFast; int WebRtcSpl_DownsampleFastC(const int16_t* data_in, size_t data_in_length, int16_t* data_out, size_t data_out_length, const int16_t* __restrict coefficients, size_t coefficients_length, int factor, size_t delay); #if defined(WEBRTC_HAS_NEON) int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in, size_t data_in_length, int16_t* data_out, size_t data_out_length, const int16_t* __restrict coefficients, size_t coefficients_length, int factor, size_t delay); #endif #if defined(MIPS32_LE) int WebRtcSpl_DownsampleFast_mips(const int16_t* data_in, size_t data_in_length, int16_t* data_out, size_t data_out_length, const int16_t* __restrict coefficients, size_t coefficients_length, int factor, size_t delay); #endif // End: Filter operations. // FFT operations int WebRtcSpl_ComplexFFT(int16_t vector[], int stages, int mode); int WebRtcSpl_ComplexIFFT(int16_t vector[], int stages, int mode); // Treat a 16-bit complex data buffer |complex_data| as an array of 32-bit // values, and swap elements whose indexes are bit-reverses of each other. // // Input: // - complex_data : Complex data buffer containing 2^|stages| real // elements interleaved with 2^|stages| imaginary // elements: [Re Im Re Im Re Im....] // - stages : Number of FFT stages. Must be at least 3 and at most // 10, since the table WebRtcSpl_kSinTable1024[] is 1024 // elements long. // // Output: // - complex_data : The complex data buffer. void WebRtcSpl_ComplexBitReverse(int16_t* __restrict complex_data, int stages); // End: FFT operations /************************************************************ * * RESAMPLING FUNCTIONS AND THEIR STRUCTS ARE DEFINED BELOW * ************************************************************/ /******************************************************************* * resample.c * * Includes the following resampling combinations * 22 kHz -> 16 kHz * 16 kHz -> 22 kHz * 22 kHz -> 8 kHz * 8 kHz -> 22 kHz * ******************************************************************/ // state structure for 22 -> 16 resampler typedef struct { int32_t S_22_44[8]; int32_t S_44_32[8]; int32_t S_32_16[8]; } WebRtcSpl_State22khzTo16khz; void WebRtcSpl_Resample22khzTo16khz(const int16_t* in, int16_t* out, WebRtcSpl_State22khzTo16khz* state, int32_t* tmpmem); void WebRtcSpl_ResetResample22khzTo16khz(WebRtcSpl_State22khzTo16khz* state); // state structure for 16 -> 22 resampler typedef struct { int32_t S_16_32[8]; int32_t S_32_22[8]; } WebRtcSpl_State16khzTo22khz; void WebRtcSpl_Resample16khzTo22khz(const int16_t* in, int16_t* out, WebRtcSpl_State16khzTo22khz* state, int32_t* tmpmem); void WebRtcSpl_ResetResample16khzTo22khz(WebRtcSpl_State16khzTo22khz* state); // state structure for 22 -> 8 resampler typedef struct { int32_t S_22_22[16]; int32_t S_22_16[8]; int32_t S_16_8[8]; } WebRtcSpl_State22khzTo8khz; void WebRtcSpl_Resample22khzTo8khz(const int16_t* in, int16_t* out, WebRtcSpl_State22khzTo8khz* state, int32_t* tmpmem); void WebRtcSpl_ResetResample22khzTo8khz(WebRtcSpl_State22khzTo8khz* state); // state structure for 8 -> 22 resampler typedef struct { int32_t S_8_16[8]; int32_t S_16_11[8]; int32_t S_11_22[8]; } WebRtcSpl_State8khzTo22khz; void WebRtcSpl_Resample8khzTo22khz(const int16_t* in, int16_t* out, WebRtcSpl_State8khzTo22khz* state, int32_t* tmpmem); void WebRtcSpl_ResetResample8khzTo22khz(WebRtcSpl_State8khzTo22khz* state); /******************************************************************* * resample_fractional.c * Functions for internal use in the other resample functions * * Includes the following resampling combinations * 48 kHz -> 32 kHz * 32 kHz -> 24 kHz * 44 kHz -> 32 kHz * ******************************************************************/ void WebRtcSpl_Resample48khzTo32khz(const int32_t* In, int32_t* Out, size_t K); void WebRtcSpl_Resample32khzTo24khz(const int32_t* In, int32_t* Out, size_t K); void WebRtcSpl_Resample44khzTo32khz(const int32_t* In, int32_t* Out, size_t K); /******************************************************************* * resample_48khz.c * * Includes the following resampling combinations * 48 kHz -> 16 kHz * 16 kHz -> 48 kHz * 48 kHz -> 8 kHz * 8 kHz -> 48 kHz * ******************************************************************/ typedef struct { int32_t S_48_48[16]; int32_t S_48_32[8]; int32_t S_32_16[8]; } WebRtcSpl_State48khzTo16khz; void WebRtcSpl_Resample48khzTo16khz(const int16_t* in, int16_t* out, WebRtcSpl_State48khzTo16khz* state, int32_t* tmpmem); void WebRtcSpl_ResetResample48khzTo16khz(WebRtcSpl_State48khzTo16khz* state); typedef struct { int32_t S_16_32[8]; int32_t S_32_24[8]; int32_t S_24_48[8]; } WebRtcSpl_State16khzTo48khz; void WebRtcSpl_Resample16khzTo48khz(const int16_t* in, int16_t* out, WebRtcSpl_State16khzTo48khz* state, int32_t* tmpmem); void WebRtcSpl_ResetResample16khzTo48khz(WebRtcSpl_State16khzTo48khz* state); typedef struct { int32_t S_48_24[8]; int32_t S_24_24[16]; int32_t S_24_16[8]; int32_t S_16_8[8]; } WebRtcSpl_State48khzTo8khz; void WebRtcSpl_Resample48khzTo8khz(const int16_t* in, int16_t* out, WebRtcSpl_State48khzTo8khz* state, int32_t* tmpmem); void WebRtcSpl_ResetResample48khzTo8khz(WebRtcSpl_State48khzTo8khz* state); typedef struct { int32_t S_8_16[8]; int32_t S_16_12[8]; int32_t S_12_24[8]; int32_t S_24_48[8]; } WebRtcSpl_State8khzTo48khz; void WebRtcSpl_Resample8khzTo48khz(const int16_t* in, int16_t* out, WebRtcSpl_State8khzTo48khz* state, int32_t* tmpmem); void WebRtcSpl_ResetResample8khzTo48khz(WebRtcSpl_State8khzTo48khz* state); /******************************************************************* * resample_by_2.c * * Includes down and up sampling by a factor of two. * ******************************************************************/ void WebRtcSpl_DownsampleBy2(const int16_t* in, size_t len, int16_t* out, int32_t* filtState); void WebRtcSpl_UpsampleBy2(const int16_t* in, size_t len, int16_t* out, int32_t* filtState); /************************************************************ * END OF RESAMPLING FUNCTIONS ************************************************************/ void WebRtcSpl_AnalysisQMF(const int16_t* in_data, size_t in_data_length, int16_t* low_band, int16_t* high_band, int32_t* filter_state1, int32_t* filter_state2); void WebRtcSpl_SynthesisQMF(const int16_t* low_band, const int16_t* high_band, size_t band_length, int16_t* out_data, int32_t* filter_state1, int32_t* filter_state2); #ifdef __cplusplus } #endif // __cplusplus #endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SIGNAL_PROCESSING_LIBRARY_H_ // // WebRtcSpl_AddSatW16(...) // WebRtcSpl_AddSatW32(...) // // Returns the result of a saturated 16-bit, respectively 32-bit, addition of // the numbers specified by the |var1| and |var2| parameters. // // Input: // - var1 : Input variable 1 // - var2 : Input variable 2 // // Return value : Added and saturated value // // // WebRtcSpl_SubSatW16(...) // WebRtcSpl_SubSatW32(...) // // Returns the result of a saturated 16-bit, respectively 32-bit, subtraction // of the numbers specified by the |var1| and |var2| parameters. // // Input: // - var1 : Input variable 1 // - var2 : Input variable 2 // // Returned value : Subtracted and saturated value // // // WebRtcSpl_GetSizeInBits(...) // // Returns the # of bits that are needed at the most to represent the number // specified by the |value| parameter. // // Input: // - value : Input value // // Return value : Number of bits needed to represent |value| // // // WebRtcSpl_NormW32(...) // // Norm returns the # of left shifts required to 32-bit normalize the 32-bit // signed number specified by the |value| parameter. // // Input: // - value : Input value // // Return value : Number of bit shifts needed to 32-bit normalize |value| // // // WebRtcSpl_NormW16(...) // // Norm returns the # of left shifts required to 16-bit normalize the 16-bit // signed number specified by the |value| parameter. // // Input: // - value : Input value // // Return value : Number of bit shifts needed to 32-bit normalize |value| // // // WebRtcSpl_NormU32(...) // // Norm returns the # of left shifts required to 32-bit normalize the unsigned // 32-bit number specified by the |value| parameter. // // Input: // - value : Input value // // Return value : Number of bit shifts needed to 32-bit normalize |value| // // // WebRtcSpl_GetScalingSquare(...) // // Returns the # of bits required to scale the samples specified in the // |in_vector| parameter so that, if the squares of the samples are added the // # of times specified by the |times| parameter, the 32-bit addition will not // overflow (result in int32_t). // // Input: // - in_vector : Input vector to check scaling on // - in_vector_length : Samples in |in_vector| // - times : Number of additions to be performed // // Return value : Number of right bit shifts needed to avoid // overflow in the addition calculation // // // WebRtcSpl_MemSetW16(...) // // Sets all the values in the int16_t vector |vector| of length // |vector_length| to the specified value |set_value| // // Input: // - vector : Pointer to the int16_t vector // - set_value : Value specified // - vector_length : Length of vector // // // WebRtcSpl_MemSetW32(...) // // Sets all the values in the int32_t vector |vector| of length // |vector_length| to the specified value |set_value| // // Input: // - vector : Pointer to the int16_t vector // - set_value : Value specified // - vector_length : Length of vector // // // WebRtcSpl_MemCpyReversedOrder(...) // // Copies all the values from the source int16_t vector |in_vector| to a // destination int16_t vector |out_vector|. It is done in reversed order, // meaning that the first sample of |in_vector| is copied to the last sample of // the |out_vector|. The procedure continues until the last sample of // |in_vector| has been copied to the first sample of |out_vector|. This // creates a reversed vector. Used in e.g. prediction in iLBC. // // Input: // - in_vector : Pointer to the first sample in a int16_t vector // of length |length| // - vector_length : Number of elements to copy // // Output: // - out_vector : Pointer to the last sample in a int16_t vector // of length |length| // // // WebRtcSpl_CopyFromEndW16(...) // // Copies the rightmost |samples| of |in_vector| (of length |in_vector_length|) // to the vector |out_vector|. // // Input: // - in_vector : Input vector // - in_vector_length : Number of samples in |in_vector| // - samples : Number of samples to extract (from right side) // from |in_vector| // // Output: // - out_vector : Vector with the requested samples // // // WebRtcSpl_ZerosArrayW16(...) // WebRtcSpl_ZerosArrayW32(...) // // Inserts the value "zero" in all positions of a w16 and a w32 vector // respectively. // // Input: // - vector_length : Number of samples in vector // // Output: // - vector : Vector containing all zeros // // // WebRtcSpl_VectorBitShiftW16(...) // WebRtcSpl_VectorBitShiftW32(...) // // Bit shifts all the values in a vector up or downwards. Different calls for // int16_t and int32_t vectors respectively. // // Input: // - vector_length : Length of vector // - in_vector : Pointer to the vector that should be bit shifted // - right_shifts : Number of right bit shifts (negative value gives left // shifts) // // Output: // - out_vector : Pointer to the result vector (can be the same as // |in_vector|) // // // WebRtcSpl_VectorBitShiftW32ToW16(...) // // Bit shifts all the values in a int32_t vector up or downwards and // stores the result as an int16_t vector. The function will saturate the // signal if needed, before storing in the output vector. // // Input: // - vector_length : Length of vector // - in_vector : Pointer to the vector that should be bit shifted // - right_shifts : Number of right bit shifts (negative value gives left // shifts) // // Output: // - out_vector : Pointer to the result vector (can be the same as // |in_vector|) // // // WebRtcSpl_ScaleVector(...) // // Performs the vector operation: // out_vector[k] = (gain*in_vector[k])>>right_shifts // // Input: // - in_vector : Input vector // - gain : Scaling gain // - vector_length : Elements in the |in_vector| // - right_shifts : Number of right bit shifts applied // // Output: // - out_vector : Output vector (can be the same as |in_vector|) // // // WebRtcSpl_ScaleVectorWithSat(...) // // Performs the vector operation: // out_vector[k] = SATURATE( (gain*in_vector[k])>>right_shifts ) // // Input: // - in_vector : Input vector // - gain : Scaling gain // - vector_length : Elements in the |in_vector| // - right_shifts : Number of right bit shifts applied // // Output: // - out_vector : Output vector (can be the same as |in_vector|) // // // WebRtcSpl_ScaleAndAddVectors(...) // // Performs the vector operation: // out_vector[k] = (gain1*in_vector1[k])>>right_shifts1 // + (gain2*in_vector2[k])>>right_shifts2 // // Input: // - in_vector1 : Input vector 1 // - gain1 : Gain to be used for vector 1 // - right_shifts1 : Right bit shift to be used for vector 1 // - in_vector2 : Input vector 2 // - gain2 : Gain to be used for vector 2 // - right_shifts2 : Right bit shift to be used for vector 2 // - vector_length : Elements in the input vectors // // Output: // - out_vector : Output vector // // // WebRtcSpl_ReverseOrderMultArrayElements(...) // // Performs the vector operation: // out_vector[n] = (in_vector[n]*window[-n])>>right_shifts // // Input: // - in_vector : Input vector // - window : Window vector (should be reversed). The pointer // should be set to the last value in the vector // - right_shifts : Number of right bit shift to be applied after the // multiplication // - vector_length : Number of elements in |in_vector| // // Output: // - out_vector : Output vector (can be same as |in_vector|) // // // WebRtcSpl_ElementwiseVectorMult(...) // // Performs the vector operation: // out_vector[n] = (in_vector[n]*window[n])>>right_shifts // // Input: // - in_vector : Input vector // - window : Window vector. // - right_shifts : Number of right bit shift to be applied after the // multiplication // - vector_length : Number of elements in |in_vector| // // Output: // - out_vector : Output vector (can be same as |in_vector|) // // // WebRtcSpl_AddVectorsAndShift(...) // // Performs the vector operation: // out_vector[k] = (in_vector1[k] + in_vector2[k])>>right_shifts // // Input: // - in_vector1 : Input vector 1 // - in_vector2 : Input vector 2 // - right_shifts : Number of right bit shift to be applied after the // multiplication // - vector_length : Number of elements in |in_vector1| and |in_vector2| // // Output: // - out_vector : Output vector (can be same as |in_vector1|) // // // WebRtcSpl_AddAffineVectorToVector(...) // // Adds an affine transformed vector to another vector |out_vector|, i.e, // performs // out_vector[k] += (in_vector[k]*gain+add_constant)>>right_shifts // // Input: // - in_vector : Input vector // - gain : Gain value, used to multiply the in vector with // - add_constant : Constant value to add (usually 1<<(right_shifts-1), // but others can be used as well // - right_shifts : Number of right bit shifts (0-16) // - vector_length : Number of samples in |in_vector| and |out_vector| // // Output: // - out_vector : Vector with the output // // // WebRtcSpl_AffineTransformVector(...) // // Affine transforms a vector, i.e, performs // out_vector[k] = (in_vector[k]*gain+add_constant)>>right_shifts // // Input: // - in_vector : Input vector // - gain : Gain value, used to multiply the in vector with // - add_constant : Constant value to add (usually 1<<(right_shifts-1), // but others can be used as well // - right_shifts : Number of right bit shifts (0-16) // - vector_length : Number of samples in |in_vector| and |out_vector| // // Output: // - out_vector : Vector with the output // // // WebRtcSpl_IncreaseSeed(...) // // Increases the seed (and returns the new value) // // Input: // - seed : Seed for random calculation // // Output: // - seed : Updated seed value // // Return value : The new seed value // // // WebRtcSpl_RandU(...) // // Produces a uniformly distributed value in the int16_t range // // Input: // - seed : Seed for random calculation // // Output: // - seed : Updated seed value // // Return value : Uniformly distributed value in the range // [Word16_MIN...Word16_MAX] // // // WebRtcSpl_RandN(...) // // Produces a normal distributed value in the int16_t range // // Input: // - seed : Seed for random calculation // // Output: // - seed : Updated seed value // // Return value : N(0,1) value in the Q13 domain // // // WebRtcSpl_RandUArray(...) // // Produces a uniformly distributed vector with elements in the int16_t // range // // Input: // - vector_length : Samples wanted in the vector // - seed : Seed for random calculation // // Output: // - vector : Vector with the uniform values // - seed : Updated seed value // // Return value : Number of samples in vector, i.e., |vector_length| // // // WebRtcSpl_Sqrt(...) // // Returns the square root of the input value |value|. The precision of this // function is integer precision, i.e., sqrt(8) gives 2 as answer. // If |value| is a negative number then 0 is returned. // // Algorithm: // // A sixth order Taylor Series expansion is used here to compute the square // root of a number y^0.5 = (1+x)^0.5 // where // x = y-1 // = 1+(x/2)-0.5*((x/2)^2+0.5*((x/2)^3-0.625*((x/2)^4+0.875*((x/2)^5) // 0.5 <= x < 1 // // Input: // - value : Value to calculate sqrt of // // Return value : Result of the sqrt calculation // // // WebRtcSpl_DivU32U16(...) // // Divides a uint32_t |num| by a uint16_t |den|. // // If |den|==0, (uint32_t)0xFFFFFFFF is returned. // // Input: // - num : Numerator // - den : Denominator // // Return value : Result of the division (as a uint32_t), i.e., the // integer part of num/den. // // // WebRtcSpl_DivW32W16(...) // // Divides a int32_t |num| by a int16_t |den|. // // If |den|==0, (int32_t)0x7FFFFFFF is returned. // // Input: // - num : Numerator // - den : Denominator // // Return value : Result of the division (as a int32_t), i.e., the // integer part of num/den. // // // WebRtcSpl_DivW32W16ResW16(...) // // Divides a int32_t |num| by a int16_t |den|, assuming that the // result is less than 32768, otherwise an unpredictable result will occur. // // If |den|==0, (int16_t)0x7FFF is returned. // // Input: // - num : Numerator // - den : Denominator // // Return value : Result of the division (as a int16_t), i.e., the // integer part of num/den. // // // WebRtcSpl_DivResultInQ31(...) // // Divides a int32_t |num| by a int16_t |den|, assuming that the // absolute value of the denominator is larger than the numerator, otherwise // an unpredictable result will occur. // // Input: // - num : Numerator // - den : Denominator // // Return value : Result of the division in Q31. // // // WebRtcSpl_DivW32HiLow(...) // // Divides a int32_t |num| by a denominator in hi, low format. The // absolute value of the denominator has to be larger (or equal to) the // numerator. // // Input: // - num : Numerator // - den_hi : High part of denominator // - den_low : Low part of denominator // // Return value : Divided value in Q31 // // // WebRtcSpl_Energy(...) // // Calculates the energy of a vector // // Input: // - vector : Vector which the energy should be calculated on // - vector_length : Number of samples in vector // // Output: // - scale_factor : Number of left bit shifts needed to get the physical // energy value, i.e, to get the Q0 value // // Return value : Energy value in Q(-|scale_factor|) // // // WebRtcSpl_FilterAR(...) // // Performs a 32-bit AR filtering on a vector in Q12 // // Input: // - ar_coef : AR-coefficient vector (values in Q12), // ar_coef[0] must be 4096. // - ar_coef_length : Number of coefficients in |ar_coef|. // - in_vector : Vector to be filtered. // - in_vector_length : Number of samples in |in_vector|. // - filter_state : Current state (higher part) of the filter. // - filter_state_length : Length (in samples) of |filter_state|. // - filter_state_low : Current state (lower part) of the filter. // - filter_state_low_length : Length (in samples) of |filter_state_low|. // - out_vector_low_length : Maximum length (in samples) of // |out_vector_low|. // // Output: // - filter_state : Updated state (upper part) vector. // - filter_state_low : Updated state (lower part) vector. // - out_vector : Vector containing the upper part of the // filtered values. // - out_vector_low : Vector containing the lower part of the // filtered values. // // Return value : Number of samples in the |out_vector|. // // // WebRtcSpl_ComplexIFFT(...) // // Complex Inverse FFT // // Computes an inverse complex 2^|stages|-point FFT on the input vector, which // is in bit-reversed order. The original content of the vector is destroyed in // the process, since the input is overwritten by the output, normal-ordered, // FFT vector. With X as the input complex vector, y as the output complex // vector and with M = 2^|stages|, the following is computed: // // M-1 // y(k) = sum[X(i)*[cos(2*pi*i*k/M) + j*sin(2*pi*i*k/M)]] // i=0 // // The implementations are optimized for speed, not for code size. It uses the // decimation-in-time algorithm with radix-2 butterfly technique. // // Input: // - vector : In pointer to complex vector containing 2^|stages| // real elements interleaved with 2^|stages| imaginary // elements. // [ReImReImReIm....] // The elements are in Q(-scale) domain, see more on Return // Value below. // // - stages : Number of FFT stages. Must be at least 3 and at most 10, // since the table WebRtcSpl_kSinTable1024[] is 1024 // elements long. // // - mode : This parameter gives the user to choose how the FFT // should work. // mode==0: Low-complexity and Low-accuracy mode // mode==1: High-complexity and High-accuracy mode // // Output: // - vector : Out pointer to the FFT vector (the same as input). // // Return Value : The scale value that tells the number of left bit shifts // that the elements in the |vector| should be shifted with // in order to get Q0 values, i.e. the physically correct // values. The scale parameter is always 0 or positive, // except if N>1024 (|stages|>10), which returns a scale // value of -1, indicating error. // // // WebRtcSpl_ComplexFFT(...) // // Complex FFT // // Computes a complex 2^|stages|-point FFT on the input vector, which is in // bit-reversed order. The original content of the vector is destroyed in // the process, since the input is overwritten by the output, normal-ordered, // FFT vector. With x as the input complex vector, Y as the output complex // vector and with M = 2^|stages|, the following is computed: // // M-1 // Y(k) = 1/M * sum[x(i)*[cos(2*pi*i*k/M) + j*sin(2*pi*i*k/M)]] // i=0 // // The implementations are optimized for speed, not for code size. It uses the // decimation-in-time algorithm with radix-2 butterfly technique. // // This routine prevents overflow by scaling by 2 before each FFT stage. This is // a fixed scaling, for proper normalization - there will be log2(n) passes, so // this results in an overall factor of 1/n, distributed to maximize arithmetic // accuracy. // // Input: // - vector : In pointer to complex vector containing 2^|stages| real // elements interleaved with 2^|stages| imaginary elements. // [ReImReImReIm....] // The output is in the Q0 domain. // // - stages : Number of FFT stages. Must be at least 3 and at most 10, // since the table WebRtcSpl_kSinTable1024[] is 1024 // elements long. // // - mode : This parameter gives the user to choose how the FFT // should work. // mode==0: Low-complexity and Low-accuracy mode // mode==1: High-complexity and High-accuracy mode // // Output: // - vector : The output FFT vector is in the Q0 domain. // // Return value : The scale parameter is always 0, except if N>1024, // which returns a scale value of -1, indicating error. // // // WebRtcSpl_AnalysisQMF(...) // // Splits a 0-2*F Hz signal into two sub bands: 0-F Hz and F-2*F Hz. The // current version has F = 8000, therefore, a super-wideband audio signal is // split to lower-band 0-8 kHz and upper-band 8-16 kHz. // // Input: // - in_data : Wide band speech signal, 320 samples (10 ms) // // Input & Output: // - filter_state1 : Filter state for first All-pass filter // - filter_state2 : Filter state for second All-pass filter // // Output: // - low_band : Lower-band signal 0-8 kHz band, 160 samples (10 ms) // - high_band : Upper-band signal 8-16 kHz band (flipped in frequency // domain), 160 samples (10 ms) // // // WebRtcSpl_SynthesisQMF(...) // // Combines the two sub bands (0-F and F-2*F Hz) into a signal of 0-2*F // Hz, (current version has F = 8000 Hz). So the filter combines lower-band // (0-8 kHz) and upper-band (8-16 kHz) channels to obtain super-wideband 0-16 // kHz audio. // // Input: // - low_band : The signal with the 0-8 kHz band, 160 samples (10 ms) // - high_band : The signal with the 8-16 kHz band, 160 samples (10 ms) // // Input & Output: // - filter_state1 : Filter state for first All-pass filter // - filter_state2 : Filter state for second All-pass filter // // Output: // - out_data : Super-wideband speech signal, 0-16 kHz // // int16_t WebRtcSpl_SatW32ToW16(...) // // This function saturates a 32-bit word into a 16-bit word. // // Input: // - value32 : The value of a 32-bit word. // // Output: // - out16 : the saturated 16-bit word. // // int32_t WebRtc_MulAccumW16(...) // // This function multiply a 16-bit word by a 16-bit word, and accumulate this // value to a 32-bit integer. // // Input: // - a : The value of the first 16-bit word. // - b : The value of the second 16-bit word. // - c : The value of an 32-bit integer. // // Return Value: The value of a * b + c. // ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/include/spl_inl.h0000664000175000017500000001231214475643423027571 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // This header file includes the inline functions in // the fix point signal processing library. #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_H_ #define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_H_ #include "rtc_base/compile_assert_c.h" extern const int8_t kWebRtcSpl_CountLeadingZeros32_Table[64]; // Don't call this directly except in tests! static __inline int WebRtcSpl_CountLeadingZeros32_NotBuiltin(uint32_t n) { // Normalize n by rounding up to the nearest number that is a sequence of 0 // bits followed by a sequence of 1 bits. This number has the same number of // leading zeros as the original n. There are exactly 33 such values. n |= n >> 1; n |= n >> 2; n |= n >> 4; n |= n >> 8; n |= n >> 16; // Multiply the modified n with a constant selected (by exhaustive search) // such that each of the 33 possible values of n give a product whose 6 most // significant bits are unique. Then look up the answer in the table. return kWebRtcSpl_CountLeadingZeros32_Table[(n * 0x8c0b2891) >> 26]; } // Don't call this directly except in tests! static __inline int WebRtcSpl_CountLeadingZeros64_NotBuiltin(uint64_t n) { const int leading_zeros = n >> 32 == 0 ? 32 : 0; return leading_zeros + WebRtcSpl_CountLeadingZeros32_NotBuiltin( (uint32_t)(n >> (32 - leading_zeros))); } // Returns the number of leading zero bits in the argument. static __inline int WebRtcSpl_CountLeadingZeros32(uint32_t n) { #ifdef __GNUC__ RTC_COMPILE_ASSERT(sizeof(unsigned int) == sizeof(uint32_t)); return n == 0 ? 32 : __builtin_clz(n); #else return WebRtcSpl_CountLeadingZeros32_NotBuiltin(n); #endif } // Returns the number of leading zero bits in the argument. static __inline int WebRtcSpl_CountLeadingZeros64(uint64_t n) { #ifdef __GNUC__ RTC_COMPILE_ASSERT(sizeof(unsigned long long) == sizeof(uint64_t)); // NOLINT return n == 0 ? 64 : __builtin_clzll(n); #else return WebRtcSpl_CountLeadingZeros64_NotBuiltin(n); #endif } #ifdef WEBRTC_ARCH_ARM_V7 #include "common_audio/signal_processing/include/spl_inl_armv7.h" #else #if defined(MIPS32_LE) #include "common_audio/signal_processing/include/spl_inl_mips.h" #endif #if !defined(MIPS_DSP_R1_LE) static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) { int16_t out16 = (int16_t)value32; if (value32 > 32767) out16 = 32767; else if (value32 < -32768) out16 = -32768; return out16; } static __inline int32_t WebRtcSpl_AddSatW32(int32_t a, int32_t b) { // Do the addition in unsigned numbers, since signed overflow is undefined // behavior. const int32_t sum = (int32_t)((uint32_t)a + (uint32_t)b); // a + b can't overflow if a and b have different signs. If they have the // same sign, a + b also has the same sign iff it didn't overflow. if ((a < 0) == (b < 0) && (a < 0) != (sum < 0)) { // The direction of the overflow is obvious from the sign of a + b. return sum < 0 ? INT32_MAX : INT32_MIN; } return sum; } static __inline int32_t WebRtcSpl_SubSatW32(int32_t a, int32_t b) { // Do the subtraction in unsigned numbers, since signed overflow is undefined // behavior. const int32_t diff = (int32_t)((uint32_t)a - (uint32_t)b); // a - b can't overflow if a and b have the same sign. If they have different // signs, a - b has the same sign as a iff it didn't overflow. if ((a < 0) != (b < 0) && (a < 0) != (diff < 0)) { // The direction of the overflow is obvious from the sign of a - b. return diff < 0 ? INT32_MAX : INT32_MIN; } return diff; } static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) { return WebRtcSpl_SatW32ToW16((int32_t)a + (int32_t)b); } static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) { return WebRtcSpl_SatW32ToW16((int32_t)var1 - (int32_t)var2); } #endif // #if !defined(MIPS_DSP_R1_LE) #if !defined(MIPS32_LE) static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) { return 32 - WebRtcSpl_CountLeadingZeros32(n); } // Return the number of steps a can be left-shifted without overflow, // or 0 if a == 0. static __inline int16_t WebRtcSpl_NormW32(int32_t a) { return a == 0 ? 0 : WebRtcSpl_CountLeadingZeros32(a < 0 ? ~a : a) - 1; } // Return the number of steps a can be left-shifted without overflow, // or 0 if a == 0. static __inline int16_t WebRtcSpl_NormU32(uint32_t a) { return a == 0 ? 0 : WebRtcSpl_CountLeadingZeros32(a); } // Return the number of steps a can be left-shifted without overflow, // or 0 if a == 0. static __inline int16_t WebRtcSpl_NormW16(int16_t a) { const int32_t a32 = a; return a == 0 ? 0 : WebRtcSpl_CountLeadingZeros32(a < 0 ? ~a32 : a32) - 17; } static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) { return (a * b + c); } #endif // #if !defined(MIPS32_LE) #endif // WEBRTC_ARCH_ARM_V7 #endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/include/spl_inl_armv7.h0000664000175000017500000000663614475643423030721 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* This header file includes the inline functions for ARM processors in * the fix point signal processing library. */ #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_ARMV7_H_ #define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_ARMV7_H_ /* TODO(kma): Replace some assembly code with GCC intrinsics * (e.g. __builtin_clz). */ /* This function produces result that is not bit exact with that by the generic * C version in some cases, although the former is at least as accurate as the * later. */ static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a, int32_t b) { int32_t tmp = 0; __asm __volatile("smulwb %0, %1, %2" : "=r"(tmp) : "r"(b), "r"(a)); return tmp; } static __inline int32_t WEBRTC_SPL_MUL_16_16(int16_t a, int16_t b) { int32_t tmp = 0; __asm __volatile("smulbb %0, %1, %2" : "=r"(tmp) : "r"(a), "r"(b)); return tmp; } // TODO(kma): add unit test. static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) { int32_t tmp = 0; __asm __volatile("smlabb %0, %1, %2, %3" : "=r"(tmp) : "r"(a), "r"(b), "r"(c)); return tmp; } static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) { int32_t s_sum = 0; __asm __volatile("qadd16 %0, %1, %2" : "=r"(s_sum) : "r"(a), "r"(b)); return (int16_t)s_sum; } static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) { int32_t l_sum = 0; __asm __volatile("qadd %0, %1, %2" : "=r"(l_sum) : "r"(l_var1), "r"(l_var2)); return l_sum; } static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) { int32_t l_sub = 0; __asm __volatile("qsub %0, %1, %2" : "=r"(l_sub) : "r"(l_var1), "r"(l_var2)); return l_sub; } static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) { int32_t s_sub = 0; __asm __volatile("qsub16 %0, %1, %2" : "=r"(s_sub) : "r"(var1), "r"(var2)); return (int16_t)s_sub; } static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) { int32_t tmp = 0; __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(n)); return (int16_t)(32 - tmp); } static __inline int16_t WebRtcSpl_NormW32(int32_t a) { int32_t tmp = 0; if (a == 0) { return 0; } else if (a < 0) { a ^= 0xFFFFFFFF; } __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(a)); return (int16_t)(tmp - 1); } static __inline int16_t WebRtcSpl_NormU32(uint32_t a) { int tmp = 0; if (a == 0) return 0; __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(a)); return (int16_t)tmp; } static __inline int16_t WebRtcSpl_NormW16(int16_t a) { int32_t tmp = 0; int32_t a_32 = a; if (a_32 == 0) { return 0; } else if (a_32 < 0) { a_32 ^= 0xFFFFFFFF; } __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(a_32)); return (int16_t)(tmp - 17); } // TODO(kma): add unit test. static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) { int32_t out = 0; __asm __volatile("ssat %0, #16, %1" : "=r"(out) : "r"(value32)); return (int16_t)out; } #endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_ARMV7_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/include/spl_inl_mips.h0000664000175000017500000001552214475643423030627 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // This header file includes the inline functions in // the fix point signal processing library. #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_MIPS_H_ #define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_MIPS_H_ static __inline int32_t WEBRTC_SPL_MUL_16_16(int32_t a, int32_t b) { int32_t value32 = 0; int32_t a1 = 0, b1 = 0; __asm __volatile( #if defined(MIPS32_R2_LE) "seh %[a1], %[a] \n\t" "seh %[b1], %[b] \n\t" #else "sll %[a1], %[a], 16 \n\t" "sll %[b1], %[b], 16 \n\t" "sra %[a1], %[a1], 16 \n\t" "sra %[b1], %[b1], 16 \n\t" #endif "mul %[value32], %[a1], %[b1] \n\t" : [value32] "=r"(value32), [a1] "=&r"(a1), [b1] "=&r"(b1) : [a] "r"(a), [b] "r"(b) : "hi", "lo"); return value32; } static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a, int32_t b) { int32_t value32 = 0, b1 = 0, b2 = 0; int32_t a1 = 0; __asm __volatile( #if defined(MIPS32_R2_LE) "seh %[a1], %[a] \n\t" #else "sll %[a1], %[a], 16 \n\t" "sra %[a1], %[a1], 16 \n\t" #endif "andi %[b2], %[b], 0xFFFF \n\t" "sra %[b1], %[b], 16 \n\t" "sra %[b2], %[b2], 1 \n\t" "mul %[value32], %[a1], %[b1] \n\t" "mul %[b2], %[a1], %[b2] \n\t" "addiu %[b2], %[b2], 0x4000 \n\t" "sra %[b2], %[b2], 15 \n\t" "addu %[value32], %[value32], %[b2] \n\t" : [value32] "=&r"(value32), [b1] "=&r"(b1), [b2] "=&r"(b2), [a1] "=&r"(a1) : [a] "r"(a), [b] "r"(b) : "hi", "lo"); return value32; } #if defined(MIPS_DSP_R1_LE) static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) { __asm __volatile( "shll_s.w %[value32], %[value32], 16 \n\t" "sra %[value32], %[value32], 16 \n\t" : [value32] "+r"(value32) :); int16_t out16 = (int16_t)value32; return out16; } static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) { int32_t value32 = 0; __asm __volatile("addq_s.ph %[value32], %[a], %[b] \n\t" : [value32] "=r"(value32) : [a] "r"(a), [b] "r"(b)); return (int16_t)value32; } static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) { int32_t l_sum; __asm __volatile( "addq_s.w %[l_sum], %[l_var1], %[l_var2] \n\t" : [l_sum] "=r"(l_sum) : [l_var1] "r"(l_var1), [l_var2] "r"(l_var2)); return l_sum; } static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) { int32_t value32; __asm __volatile("subq_s.ph %[value32], %[var1], %[var2] \n\t" : [value32] "=r"(value32) : [var1] "r"(var1), [var2] "r"(var2)); return (int16_t)value32; } static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) { int32_t l_diff; __asm __volatile( "subq_s.w %[l_diff], %[l_var1], %[l_var2] \n\t" : [l_diff] "=r"(l_diff) : [l_var1] "r"(l_var1), [l_var2] "r"(l_var2)); return l_diff; } #endif static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) { int bits = 0; int i32 = 32; __asm __volatile( "clz %[bits], %[n] \n\t" "subu %[bits], %[i32], %[bits] \n\t" : [bits] "=&r"(bits) : [n] "r"(n), [i32] "r"(i32)); return (int16_t)bits; } static __inline int16_t WebRtcSpl_NormW32(int32_t a) { int zeros = 0; __asm __volatile( ".set push \n\t" ".set noreorder \n\t" "bnez %[a], 1f \n\t" " sra %[zeros], %[a], 31 \n\t" "b 2f \n\t" " move %[zeros], $zero \n\t" "1: \n\t" "xor %[zeros], %[a], %[zeros] \n\t" "clz %[zeros], %[zeros] \n\t" "addiu %[zeros], %[zeros], -1 \n\t" "2: \n\t" ".set pop \n\t" : [zeros] "=&r"(zeros) : [a] "r"(a)); return (int16_t)zeros; } static __inline int16_t WebRtcSpl_NormU32(uint32_t a) { int zeros = 0; __asm __volatile("clz %[zeros], %[a] \n\t" : [zeros] "=r"(zeros) : [a] "r"(a)); return (int16_t)(zeros & 0x1f); } static __inline int16_t WebRtcSpl_NormW16(int16_t a) { int zeros = 0; int a0 = a << 16; __asm __volatile( ".set push \n\t" ".set noreorder \n\t" "bnez %[a0], 1f \n\t" " sra %[zeros], %[a0], 31 \n\t" "b 2f \n\t" " move %[zeros], $zero \n\t" "1: \n\t" "xor %[zeros], %[a0], %[zeros] \n\t" "clz %[zeros], %[zeros] \n\t" "addiu %[zeros], %[zeros], -1 \n\t" "2: \n\t" ".set pop \n\t" : [zeros] "=&r"(zeros) : [a0] "r"(a0)); return (int16_t)zeros; } static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) { int32_t res = 0, c1 = 0; __asm __volatile( #if defined(MIPS32_R2_LE) "seh %[a], %[a] \n\t" "seh %[b], %[b] \n\t" #else "sll %[a], %[a], 16 \n\t" "sll %[b], %[b], 16 \n\t" "sra %[a], %[a], 16 \n\t" "sra %[b], %[b], 16 \n\t" #endif "mul %[res], %[a], %[b] \n\t" "addu %[c1], %[c], %[res] \n\t" : [c1] "=r"(c1), [res] "=&r"(res) : [a] "r"(a), [b] "r"(b), [c] "r"(c) : "hi", "lo"); return (c1); } #endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_MIPS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/levinson_durbin.c0000664000175000017500000001744314475643423027713 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the function WebRtcSpl_LevinsonDurbin(). * The description header can be found in signal_processing_library.h * */ #include "common_audio/signal_processing/include/signal_processing_library.h" #include "rtc_base/sanitizer.h" #define SPL_LEVINSON_MAXORDER 20 int16_t RTC_NO_SANITIZE("signed-integer-overflow") // bugs.webrtc.org/5486 WebRtcSpl_LevinsonDurbin(const int32_t* R, int16_t* A, int16_t* K, size_t order) { size_t i, j; // Auto-correlation coefficients in high precision int16_t R_hi[SPL_LEVINSON_MAXORDER + 1], R_low[SPL_LEVINSON_MAXORDER + 1]; // LPC coefficients in high precision int16_t A_hi[SPL_LEVINSON_MAXORDER + 1], A_low[SPL_LEVINSON_MAXORDER + 1]; // LPC coefficients for next iteration int16_t A_upd_hi[SPL_LEVINSON_MAXORDER + 1], A_upd_low[SPL_LEVINSON_MAXORDER + 1]; // Reflection coefficient in high precision int16_t K_hi, K_low; // Prediction gain Alpha in high precision and with scale factor int16_t Alpha_hi, Alpha_low, Alpha_exp; int16_t tmp_hi, tmp_low; int32_t temp1W32, temp2W32, temp3W32; int16_t norm; // Normalize the autocorrelation R[0]...R[order+1] norm = WebRtcSpl_NormW32(R[0]); for (i = 0; i <= order; ++i) { temp1W32 = R[i] * (1 << norm); // UBSan: 12 * 268435456 cannot be represented in type 'int' // Put R in hi and low format R_hi[i] = (int16_t)(temp1W32 >> 16); R_low[i] = (int16_t)((temp1W32 - ((int32_t)R_hi[i] * 65536)) >> 1); } // K = A[1] = -R[1] / R[0] temp2W32 = R[1] * (1 << norm); // R[1] in Q31 temp3W32 = WEBRTC_SPL_ABS_W32(temp2W32); // abs R[1] temp1W32 = WebRtcSpl_DivW32HiLow(temp3W32, R_hi[0], R_low[0]); // abs(R[1])/R[0] in Q31 // Put back the sign on R[1] if (temp2W32 > 0) { temp1W32 = -temp1W32; } // Put K in hi and low format K_hi = (int16_t)(temp1W32 >> 16); K_low = (int16_t)((temp1W32 - ((int32_t)K_hi * 65536)) >> 1); // Store first reflection coefficient K[0] = K_hi; temp1W32 >>= 4; // A[1] in Q27. // Put A[1] in hi and low format A_hi[1] = (int16_t)(temp1W32 >> 16); A_low[1] = (int16_t)((temp1W32 - ((int32_t)A_hi[1] * 65536)) >> 1); // Alpha = R[0] * (1-K^2) temp1W32 = ((K_hi * K_low >> 14) + K_hi * K_hi) * 2; // = k^2 in Q31 temp1W32 = WEBRTC_SPL_ABS_W32(temp1W32); // Guard against <0 temp1W32 = (int32_t)0x7fffffffL - temp1W32; // temp1W32 = (1 - K[0]*K[0]) in Q31 // Store temp1W32 = 1 - K[0]*K[0] on hi and low format tmp_hi = (int16_t)(temp1W32 >> 16); tmp_low = (int16_t)((temp1W32 - ((int32_t)tmp_hi << 16)) >> 1); // Calculate Alpha in Q31 temp1W32 = (R_hi[0] * tmp_hi + (R_hi[0] * tmp_low >> 15) + (R_low[0] * tmp_hi >> 15)) << 1; // Normalize Alpha and put it in hi and low format Alpha_exp = WebRtcSpl_NormW32(temp1W32); temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, Alpha_exp); Alpha_hi = (int16_t)(temp1W32 >> 16); Alpha_low = (int16_t)((temp1W32 - ((int32_t)Alpha_hi << 16)) >> 1); // Perform the iterative calculations in the Levinson-Durbin algorithm for (i = 2; i <= order; i++) { /* ---- temp1W32 = R[i] + > R[j]*A[i-j] / ---- j=1..i-1 */ temp1W32 = 0; for (j = 1; j < i; j++) { // temp1W32 is in Q31 temp1W32 += (R_hi[j] * A_hi[i - j] * 2) + (((R_hi[j] * A_low[i - j] >> 15) + (R_low[j] * A_hi[i - j] >> 15)) * 2); } temp1W32 = temp1W32 * 16; temp1W32 += ((int32_t)R_hi[i] * 65536) + WEBRTC_SPL_LSHIFT_W32((int32_t)R_low[i], 1); // K = -temp1W32 / Alpha temp2W32 = WEBRTC_SPL_ABS_W32(temp1W32); // abs(temp1W32) temp3W32 = WebRtcSpl_DivW32HiLow(temp2W32, Alpha_hi, Alpha_low); // abs(temp1W32)/Alpha // Put the sign of temp1W32 back again if (temp1W32 > 0) { temp3W32 = -temp3W32; } // Use the Alpha shifts from earlier to de-normalize norm = WebRtcSpl_NormW32(temp3W32); if ((Alpha_exp <= norm) || (temp3W32 == 0)) { temp3W32 = temp3W32 * (1 << Alpha_exp); } else { if (temp3W32 > 0) { temp3W32 = (int32_t)0x7fffffffL; } else { temp3W32 = (int32_t)0x80000000L; } } // Put K on hi and low format K_hi = (int16_t)(temp3W32 >> 16); K_low = (int16_t)((temp3W32 - ((int32_t)K_hi * 65536)) >> 1); // Store Reflection coefficient in Q15 K[i - 1] = K_hi; // Test for unstable filter. // If unstable return 0 and let the user decide what to do in that case if ((int32_t)WEBRTC_SPL_ABS_W16(K_hi) > (int32_t)32750) { return 0; // Unstable filter } /* Compute updated LPC coefficient: Anew[i] Anew[j]= A[j] + K*A[i-j] for j=1..i-1 Anew[i]= K */ for (j = 1; j < i; j++) { // temp1W32 = A[j] in Q27 temp1W32 = (int32_t)A_hi[j] * 65536 + WEBRTC_SPL_LSHIFT_W32((int32_t)A_low[j],1); // temp1W32 += K*A[i-j] in Q27 temp1W32 += (K_hi * A_hi[i - j] + (K_hi * A_low[i - j] >> 15) + (K_low * A_hi[i - j] >> 15)) * 2; // Put Anew in hi and low format A_upd_hi[j] = (int16_t)(temp1W32 >> 16); A_upd_low[j] = (int16_t)( (temp1W32 - ((int32_t)A_upd_hi[j] * 65536)) >> 1); } // temp3W32 = K in Q27 (Convert from Q31 to Q27) temp3W32 >>= 4; // Store Anew in hi and low format A_upd_hi[i] = (int16_t)(temp3W32 >> 16); A_upd_low[i] = (int16_t)( (temp3W32 - ((int32_t)A_upd_hi[i] * 65536)) >> 1); // Alpha = Alpha * (1-K^2) temp1W32 = ((K_hi * K_low >> 14) + K_hi * K_hi) * 2; // K*K in Q31 temp1W32 = WEBRTC_SPL_ABS_W32(temp1W32); // Guard against <0 temp1W32 = (int32_t)0x7fffffffL - temp1W32; // 1 - K*K in Q31 // Convert 1- K^2 in hi and low format tmp_hi = (int16_t)(temp1W32 >> 16); tmp_low = (int16_t)((temp1W32 - ((int32_t)tmp_hi << 16)) >> 1); // Calculate Alpha = Alpha * (1-K^2) in Q31 temp1W32 = (Alpha_hi * tmp_hi + (Alpha_hi * tmp_low >> 15) + (Alpha_low * tmp_hi >> 15)) << 1; // Normalize Alpha and store it on hi and low format norm = WebRtcSpl_NormW32(temp1W32); temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, norm); Alpha_hi = (int16_t)(temp1W32 >> 16); Alpha_low = (int16_t)((temp1W32 - ((int32_t)Alpha_hi << 16)) >> 1); // Update the total normalization of Alpha Alpha_exp = Alpha_exp + norm; // Update A[] for (j = 1; j <= i; j++) { A_hi[j] = A_upd_hi[j]; A_low[j] = A_upd_low[j]; } } /* Set A[0] to 1.0 and store the A[i] i=1...order in Q12 (Convert from Q27 and use rounding) */ A[0] = 4096; for (i = 1; i <= order; i++) { // temp1W32 in Q27 temp1W32 = (int32_t)A_hi[i] * 65536 + WEBRTC_SPL_LSHIFT_W32((int32_t)A_low[i], 1); // Round and store upper word A[i] = (int16_t)(((temp1W32 * 2) + 32768) >> 16); } return 1; // Stable filters } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/lpc_to_refl_coef.c0000664000175000017500000000341514475643423027771 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the function WebRtcSpl_LpcToReflCoef(). * The description header can be found in signal_processing_library.h * */ #include "common_audio/signal_processing/include/signal_processing_library.h" #define SPL_LPC_TO_REFL_COEF_MAX_AR_MODEL_ORDER 50 void WebRtcSpl_LpcToReflCoef(int16_t* a16, int use_order, int16_t* k16) { int m, k; int32_t tmp32[SPL_LPC_TO_REFL_COEF_MAX_AR_MODEL_ORDER]; int32_t tmp_inv_denom32; int16_t tmp_inv_denom16; k16[use_order - 1] = a16[use_order] << 3; // Q12<<3 => Q15 for (m = use_order - 1; m > 0; m--) { // (1 - k^2) in Q30 tmp_inv_denom32 = 1073741823 - k16[m] * k16[m]; // (1 - k^2) in Q15 tmp_inv_denom16 = (int16_t)(tmp_inv_denom32 >> 15); for (k = 1; k <= m; k++) { // tmp[k] = (a[k] - RC[m] * a[m-k+1]) / (1.0 - RC[m]*RC[m]); // [Q12<<16 - (Q15*Q12)<<1] = [Q28 - Q28] = Q28 tmp32[k] = (a16[k] << 16) - (k16[m] * a16[m - k + 1] << 1); tmp32[k] = WebRtcSpl_DivW32W16(tmp32[k], tmp_inv_denom16); //Q28/Q15 = Q13 } for (k = 1; k < m; k++) { a16[k] = (int16_t)(tmp32[k] >> 1); // Q13>>1 => Q12 } tmp32[m] = WEBRTC_SPL_SAT(8191, tmp32[m], -8191); k16[m - 1] = (int16_t)WEBRTC_SPL_LSHIFT_W32(tmp32[m], 2); //Q13<<2 => Q15 } return; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/min_max_operations.c0000664000175000017500000001255314475643423030403 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the implementation of functions * WebRtcSpl_MaxAbsValueW16C() * WebRtcSpl_MaxAbsValueW32C() * WebRtcSpl_MaxValueW16C() * WebRtcSpl_MaxValueW32C() * WebRtcSpl_MinValueW16C() * WebRtcSpl_MinValueW32C() * WebRtcSpl_MaxAbsIndexW16() * WebRtcSpl_MaxIndexW16() * WebRtcSpl_MaxIndexW32() * WebRtcSpl_MinIndexW16() * WebRtcSpl_MinIndexW32() * */ #include #include "rtc_base/checks.h" #include "common_audio/signal_processing/include/signal_processing_library.h" // TODO(bjorn/kma): Consolidate function pairs (e.g. combine // WebRtcSpl_MaxAbsValueW16C and WebRtcSpl_MaxAbsIndexW16 into a single one.) // TODO(kma): Move the next six functions into min_max_operations_c.c. // Maximum absolute value of word16 vector. C version for generic platforms. int16_t WebRtcSpl_MaxAbsValueW16C(const int16_t* vector, size_t length) { size_t i = 0; int absolute = 0, maximum = 0; RTC_DCHECK_GT(length, 0); for (i = 0; i < length; i++) { absolute = abs((int)vector[i]); if (absolute > maximum) { maximum = absolute; } } // Guard the case for abs(-32768). if (maximum > WEBRTC_SPL_WORD16_MAX) { maximum = WEBRTC_SPL_WORD16_MAX; } return (int16_t)maximum; } // Maximum absolute value of word32 vector. C version for generic platforms. int32_t WebRtcSpl_MaxAbsValueW32C(const int32_t* vector, size_t length) { // Use uint32_t for the local variables, to accommodate the return value // of abs(0x80000000), which is 0x80000000. uint32_t absolute = 0, maximum = 0; size_t i = 0; RTC_DCHECK_GT(length, 0); for (i = 0; i < length; i++) { absolute = abs((int)vector[i]); if (absolute > maximum) { maximum = absolute; } } maximum = WEBRTC_SPL_MIN(maximum, WEBRTC_SPL_WORD32_MAX); return (int32_t)maximum; } // Maximum value of word16 vector. C version for generic platforms. int16_t WebRtcSpl_MaxValueW16C(const int16_t* vector, size_t length) { int16_t maximum = WEBRTC_SPL_WORD16_MIN; size_t i = 0; RTC_DCHECK_GT(length, 0); for (i = 0; i < length; i++) { if (vector[i] > maximum) maximum = vector[i]; } return maximum; } // Maximum value of word32 vector. C version for generic platforms. int32_t WebRtcSpl_MaxValueW32C(const int32_t* vector, size_t length) { int32_t maximum = WEBRTC_SPL_WORD32_MIN; size_t i = 0; RTC_DCHECK_GT(length, 0); for (i = 0; i < length; i++) { if (vector[i] > maximum) maximum = vector[i]; } return maximum; } // Minimum value of word16 vector. C version for generic platforms. int16_t WebRtcSpl_MinValueW16C(const int16_t* vector, size_t length) { int16_t minimum = WEBRTC_SPL_WORD16_MAX; size_t i = 0; RTC_DCHECK_GT(length, 0); for (i = 0; i < length; i++) { if (vector[i] < minimum) minimum = vector[i]; } return minimum; } // Minimum value of word32 vector. C version for generic platforms. int32_t WebRtcSpl_MinValueW32C(const int32_t* vector, size_t length) { int32_t minimum = WEBRTC_SPL_WORD32_MAX; size_t i = 0; RTC_DCHECK_GT(length, 0); for (i = 0; i < length; i++) { if (vector[i] < minimum) minimum = vector[i]; } return minimum; } // Index of maximum absolute value in a word16 vector. size_t WebRtcSpl_MaxAbsIndexW16(const int16_t* vector, size_t length) { // Use type int for local variables, to accomodate the value of abs(-32768). size_t i = 0, index = 0; int absolute = 0, maximum = 0; RTC_DCHECK_GT(length, 0); for (i = 0; i < length; i++) { absolute = abs((int)vector[i]); if (absolute > maximum) { maximum = absolute; index = i; } } return index; } // Index of maximum value in a word16 vector. size_t WebRtcSpl_MaxIndexW16(const int16_t* vector, size_t length) { size_t i = 0, index = 0; int16_t maximum = WEBRTC_SPL_WORD16_MIN; RTC_DCHECK_GT(length, 0); for (i = 0; i < length; i++) { if (vector[i] > maximum) { maximum = vector[i]; index = i; } } return index; } // Index of maximum value in a word32 vector. size_t WebRtcSpl_MaxIndexW32(const int32_t* vector, size_t length) { size_t i = 0, index = 0; int32_t maximum = WEBRTC_SPL_WORD32_MIN; RTC_DCHECK_GT(length, 0); for (i = 0; i < length; i++) { if (vector[i] > maximum) { maximum = vector[i]; index = i; } } return index; } // Index of minimum value in a word16 vector. size_t WebRtcSpl_MinIndexW16(const int16_t* vector, size_t length) { size_t i = 0, index = 0; int16_t minimum = WEBRTC_SPL_WORD16_MAX; RTC_DCHECK_GT(length, 0); for (i = 0; i < length; i++) { if (vector[i] < minimum) { minimum = vector[i]; index = i; } } return index; } // Index of minimum value in a word32 vector. size_t WebRtcSpl_MinIndexW32(const int32_t* vector, size_t length) { size_t i = 0, index = 0; int32_t minimum = WEBRTC_SPL_WORD32_MAX; RTC_DCHECK_GT(length, 0); for (i = 0; i < length; i++) { if (vector[i] < minimum) { minimum = vector[i]; index = i; } } return index; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/min_max_operations_mips.c0000664000175000017500000004054014475643423031430 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the implementation of function * WebRtcSpl_MaxAbsValueW16() * * The description header can be found in signal_processing_library.h. * */ #include "rtc_base/checks.h" #include "common_audio/signal_processing/include/signal_processing_library.h" // Maximum absolute value of word16 vector. int16_t WebRtcSpl_MaxAbsValueW16_mips(const int16_t* vector, size_t length) { int32_t totMax = 0; int32_t tmp32_0, tmp32_1, tmp32_2, tmp32_3; size_t i, loop_size; RTC_DCHECK_GT(length, 0); #if defined(MIPS_DSP_R1) const int32_t* tmpvec32 = (int32_t*)vector; loop_size = length >> 4; for (i = 0; i < loop_size; i++) { __asm__ volatile ( "lw %[tmp32_0], 0(%[tmpvec32]) \n\t" "lw %[tmp32_1], 4(%[tmpvec32]) \n\t" "lw %[tmp32_2], 8(%[tmpvec32]) \n\t" "lw %[tmp32_3], 12(%[tmpvec32]) \n\t" "absq_s.ph %[tmp32_0], %[tmp32_0] \n\t" "absq_s.ph %[tmp32_1], %[tmp32_1] \n\t" "cmp.lt.ph %[totMax], %[tmp32_0] \n\t" "pick.ph %[totMax], %[tmp32_0], %[totMax] \n\t" "lw %[tmp32_0], 16(%[tmpvec32]) \n\t" "absq_s.ph %[tmp32_2], %[tmp32_2] \n\t" "cmp.lt.ph %[totMax], %[tmp32_1] \n\t" "pick.ph %[totMax], %[tmp32_1], %[totMax] \n\t" "lw %[tmp32_1], 20(%[tmpvec32]) \n\t" "absq_s.ph %[tmp32_3], %[tmp32_3] \n\t" "cmp.lt.ph %[totMax], %[tmp32_2] \n\t" "pick.ph %[totMax], %[tmp32_2], %[totMax] \n\t" "lw %[tmp32_2], 24(%[tmpvec32]) \n\t" "cmp.lt.ph %[totMax], %[tmp32_3] \n\t" "pick.ph %[totMax], %[tmp32_3], %[totMax] \n\t" "lw %[tmp32_3], 28(%[tmpvec32]) \n\t" "absq_s.ph %[tmp32_0], %[tmp32_0] \n\t" "absq_s.ph %[tmp32_1], %[tmp32_1] \n\t" "cmp.lt.ph %[totMax], %[tmp32_0] \n\t" "pick.ph %[totMax], %[tmp32_0], %[totMax] \n\t" "absq_s.ph %[tmp32_2], %[tmp32_2] \n\t" "cmp.lt.ph %[totMax], %[tmp32_1] \n\t" "pick.ph %[totMax], %[tmp32_1], %[totMax] \n\t" "absq_s.ph %[tmp32_3], %[tmp32_3] \n\t" "cmp.lt.ph %[totMax], %[tmp32_2] \n\t" "pick.ph %[totMax], %[tmp32_2], %[totMax] \n\t" "cmp.lt.ph %[totMax], %[tmp32_3] \n\t" "pick.ph %[totMax], %[tmp32_3], %[totMax] \n\t" "addiu %[tmpvec32], %[tmpvec32], 32 \n\t" : [tmp32_0] "=&r" (tmp32_0), [tmp32_1] "=&r" (tmp32_1), [tmp32_2] "=&r" (tmp32_2), [tmp32_3] "=&r" (tmp32_3), [totMax] "+r" (totMax), [tmpvec32] "+r" (tmpvec32) : : "memory" ); } __asm__ volatile ( "rotr %[tmp32_0], %[totMax], 16 \n\t" "cmp.lt.ph %[totMax], %[tmp32_0] \n\t" "pick.ph %[totMax], %[tmp32_0], %[totMax] \n\t" "packrl.ph %[totMax], $0, %[totMax] \n\t" : [tmp32_0] "=&r" (tmp32_0), [totMax] "+r" (totMax) : ); loop_size = length & 0xf; for (i = 0; i < loop_size; i++) { __asm__ volatile ( "lh %[tmp32_0], 0(%[tmpvec32]) \n\t" "addiu %[tmpvec32], %[tmpvec32], 2 \n\t" "absq_s.w %[tmp32_0], %[tmp32_0] \n\t" "slt %[tmp32_1], %[totMax], %[tmp32_0] \n\t" "movn %[totMax], %[tmp32_0], %[tmp32_1] \n\t" : [tmp32_0] "=&r" (tmp32_0), [tmp32_1] "=&r" (tmp32_1), [tmpvec32] "+r" (tmpvec32), [totMax] "+r" (totMax) : : "memory" ); } #else // #if defined(MIPS_DSP_R1) int32_t v16MaxMax = WEBRTC_SPL_WORD16_MAX; int32_t r, r1, r2, r3; const int16_t* tmpvector = vector; loop_size = length >> 4; for (i = 0; i < loop_size; i++) { __asm__ volatile ( "lh %[tmp32_0], 0(%[tmpvector]) \n\t" "lh %[tmp32_1], 2(%[tmpvector]) \n\t" "lh %[tmp32_2], 4(%[tmpvector]) \n\t" "lh %[tmp32_3], 6(%[tmpvector]) \n\t" "abs %[tmp32_0], %[tmp32_0] \n\t" "abs %[tmp32_1], %[tmp32_1] \n\t" "abs %[tmp32_2], %[tmp32_2] \n\t" "abs %[tmp32_3], %[tmp32_3] \n\t" "slt %[r], %[totMax], %[tmp32_0] \n\t" "movn %[totMax], %[tmp32_0], %[r] \n\t" "slt %[r1], %[totMax], %[tmp32_1] \n\t" "movn %[totMax], %[tmp32_1], %[r1] \n\t" "slt %[r2], %[totMax], %[tmp32_2] \n\t" "movn %[totMax], %[tmp32_2], %[r2] \n\t" "slt %[r3], %[totMax], %[tmp32_3] \n\t" "movn %[totMax], %[tmp32_3], %[r3] \n\t" "lh %[tmp32_0], 8(%[tmpvector]) \n\t" "lh %[tmp32_1], 10(%[tmpvector]) \n\t" "lh %[tmp32_2], 12(%[tmpvector]) \n\t" "lh %[tmp32_3], 14(%[tmpvector]) \n\t" "abs %[tmp32_0], %[tmp32_0] \n\t" "abs %[tmp32_1], %[tmp32_1] \n\t" "abs %[tmp32_2], %[tmp32_2] \n\t" "abs %[tmp32_3], %[tmp32_3] \n\t" "slt %[r], %[totMax], %[tmp32_0] \n\t" "movn %[totMax], %[tmp32_0], %[r] \n\t" "slt %[r1], %[totMax], %[tmp32_1] \n\t" "movn %[totMax], %[tmp32_1], %[r1] \n\t" "slt %[r2], %[totMax], %[tmp32_2] \n\t" "movn %[totMax], %[tmp32_2], %[r2] \n\t" "slt %[r3], %[totMax], %[tmp32_3] \n\t" "movn %[totMax], %[tmp32_3], %[r3] \n\t" "lh %[tmp32_0], 16(%[tmpvector]) \n\t" "lh %[tmp32_1], 18(%[tmpvector]) \n\t" "lh %[tmp32_2], 20(%[tmpvector]) \n\t" "lh %[tmp32_3], 22(%[tmpvector]) \n\t" "abs %[tmp32_0], %[tmp32_0] \n\t" "abs %[tmp32_1], %[tmp32_1] \n\t" "abs %[tmp32_2], %[tmp32_2] \n\t" "abs %[tmp32_3], %[tmp32_3] \n\t" "slt %[r], %[totMax], %[tmp32_0] \n\t" "movn %[totMax], %[tmp32_0], %[r] \n\t" "slt %[r1], %[totMax], %[tmp32_1] \n\t" "movn %[totMax], %[tmp32_1], %[r1] \n\t" "slt %[r2], %[totMax], %[tmp32_2] \n\t" "movn %[totMax], %[tmp32_2], %[r2] \n\t" "slt %[r3], %[totMax], %[tmp32_3] \n\t" "movn %[totMax], %[tmp32_3], %[r3] \n\t" "lh %[tmp32_0], 24(%[tmpvector]) \n\t" "lh %[tmp32_1], 26(%[tmpvector]) \n\t" "lh %[tmp32_2], 28(%[tmpvector]) \n\t" "lh %[tmp32_3], 30(%[tmpvector]) \n\t" "abs %[tmp32_0], %[tmp32_0] \n\t" "abs %[tmp32_1], %[tmp32_1] \n\t" "abs %[tmp32_2], %[tmp32_2] \n\t" "abs %[tmp32_3], %[tmp32_3] \n\t" "slt %[r], %[totMax], %[tmp32_0] \n\t" "movn %[totMax], %[tmp32_0], %[r] \n\t" "slt %[r1], %[totMax], %[tmp32_1] \n\t" "movn %[totMax], %[tmp32_1], %[r1] \n\t" "slt %[r2], %[totMax], %[tmp32_2] \n\t" "movn %[totMax], %[tmp32_2], %[r2] \n\t" "slt %[r3], %[totMax], %[tmp32_3] \n\t" "movn %[totMax], %[tmp32_3], %[r3] \n\t" "addiu %[tmpvector], %[tmpvector], 32 \n\t" : [tmp32_0] "=&r" (tmp32_0), [tmp32_1] "=&r" (tmp32_1), [tmp32_2] "=&r" (tmp32_2), [tmp32_3] "=&r" (tmp32_3), [totMax] "+r" (totMax), [r] "=&r" (r), [tmpvector] "+r" (tmpvector), [r1] "=&r" (r1), [r2] "=&r" (r2), [r3] "=&r" (r3) : : "memory" ); } loop_size = length & 0xf; for (i = 0; i < loop_size; i++) { __asm__ volatile ( "lh %[tmp32_0], 0(%[tmpvector]) \n\t" "addiu %[tmpvector], %[tmpvector], 2 \n\t" "abs %[tmp32_0], %[tmp32_0] \n\t" "slt %[tmp32_1], %[totMax], %[tmp32_0] \n\t" "movn %[totMax], %[tmp32_0], %[tmp32_1] \n\t" : [tmp32_0] "=&r" (tmp32_0), [tmp32_1] "=&r" (tmp32_1), [tmpvector] "+r" (tmpvector), [totMax] "+r" (totMax) : : "memory" ); } __asm__ volatile ( "slt %[r], %[v16MaxMax], %[totMax] \n\t" "movn %[totMax], %[v16MaxMax], %[r] \n\t" : [totMax] "+r" (totMax), [r] "=&r" (r) : [v16MaxMax] "r" (v16MaxMax) ); #endif // #if defined(MIPS_DSP_R1) return (int16_t)totMax; } #if defined(MIPS_DSP_R1_LE) // Maximum absolute value of word32 vector. Version for MIPS platform. int32_t WebRtcSpl_MaxAbsValueW32_mips(const int32_t* vector, size_t length) { // Use uint32_t for the local variables, to accommodate the return value // of abs(0x80000000), which is 0x80000000. uint32_t absolute = 0, maximum = 0; int tmp1 = 0, max_value = 0x7fffffff; RTC_DCHECK_GT(length, 0); __asm__ volatile ( ".set push \n\t" ".set noreorder \n\t" "1: \n\t" "lw %[absolute], 0(%[vector]) \n\t" "absq_s.w %[absolute], %[absolute] \n\t" "addiu %[length], %[length], -1 \n\t" "slt %[tmp1], %[maximum], %[absolute] \n\t" "movn %[maximum], %[absolute], %[tmp1] \n\t" "bgtz %[length], 1b \n\t" " addiu %[vector], %[vector], 4 \n\t" "slt %[tmp1], %[max_value], %[maximum] \n\t" "movn %[maximum], %[max_value], %[tmp1] \n\t" ".set pop \n\t" : [tmp1] "=&r" (tmp1), [maximum] "+r" (maximum), [absolute] "+r" (absolute) : [vector] "r" (vector), [length] "r" (length), [max_value] "r" (max_value) : "memory" ); return (int32_t)maximum; } #endif // #if defined(MIPS_DSP_R1_LE) // Maximum value of word16 vector. Version for MIPS platform. int16_t WebRtcSpl_MaxValueW16_mips(const int16_t* vector, size_t length) { int16_t maximum = WEBRTC_SPL_WORD16_MIN; int tmp1; int16_t value; RTC_DCHECK_GT(length, 0); __asm__ volatile ( ".set push \n\t" ".set noreorder \n\t" "1: \n\t" "lh %[value], 0(%[vector]) \n\t" "addiu %[length], %[length], -1 \n\t" "slt %[tmp1], %[maximum], %[value] \n\t" "movn %[maximum], %[value], %[tmp1] \n\t" "bgtz %[length], 1b \n\t" " addiu %[vector], %[vector], 2 \n\t" ".set pop \n\t" : [tmp1] "=&r" (tmp1), [maximum] "+r" (maximum), [value] "=&r" (value) : [vector] "r" (vector), [length] "r" (length) : "memory" ); return maximum; } // Maximum value of word32 vector. Version for MIPS platform. int32_t WebRtcSpl_MaxValueW32_mips(const int32_t* vector, size_t length) { int32_t maximum = WEBRTC_SPL_WORD32_MIN; int tmp1, value; RTC_DCHECK_GT(length, 0); __asm__ volatile ( ".set push \n\t" ".set noreorder \n\t" "1: \n\t" "lw %[value], 0(%[vector]) \n\t" "addiu %[length], %[length], -1 \n\t" "slt %[tmp1], %[maximum], %[value] \n\t" "movn %[maximum], %[value], %[tmp1] \n\t" "bgtz %[length], 1b \n\t" " addiu %[vector], %[vector], 4 \n\t" ".set pop \n\t" : [tmp1] "=&r" (tmp1), [maximum] "+r" (maximum), [value] "=&r" (value) : [vector] "r" (vector), [length] "r" (length) : "memory" ); return maximum; } // Minimum value of word16 vector. Version for MIPS platform. int16_t WebRtcSpl_MinValueW16_mips(const int16_t* vector, size_t length) { int16_t minimum = WEBRTC_SPL_WORD16_MAX; int tmp1; int16_t value; RTC_DCHECK_GT(length, 0); __asm__ volatile ( ".set push \n\t" ".set noreorder \n\t" "1: \n\t" "lh %[value], 0(%[vector]) \n\t" "addiu %[length], %[length], -1 \n\t" "slt %[tmp1], %[value], %[minimum] \n\t" "movn %[minimum], %[value], %[tmp1] \n\t" "bgtz %[length], 1b \n\t" " addiu %[vector], %[vector], 2 \n\t" ".set pop \n\t" : [tmp1] "=&r" (tmp1), [minimum] "+r" (minimum), [value] "=&r" (value) : [vector] "r" (vector), [length] "r" (length) : "memory" ); return minimum; } // Minimum value of word32 vector. Version for MIPS platform. int32_t WebRtcSpl_MinValueW32_mips(const int32_t* vector, size_t length) { int32_t minimum = WEBRTC_SPL_WORD32_MAX; int tmp1, value; RTC_DCHECK_GT(length, 0); __asm__ volatile ( ".set push \n\t" ".set noreorder \n\t" "1: \n\t" "lw %[value], 0(%[vector]) \n\t" "addiu %[length], %[length], -1 \n\t" "slt %[tmp1], %[value], %[minimum] \n\t" "movn %[minimum], %[value], %[tmp1] \n\t" "bgtz %[length], 1b \n\t" " addiu %[vector], %[vector], 4 \n\t" ".set pop \n\t" : [tmp1] "=&r" (tmp1), [minimum] "+r" (minimum), [value] "=&r" (value) : [vector] "r" (vector), [length] "r" (length) : "memory" ); return minimum; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/min_max_operations_neon.c0000664000175000017500000001767614475643423031435 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include #include #include "rtc_base/checks.h" #include "common_audio/signal_processing/include/signal_processing_library.h" // Maximum absolute value of word16 vector. C version for generic platforms. int16_t WebRtcSpl_MaxAbsValueW16Neon(const int16_t* vector, size_t length) { int absolute = 0, maximum = 0; RTC_DCHECK_GT(length, 0); const int16_t* p_start = vector; size_t rest = length & 7; const int16_t* p_end = vector + length - rest; int16x8_t v; uint16x8_t max_qv; max_qv = vdupq_n_u16(0); while (p_start < p_end) { v = vld1q_s16(p_start); // Note vabs doesn't change the value of -32768. v = vabsq_s16(v); // Use u16 so we don't lose the value -32768. max_qv = vmaxq_u16(max_qv, vreinterpretq_u16_s16(v)); p_start += 8; } #ifdef WEBRTC_ARCH_ARM64 maximum = (int)vmaxvq_u16(max_qv); #else uint16x4_t max_dv; max_dv = vmax_u16(vget_low_u16(max_qv), vget_high_u16(max_qv)); max_dv = vpmax_u16(max_dv, max_dv); max_dv = vpmax_u16(max_dv, max_dv); maximum = (int)vget_lane_u16(max_dv, 0); #endif p_end = vector + length; while (p_start < p_end) { absolute = abs((int)(*p_start)); if (absolute > maximum) { maximum = absolute; } p_start++; } // Guard the case for abs(-32768). if (maximum > WEBRTC_SPL_WORD16_MAX) { maximum = WEBRTC_SPL_WORD16_MAX; } return (int16_t)maximum; } // Maximum absolute value of word32 vector. NEON intrinsics version for // ARM 32-bit/64-bit platforms. int32_t WebRtcSpl_MaxAbsValueW32Neon(const int32_t* vector, size_t length) { // Use uint32_t for the local variables, to accommodate the return value // of abs(0x80000000), which is 0x80000000. uint32_t absolute = 0, maximum = 0; size_t i = 0; size_t residual = length & 0x7; RTC_DCHECK_GT(length, 0); const int32_t* p_start = vector; uint32x4_t max32x4_0 = vdupq_n_u32(0); uint32x4_t max32x4_1 = vdupq_n_u32(0); // First part, unroll the loop 8 times. for (i = 0; i < length - residual; i += 8) { int32x4_t in32x4_0 = vld1q_s32(p_start); p_start += 4; int32x4_t in32x4_1 = vld1q_s32(p_start); p_start += 4; in32x4_0 = vabsq_s32(in32x4_0); in32x4_1 = vabsq_s32(in32x4_1); // vabs doesn't change the value of 0x80000000. // Use u32 so we don't lose the value 0x80000000. max32x4_0 = vmaxq_u32(max32x4_0, vreinterpretq_u32_s32(in32x4_0)); max32x4_1 = vmaxq_u32(max32x4_1, vreinterpretq_u32_s32(in32x4_1)); } uint32x4_t max32x4 = vmaxq_u32(max32x4_0, max32x4_1); #if defined(WEBRTC_ARCH_ARM64) maximum = vmaxvq_u32(max32x4); #else uint32x2_t max32x2 = vmax_u32(vget_low_u32(max32x4), vget_high_u32(max32x4)); max32x2 = vpmax_u32(max32x2, max32x2); maximum = vget_lane_u32(max32x2, 0); #endif // Second part, do the remaining iterations (if any). for (i = residual; i > 0; i--) { absolute = abs((int)(*p_start)); if (absolute > maximum) { maximum = absolute; } p_start++; } // Guard against the case for 0x80000000. maximum = WEBRTC_SPL_MIN(maximum, WEBRTC_SPL_WORD32_MAX); return (int32_t)maximum; } // Maximum value of word16 vector. NEON intrinsics version for // ARM 32-bit/64-bit platforms. int16_t WebRtcSpl_MaxValueW16Neon(const int16_t* vector, size_t length) { int16_t maximum = WEBRTC_SPL_WORD16_MIN; size_t i = 0; size_t residual = length & 0x7; RTC_DCHECK_GT(length, 0); const int16_t* p_start = vector; int16x8_t max16x8 = vdupq_n_s16(WEBRTC_SPL_WORD16_MIN); // First part, unroll the loop 8 times. for (i = 0; i < length - residual; i += 8) { int16x8_t in16x8 = vld1q_s16(p_start); max16x8 = vmaxq_s16(max16x8, in16x8); p_start += 8; } #if defined(WEBRTC_ARCH_ARM64) maximum = vmaxvq_s16(max16x8); #else int16x4_t max16x4 = vmax_s16(vget_low_s16(max16x8), vget_high_s16(max16x8)); max16x4 = vpmax_s16(max16x4, max16x4); max16x4 = vpmax_s16(max16x4, max16x4); maximum = vget_lane_s16(max16x4, 0); #endif // Second part, do the remaining iterations (if any). for (i = residual; i > 0; i--) { if (*p_start > maximum) maximum = *p_start; p_start++; } return maximum; } // Maximum value of word32 vector. NEON intrinsics version for // ARM 32-bit/64-bit platforms. int32_t WebRtcSpl_MaxValueW32Neon(const int32_t* vector, size_t length) { int32_t maximum = WEBRTC_SPL_WORD32_MIN; size_t i = 0; size_t residual = length & 0x7; RTC_DCHECK_GT(length, 0); const int32_t* p_start = vector; int32x4_t max32x4_0 = vdupq_n_s32(WEBRTC_SPL_WORD32_MIN); int32x4_t max32x4_1 = vdupq_n_s32(WEBRTC_SPL_WORD32_MIN); // First part, unroll the loop 8 times. for (i = 0; i < length - residual; i += 8) { int32x4_t in32x4_0 = vld1q_s32(p_start); p_start += 4; int32x4_t in32x4_1 = vld1q_s32(p_start); p_start += 4; max32x4_0 = vmaxq_s32(max32x4_0, in32x4_0); max32x4_1 = vmaxq_s32(max32x4_1, in32x4_1); } int32x4_t max32x4 = vmaxq_s32(max32x4_0, max32x4_1); #if defined(WEBRTC_ARCH_ARM64) maximum = vmaxvq_s32(max32x4); #else int32x2_t max32x2 = vmax_s32(vget_low_s32(max32x4), vget_high_s32(max32x4)); max32x2 = vpmax_s32(max32x2, max32x2); maximum = vget_lane_s32(max32x2, 0); #endif // Second part, do the remaining iterations (if any). for (i = residual; i > 0; i--) { if (*p_start > maximum) maximum = *p_start; p_start++; } return maximum; } // Minimum value of word16 vector. NEON intrinsics version for // ARM 32-bit/64-bit platforms. int16_t WebRtcSpl_MinValueW16Neon(const int16_t* vector, size_t length) { int16_t minimum = WEBRTC_SPL_WORD16_MAX; size_t i = 0; size_t residual = length & 0x7; RTC_DCHECK_GT(length, 0); const int16_t* p_start = vector; int16x8_t min16x8 = vdupq_n_s16(WEBRTC_SPL_WORD16_MAX); // First part, unroll the loop 8 times. for (i = 0; i < length - residual; i += 8) { int16x8_t in16x8 = vld1q_s16(p_start); min16x8 = vminq_s16(min16x8, in16x8); p_start += 8; } #if defined(WEBRTC_ARCH_ARM64) minimum = vminvq_s16(min16x8); #else int16x4_t min16x4 = vmin_s16(vget_low_s16(min16x8), vget_high_s16(min16x8)); min16x4 = vpmin_s16(min16x4, min16x4); min16x4 = vpmin_s16(min16x4, min16x4); minimum = vget_lane_s16(min16x4, 0); #endif // Second part, do the remaining iterations (if any). for (i = residual; i > 0; i--) { if (*p_start < minimum) minimum = *p_start; p_start++; } return minimum; } // Minimum value of word32 vector. NEON intrinsics version for // ARM 32-bit/64-bit platforms. int32_t WebRtcSpl_MinValueW32Neon(const int32_t* vector, size_t length) { int32_t minimum = WEBRTC_SPL_WORD32_MAX; size_t i = 0; size_t residual = length & 0x7; RTC_DCHECK_GT(length, 0); const int32_t* p_start = vector; int32x4_t min32x4_0 = vdupq_n_s32(WEBRTC_SPL_WORD32_MAX); int32x4_t min32x4_1 = vdupq_n_s32(WEBRTC_SPL_WORD32_MAX); // First part, unroll the loop 8 times. for (i = 0; i < length - residual; i += 8) { int32x4_t in32x4_0 = vld1q_s32(p_start); p_start += 4; int32x4_t in32x4_1 = vld1q_s32(p_start); p_start += 4; min32x4_0 = vminq_s32(min32x4_0, in32x4_0); min32x4_1 = vminq_s32(min32x4_1, in32x4_1); } int32x4_t min32x4 = vminq_s32(min32x4_0, min32x4_1); #if defined(WEBRTC_ARCH_ARM64) minimum = vminvq_s32(min32x4); #else int32x2_t min32x2 = vmin_s32(vget_low_s32(min32x4), vget_high_s32(min32x4)); min32x2 = vpmin_s32(min32x2, min32x2); minimum = vget_lane_s32(min32x2, 0); #endif // Second part, do the remaining iterations (if any). for (i = residual; i > 0; i--) { if (*p_start < minimum) minimum = *p_start; p_start++; } return minimum; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/randomization_functions.c0000664000175000017500000001464514475643423031462 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains implementations of the randomization functions * WebRtcSpl_RandU() * WebRtcSpl_RandN() * WebRtcSpl_RandUArray() * * The description header can be found in signal_processing_library.h * */ #include "common_audio/signal_processing/include/signal_processing_library.h" static const uint32_t kMaxSeedUsed = 0x80000000; static const int16_t kRandNTable[] = { 9178, -7260, 40, 10189, 4894, -3531, -13779, 14764, -4008, -8884, -8990, 1008, 7368, 5184, 3251, -5817, -9786, 5963, 1770, 8066, -7135, 10772, -2298, 1361, 6484, 2241, -8633, 792, 199, -3344, 6553, -10079, -15040, 95, 11608, -12469, 14161, -4176, 2476, 6403, 13685, -16005, 6646, 2239, 10916, -3004, -602, -3141, 2142, 14144, -5829, 5305, 8209, 4713, 2697, -5112, 16092, -1210, -2891, -6631, -5360, -11878, -6781, -2739, -6392, 536, 10923, 10872, 5059, -4748, -7770, 5477, 38, -1025, -2892, 1638, 6304, 14375, -11028, 1553, -1565, 10762, -393, 4040, 5257, 12310, 6554, -4799, 4899, -6354, 1603, -1048, -2220, 8247, -186, -8944, -12004, 2332, 4801, -4933, 6371, 131, 8614, -5927, -8287, -22760, 4033, -15162, 3385, 3246, 3153, -5250, 3766, 784, 6494, -62, 3531, -1582, 15572, 662, -3952, -330, -3196, 669, 7236, -2678, -6569, 23319, -8645, -741, 14830, -15976, 4903, 315, -11342, 10311, 1858, -7777, 2145, 5436, 5677, -113, -10033, 826, -1353, 17210, 7768, 986, -1471, 8291, -4982, 8207, -14911, -6255, -2449, -11881, -7059, -11703, -4338, 8025, 7538, -2823, -12490, 9470, -1613, -2529, -10092, -7807, 9480, 6970, -12844, 5123, 3532, 4816, 4803, -8455, -5045, 14032, -4378, -1643, 5756, -11041, -2732, -16618, -6430, -18375, -3320, 6098, 5131, -4269, -8840, 2482, -7048, 1547, -21890, -6505, -7414, -424, -11722, 7955, 1653, -17299, 1823, 473, -9232, 3337, 1111, 873, 4018, -8982, 9889, 3531, -11763, -3799, 7373, -4539, 3231, 7054, -8537, 7616, 6244, 16635, 447, -2915, 13967, 705, -2669, -1520, -1771, -16188, 5956, 5117, 6371, -9936, -1448, 2480, 5128, 7550, -8130, 5236, 8213, -6443, 7707, -1950, -13811, 7218, 7031, -3883, 67, 5731, -2874, 13480, -3743, 9298, -3280, 3552, -4425, -18, -3785, -9988, -5357, 5477, -11794, 2117, 1416, -9935, 3376, 802, -5079, -8243, 12652, 66, 3653, -2368, 6781, -21895, -7227, 2487, 7839, -385, 6646, -7016, -4658, 5531, -1705, 834, 129, 3694, -1343, 2238, -22640, -6417, -11139, 11301, -2945, -3494, -5626, 185, -3615, -2041, -7972, -3106, -60, -23497, -1566, 17064, 3519, 2518, 304, -6805, -10269, 2105, 1936, -426, -736, -8122, -1467, 4238, -6939, -13309, 360, 7402, -7970, 12576, 3287, 12194, -6289, -16006, 9171, 4042, -9193, 9123, -2512, 6388, -4734, -8739, 1028, -5406, -1696, 5889, -666, -4736, 4971, 3565, 9362, -6292, 3876, -3652, -19666, 7523, -4061, 391, -11773, 7502, -3763, 4929, -9478, 13278, 2805, 4496, 7814, 16419, 12455, -14773, 2127, -2746, 3763, 4847, 3698, 6978, 4751, -6957, -3581, -45, 6252, 1513, -4797, -7925, 11270, 16188, -2359, -5269, 9376, -10777, 7262, 20031, -6515, -2208, -5353, 8085, -1341, -1303, 7333, 5576, 3625, 5763, -7931, 9833, -3371, -10305, 6534, -13539, -9971, 997, 8464, -4064, -1495, 1857, 13624, 5458, 9490, -11086, -4524, 12022, -550, -198, 408, -8455, -7068, 10289, 9712, -3366, 9028, -7621, -5243, 2362, 6909, 4672, -4933, -1799, 4709, -4563, -62, -566, 1624, -7010, 14730, -17791, -3697, -2344, -1741, 7099, -9509, -6855, -1989, 3495, -2289, 2031, 12784, 891, 14189, -3963, -5683, 421, -12575, 1724, -12682, -5970, -8169, 3143, -1824, -5488, -5130, 8536, 12799, 794, 5738, 3459, -11689, -258, -3738, -3775, -8742, 2333, 8312, -9383, 10331, 13119, 8398, 10644, -19433, -6446, -16277, -11793, 16284, 9345, 15222, 15834, 2009, -7349, 130, -14547, 338, -5998, 3337, 21492, 2406, 7703, -951, 11196, -564, 3406, 2217, 4806, 2374, -5797, 11839, 8940, -11874, 18213, 2855, 10492 }; static uint32_t IncreaseSeed(uint32_t* seed) { seed[0] = (seed[0] * ((int32_t)69069) + 1) & (kMaxSeedUsed - 1); return seed[0]; } int16_t WebRtcSpl_RandU(uint32_t* seed) { return (int16_t)(IncreaseSeed(seed) >> 16); } int16_t WebRtcSpl_RandN(uint32_t* seed) { return kRandNTable[IncreaseSeed(seed) >> 23]; } // Creates an array of uniformly distributed variables. int16_t WebRtcSpl_RandUArray(int16_t* vector, int16_t vector_length, uint32_t* seed) { int i; for (i = 0; i < vector_length; i++) { vector[i] = WebRtcSpl_RandU(seed); } return vector_length; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/real_fft.c0000664000175000017500000000611514475643423026267 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/signal_processing/include/real_fft.h" #include #include "common_audio/signal_processing/include/signal_processing_library.h" struct RealFFT { int order; }; struct RealFFT* WebRtcSpl_CreateRealFFT(int order) { struct RealFFT* self = NULL; if (order > kMaxFFTOrder || order < 0) { return NULL; } self = malloc(sizeof(struct RealFFT)); if (self == NULL) { return NULL; } self->order = order; return self; } void WebRtcSpl_FreeRealFFT(struct RealFFT* self) { if (self != NULL) { free(self); } } // The C version FFT functions (i.e. WebRtcSpl_RealForwardFFT and // WebRtcSpl_RealInverseFFT) are real-valued FFT wrappers for complex-valued // FFT implementation in SPL. int WebRtcSpl_RealForwardFFT(struct RealFFT* self, const int16_t* real_data_in, int16_t* complex_data_out) { int i = 0; int j = 0; int result = 0; int n = 1 << self->order; // The complex-value FFT implementation needs a buffer to hold 2^order // 16-bit COMPLEX numbers, for both time and frequency data. int16_t complex_buffer[2 << kMaxFFTOrder]; // Insert zeros to the imaginary parts for complex forward FFT input. for (i = 0, j = 0; i < n; i += 1, j += 2) { complex_buffer[j] = real_data_in[i]; complex_buffer[j + 1] = 0; }; WebRtcSpl_ComplexBitReverse(complex_buffer, self->order); result = WebRtcSpl_ComplexFFT(complex_buffer, self->order, 1); // For real FFT output, use only the first N + 2 elements from // complex forward FFT. memcpy(complex_data_out, complex_buffer, sizeof(int16_t) * (n + 2)); return result; } int WebRtcSpl_RealInverseFFT(struct RealFFT* self, const int16_t* complex_data_in, int16_t* real_data_out) { int i = 0; int j = 0; int result = 0; int n = 1 << self->order; // Create the buffer specific to complex-valued FFT implementation. int16_t complex_buffer[2 << kMaxFFTOrder]; // For n-point FFT, first copy the first n + 2 elements into complex // FFT, then construct the remaining n - 2 elements by real FFT's // conjugate-symmetric properties. memcpy(complex_buffer, complex_data_in, sizeof(int16_t) * (n + 2)); for (i = n + 2; i < 2 * n; i += 2) { complex_buffer[i] = complex_data_in[2 * n - i]; complex_buffer[i + 1] = -complex_data_in[2 * n - i + 1]; } WebRtcSpl_ComplexBitReverse(complex_buffer, self->order); result = WebRtcSpl_ComplexIFFT(complex_buffer, self->order, 1); // Strip out the imaginary parts of the complex inverse FFT output. for (i = 0, j = 0; i < n; i += 1, j += 2) { real_data_out[i] = complex_buffer[j]; } return result; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/refl_coef_to_lpc.c0000664000175000017500000000270614475643423027773 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the function WebRtcSpl_ReflCoefToLpc(). * The description header can be found in signal_processing_library.h * */ #include "common_audio/signal_processing/include/signal_processing_library.h" void WebRtcSpl_ReflCoefToLpc(const int16_t *k, int use_order, int16_t *a) { int16_t any[WEBRTC_SPL_MAX_LPC_ORDER + 1]; int16_t *aptr, *aptr2, *anyptr; const int16_t *kptr; int m, i; kptr = k; *a = 4096; // i.e., (Word16_MAX >> 3)+1. *any = *a; a[1] = *k >> 3; for (m = 1; m < use_order; m++) { kptr++; aptr = a; aptr++; aptr2 = &a[m]; anyptr = any; anyptr++; any[m + 1] = *kptr >> 3; for (i = 0; i < m; i++) { *anyptr = *aptr + (int16_t)((*aptr2 * *kptr) >> 15); anyptr++; aptr++; aptr2--; } aptr = a; anyptr = any; for (i = 0; i < (m + 2); i++) { *aptr = *anyptr; aptr++; anyptr++; } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/resample.c0000664000175000017500000004062414475643423026320 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the resampling functions for 22 kHz. * The description header can be found in signal_processing_library.h * */ #include "common_audio/signal_processing/include/signal_processing_library.h" #include "common_audio/signal_processing/resample_by_2_internal.h" // Declaration of internally used functions static void WebRtcSpl_32khzTo22khzIntToShort(const int32_t *In, int16_t *Out, int32_t K); void WebRtcSpl_32khzTo22khzIntToInt(const int32_t *In, int32_t *Out, int32_t K); // interpolation coefficients static const int16_t kCoefficients32To22[5][9] = { {127, -712, 2359, -6333, 23456, 16775, -3695, 945, -154}, {-39, 230, -830, 2785, 32366, -2324, 760, -218, 38}, {117, -663, 2222, -6133, 26634, 13070, -3174, 831, -137}, {-77, 457, -1677, 5958, 31175, -4136, 1405, -408, 71}, { 98, -560, 1900, -5406, 29240, 9423, -2480, 663, -110} }; ////////////////////// // 22 kHz -> 16 kHz // ////////////////////// // number of subblocks; options: 1, 2, 4, 5, 10 #define SUB_BLOCKS_22_16 5 // 22 -> 16 resampler void WebRtcSpl_Resample22khzTo16khz(const int16_t* in, int16_t* out, WebRtcSpl_State22khzTo16khz* state, int32_t* tmpmem) { int k; // process two blocks of 10/SUB_BLOCKS_22_16 ms (to reduce temp buffer size) for (k = 0; k < SUB_BLOCKS_22_16; k++) { ///// 22 --> 44 ///// // int16_t in[220/SUB_BLOCKS_22_16] // int32_t out[440/SUB_BLOCKS_22_16] ///// WebRtcSpl_UpBy2ShortToInt(in, 220 / SUB_BLOCKS_22_16, tmpmem + 16, state->S_22_44); ///// 44 --> 32 ///// // int32_t in[440/SUB_BLOCKS_22_16] // int32_t out[320/SUB_BLOCKS_22_16] ///// // copy state to and from input array tmpmem[8] = state->S_44_32[0]; tmpmem[9] = state->S_44_32[1]; tmpmem[10] = state->S_44_32[2]; tmpmem[11] = state->S_44_32[3]; tmpmem[12] = state->S_44_32[4]; tmpmem[13] = state->S_44_32[5]; tmpmem[14] = state->S_44_32[6]; tmpmem[15] = state->S_44_32[7]; state->S_44_32[0] = tmpmem[440 / SUB_BLOCKS_22_16 + 8]; state->S_44_32[1] = tmpmem[440 / SUB_BLOCKS_22_16 + 9]; state->S_44_32[2] = tmpmem[440 / SUB_BLOCKS_22_16 + 10]; state->S_44_32[3] = tmpmem[440 / SUB_BLOCKS_22_16 + 11]; state->S_44_32[4] = tmpmem[440 / SUB_BLOCKS_22_16 + 12]; state->S_44_32[5] = tmpmem[440 / SUB_BLOCKS_22_16 + 13]; state->S_44_32[6] = tmpmem[440 / SUB_BLOCKS_22_16 + 14]; state->S_44_32[7] = tmpmem[440 / SUB_BLOCKS_22_16 + 15]; WebRtcSpl_Resample44khzTo32khz(tmpmem + 8, tmpmem, 40 / SUB_BLOCKS_22_16); ///// 32 --> 16 ///// // int32_t in[320/SUB_BLOCKS_22_16] // int32_t out[160/SUB_BLOCKS_22_16] ///// WebRtcSpl_DownBy2IntToShort(tmpmem, 320 / SUB_BLOCKS_22_16, out, state->S_32_16); // move input/output pointers 10/SUB_BLOCKS_22_16 ms seconds ahead in += 220 / SUB_BLOCKS_22_16; out += 160 / SUB_BLOCKS_22_16; } } // initialize state of 22 -> 16 resampler void WebRtcSpl_ResetResample22khzTo16khz(WebRtcSpl_State22khzTo16khz* state) { int k; for (k = 0; k < 8; k++) { state->S_22_44[k] = 0; state->S_44_32[k] = 0; state->S_32_16[k] = 0; } } ////////////////////// // 16 kHz -> 22 kHz // ////////////////////// // number of subblocks; options: 1, 2, 4, 5, 10 #define SUB_BLOCKS_16_22 4 // 16 -> 22 resampler void WebRtcSpl_Resample16khzTo22khz(const int16_t* in, int16_t* out, WebRtcSpl_State16khzTo22khz* state, int32_t* tmpmem) { int k; // process two blocks of 10/SUB_BLOCKS_16_22 ms (to reduce temp buffer size) for (k = 0; k < SUB_BLOCKS_16_22; k++) { ///// 16 --> 32 ///// // int16_t in[160/SUB_BLOCKS_16_22] // int32_t out[320/SUB_BLOCKS_16_22] ///// WebRtcSpl_UpBy2ShortToInt(in, 160 / SUB_BLOCKS_16_22, tmpmem + 8, state->S_16_32); ///// 32 --> 22 ///// // int32_t in[320/SUB_BLOCKS_16_22] // int32_t out[220/SUB_BLOCKS_16_22] ///// // copy state to and from input array tmpmem[0] = state->S_32_22[0]; tmpmem[1] = state->S_32_22[1]; tmpmem[2] = state->S_32_22[2]; tmpmem[3] = state->S_32_22[3]; tmpmem[4] = state->S_32_22[4]; tmpmem[5] = state->S_32_22[5]; tmpmem[6] = state->S_32_22[6]; tmpmem[7] = state->S_32_22[7]; state->S_32_22[0] = tmpmem[320 / SUB_BLOCKS_16_22]; state->S_32_22[1] = tmpmem[320 / SUB_BLOCKS_16_22 + 1]; state->S_32_22[2] = tmpmem[320 / SUB_BLOCKS_16_22 + 2]; state->S_32_22[3] = tmpmem[320 / SUB_BLOCKS_16_22 + 3]; state->S_32_22[4] = tmpmem[320 / SUB_BLOCKS_16_22 + 4]; state->S_32_22[5] = tmpmem[320 / SUB_BLOCKS_16_22 + 5]; state->S_32_22[6] = tmpmem[320 / SUB_BLOCKS_16_22 + 6]; state->S_32_22[7] = tmpmem[320 / SUB_BLOCKS_16_22 + 7]; WebRtcSpl_32khzTo22khzIntToShort(tmpmem, out, 20 / SUB_BLOCKS_16_22); // move input/output pointers 10/SUB_BLOCKS_16_22 ms seconds ahead in += 160 / SUB_BLOCKS_16_22; out += 220 / SUB_BLOCKS_16_22; } } // initialize state of 16 -> 22 resampler void WebRtcSpl_ResetResample16khzTo22khz(WebRtcSpl_State16khzTo22khz* state) { int k; for (k = 0; k < 8; k++) { state->S_16_32[k] = 0; state->S_32_22[k] = 0; } } ////////////////////// // 22 kHz -> 8 kHz // ////////////////////// // number of subblocks; options: 1, 2, 5, 10 #define SUB_BLOCKS_22_8 2 // 22 -> 8 resampler void WebRtcSpl_Resample22khzTo8khz(const int16_t* in, int16_t* out, WebRtcSpl_State22khzTo8khz* state, int32_t* tmpmem) { int k; // process two blocks of 10/SUB_BLOCKS_22_8 ms (to reduce temp buffer size) for (k = 0; k < SUB_BLOCKS_22_8; k++) { ///// 22 --> 22 lowpass ///// // int16_t in[220/SUB_BLOCKS_22_8] // int32_t out[220/SUB_BLOCKS_22_8] ///// WebRtcSpl_LPBy2ShortToInt(in, 220 / SUB_BLOCKS_22_8, tmpmem + 16, state->S_22_22); ///// 22 --> 16 ///// // int32_t in[220/SUB_BLOCKS_22_8] // int32_t out[160/SUB_BLOCKS_22_8] ///// // copy state to and from input array tmpmem[8] = state->S_22_16[0]; tmpmem[9] = state->S_22_16[1]; tmpmem[10] = state->S_22_16[2]; tmpmem[11] = state->S_22_16[3]; tmpmem[12] = state->S_22_16[4]; tmpmem[13] = state->S_22_16[5]; tmpmem[14] = state->S_22_16[6]; tmpmem[15] = state->S_22_16[7]; state->S_22_16[0] = tmpmem[220 / SUB_BLOCKS_22_8 + 8]; state->S_22_16[1] = tmpmem[220 / SUB_BLOCKS_22_8 + 9]; state->S_22_16[2] = tmpmem[220 / SUB_BLOCKS_22_8 + 10]; state->S_22_16[3] = tmpmem[220 / SUB_BLOCKS_22_8 + 11]; state->S_22_16[4] = tmpmem[220 / SUB_BLOCKS_22_8 + 12]; state->S_22_16[5] = tmpmem[220 / SUB_BLOCKS_22_8 + 13]; state->S_22_16[6] = tmpmem[220 / SUB_BLOCKS_22_8 + 14]; state->S_22_16[7] = tmpmem[220 / SUB_BLOCKS_22_8 + 15]; WebRtcSpl_Resample44khzTo32khz(tmpmem + 8, tmpmem, 20 / SUB_BLOCKS_22_8); ///// 16 --> 8 ///// // int32_t in[160/SUB_BLOCKS_22_8] // int32_t out[80/SUB_BLOCKS_22_8] ///// WebRtcSpl_DownBy2IntToShort(tmpmem, 160 / SUB_BLOCKS_22_8, out, state->S_16_8); // move input/output pointers 10/SUB_BLOCKS_22_8 ms seconds ahead in += 220 / SUB_BLOCKS_22_8; out += 80 / SUB_BLOCKS_22_8; } } // initialize state of 22 -> 8 resampler void WebRtcSpl_ResetResample22khzTo8khz(WebRtcSpl_State22khzTo8khz* state) { int k; for (k = 0; k < 8; k++) { state->S_22_22[k] = 0; state->S_22_22[k + 8] = 0; state->S_22_16[k] = 0; state->S_16_8[k] = 0; } } ////////////////////// // 8 kHz -> 22 kHz // ////////////////////// // number of subblocks; options: 1, 2, 5, 10 #define SUB_BLOCKS_8_22 2 // 8 -> 22 resampler void WebRtcSpl_Resample8khzTo22khz(const int16_t* in, int16_t* out, WebRtcSpl_State8khzTo22khz* state, int32_t* tmpmem) { int k; // process two blocks of 10/SUB_BLOCKS_8_22 ms (to reduce temp buffer size) for (k = 0; k < SUB_BLOCKS_8_22; k++) { ///// 8 --> 16 ///// // int16_t in[80/SUB_BLOCKS_8_22] // int32_t out[160/SUB_BLOCKS_8_22] ///// WebRtcSpl_UpBy2ShortToInt(in, 80 / SUB_BLOCKS_8_22, tmpmem + 18, state->S_8_16); ///// 16 --> 11 ///// // int32_t in[160/SUB_BLOCKS_8_22] // int32_t out[110/SUB_BLOCKS_8_22] ///// // copy state to and from input array tmpmem[10] = state->S_16_11[0]; tmpmem[11] = state->S_16_11[1]; tmpmem[12] = state->S_16_11[2]; tmpmem[13] = state->S_16_11[3]; tmpmem[14] = state->S_16_11[4]; tmpmem[15] = state->S_16_11[5]; tmpmem[16] = state->S_16_11[6]; tmpmem[17] = state->S_16_11[7]; state->S_16_11[0] = tmpmem[160 / SUB_BLOCKS_8_22 + 10]; state->S_16_11[1] = tmpmem[160 / SUB_BLOCKS_8_22 + 11]; state->S_16_11[2] = tmpmem[160 / SUB_BLOCKS_8_22 + 12]; state->S_16_11[3] = tmpmem[160 / SUB_BLOCKS_8_22 + 13]; state->S_16_11[4] = tmpmem[160 / SUB_BLOCKS_8_22 + 14]; state->S_16_11[5] = tmpmem[160 / SUB_BLOCKS_8_22 + 15]; state->S_16_11[6] = tmpmem[160 / SUB_BLOCKS_8_22 + 16]; state->S_16_11[7] = tmpmem[160 / SUB_BLOCKS_8_22 + 17]; WebRtcSpl_32khzTo22khzIntToInt(tmpmem + 10, tmpmem, 10 / SUB_BLOCKS_8_22); ///// 11 --> 22 ///// // int32_t in[110/SUB_BLOCKS_8_22] // int16_t out[220/SUB_BLOCKS_8_22] ///// WebRtcSpl_UpBy2IntToShort(tmpmem, 110 / SUB_BLOCKS_8_22, out, state->S_11_22); // move input/output pointers 10/SUB_BLOCKS_8_22 ms seconds ahead in += 80 / SUB_BLOCKS_8_22; out += 220 / SUB_BLOCKS_8_22; } } // initialize state of 8 -> 22 resampler void WebRtcSpl_ResetResample8khzTo22khz(WebRtcSpl_State8khzTo22khz* state) { int k; for (k = 0; k < 8; k++) { state->S_8_16[k] = 0; state->S_16_11[k] = 0; state->S_11_22[k] = 0; } } // compute two inner-products and store them to output array static void WebRtcSpl_DotProdIntToInt(const int32_t* in1, const int32_t* in2, const int16_t* coef_ptr, int32_t* out1, int32_t* out2) { int32_t tmp1 = 16384; int32_t tmp2 = 16384; int16_t coef; coef = coef_ptr[0]; tmp1 += coef * in1[0]; tmp2 += coef * in2[-0]; coef = coef_ptr[1]; tmp1 += coef * in1[1]; tmp2 += coef * in2[-1]; coef = coef_ptr[2]; tmp1 += coef * in1[2]; tmp2 += coef * in2[-2]; coef = coef_ptr[3]; tmp1 += coef * in1[3]; tmp2 += coef * in2[-3]; coef = coef_ptr[4]; tmp1 += coef * in1[4]; tmp2 += coef * in2[-4]; coef = coef_ptr[5]; tmp1 += coef * in1[5]; tmp2 += coef * in2[-5]; coef = coef_ptr[6]; tmp1 += coef * in1[6]; tmp2 += coef * in2[-6]; coef = coef_ptr[7]; tmp1 += coef * in1[7]; tmp2 += coef * in2[-7]; coef = coef_ptr[8]; *out1 = tmp1 + coef * in1[8]; *out2 = tmp2 + coef * in2[-8]; } // compute two inner-products and store them to output array static void WebRtcSpl_DotProdIntToShort(const int32_t* in1, const int32_t* in2, const int16_t* coef_ptr, int16_t* out1, int16_t* out2) { int32_t tmp1 = 16384; int32_t tmp2 = 16384; int16_t coef; coef = coef_ptr[0]; tmp1 += coef * in1[0]; tmp2 += coef * in2[-0]; coef = coef_ptr[1]; tmp1 += coef * in1[1]; tmp2 += coef * in2[-1]; coef = coef_ptr[2]; tmp1 += coef * in1[2]; tmp2 += coef * in2[-2]; coef = coef_ptr[3]; tmp1 += coef * in1[3]; tmp2 += coef * in2[-3]; coef = coef_ptr[4]; tmp1 += coef * in1[4]; tmp2 += coef * in2[-4]; coef = coef_ptr[5]; tmp1 += coef * in1[5]; tmp2 += coef * in2[-5]; coef = coef_ptr[6]; tmp1 += coef * in1[6]; tmp2 += coef * in2[-6]; coef = coef_ptr[7]; tmp1 += coef * in1[7]; tmp2 += coef * in2[-7]; coef = coef_ptr[8]; tmp1 += coef * in1[8]; tmp2 += coef * in2[-8]; // scale down, round and saturate tmp1 >>= 15; if (tmp1 > (int32_t)0x00007FFF) tmp1 = 0x00007FFF; if (tmp1 < (int32_t)0xFFFF8000) tmp1 = 0xFFFF8000; tmp2 >>= 15; if (tmp2 > (int32_t)0x00007FFF) tmp2 = 0x00007FFF; if (tmp2 < (int32_t)0xFFFF8000) tmp2 = 0xFFFF8000; *out1 = (int16_t)tmp1; *out2 = (int16_t)tmp2; } // Resampling ratio: 11/16 // input: int32_t (normalized, not saturated) :: size 16 * K // output: int32_t (shifted 15 positions to the left, + offset 16384) :: size 11 * K // K: Number of blocks void WebRtcSpl_32khzTo22khzIntToInt(const int32_t* In, int32_t* Out, int32_t K) { ///////////////////////////////////////////////////////////// // Filter operation: // // Perform resampling (16 input samples -> 11 output samples); // process in sub blocks of size 16 samples. int32_t m; for (m = 0; m < K; m++) { // first output sample Out[0] = ((int32_t)In[3] << 15) + (1 << 14); // sum and accumulate filter coefficients and input samples WebRtcSpl_DotProdIntToInt(&In[0], &In[22], kCoefficients32To22[0], &Out[1], &Out[10]); // sum and accumulate filter coefficients and input samples WebRtcSpl_DotProdIntToInt(&In[2], &In[20], kCoefficients32To22[1], &Out[2], &Out[9]); // sum and accumulate filter coefficients and input samples WebRtcSpl_DotProdIntToInt(&In[3], &In[19], kCoefficients32To22[2], &Out[3], &Out[8]); // sum and accumulate filter coefficients and input samples WebRtcSpl_DotProdIntToInt(&In[5], &In[17], kCoefficients32To22[3], &Out[4], &Out[7]); // sum and accumulate filter coefficients and input samples WebRtcSpl_DotProdIntToInt(&In[6], &In[16], kCoefficients32To22[4], &Out[5], &Out[6]); // update pointers In += 16; Out += 11; } } // Resampling ratio: 11/16 // input: int32_t (normalized, not saturated) :: size 16 * K // output: int16_t (saturated) :: size 11 * K // K: Number of blocks void WebRtcSpl_32khzTo22khzIntToShort(const int32_t *In, int16_t *Out, int32_t K) { ///////////////////////////////////////////////////////////// // Filter operation: // // Perform resampling (16 input samples -> 11 output samples); // process in sub blocks of size 16 samples. int32_t tmp; int32_t m; for (m = 0; m < K; m++) { // first output sample tmp = In[3]; if (tmp > (int32_t)0x00007FFF) tmp = 0x00007FFF; if (tmp < (int32_t)0xFFFF8000) tmp = 0xFFFF8000; Out[0] = (int16_t)tmp; // sum and accumulate filter coefficients and input samples WebRtcSpl_DotProdIntToShort(&In[0], &In[22], kCoefficients32To22[0], &Out[1], &Out[10]); // sum and accumulate filter coefficients and input samples WebRtcSpl_DotProdIntToShort(&In[2], &In[20], kCoefficients32To22[1], &Out[2], &Out[9]); // sum and accumulate filter coefficients and input samples WebRtcSpl_DotProdIntToShort(&In[3], &In[19], kCoefficients32To22[2], &Out[3], &Out[8]); // sum and accumulate filter coefficients and input samples WebRtcSpl_DotProdIntToShort(&In[5], &In[17], kCoefficients32To22[3], &Out[4], &Out[7]); // sum and accumulate filter coefficients and input samples WebRtcSpl_DotProdIntToShort(&In[6], &In[16], kCoefficients32To22[4], &Out[5], &Out[6]); // update pointers In += 16; Out += 11; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/resample_48khz.c0000664000175000017500000001330314475643423027342 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains resampling functions between 48 kHz and nb/wb. * The description header can be found in signal_processing_library.h * */ #include #include "common_audio/signal_processing/include/signal_processing_library.h" #include "common_audio/signal_processing/resample_by_2_internal.h" //////////////////////////// ///// 48 kHz -> 16 kHz ///// //////////////////////////// // 48 -> 16 resampler void WebRtcSpl_Resample48khzTo16khz(const int16_t* in, int16_t* out, WebRtcSpl_State48khzTo16khz* state, int32_t* tmpmem) { ///// 48 --> 48(LP) ///// // int16_t in[480] // int32_t out[480] ///// WebRtcSpl_LPBy2ShortToInt(in, 480, tmpmem + 16, state->S_48_48); ///// 48 --> 32 ///// // int32_t in[480] // int32_t out[320] ///// // copy state to and from input array memcpy(tmpmem + 8, state->S_48_32, 8 * sizeof(int32_t)); memcpy(state->S_48_32, tmpmem + 488, 8 * sizeof(int32_t)); WebRtcSpl_Resample48khzTo32khz(tmpmem + 8, tmpmem, 160); ///// 32 --> 16 ///// // int32_t in[320] // int16_t out[160] ///// WebRtcSpl_DownBy2IntToShort(tmpmem, 320, out, state->S_32_16); } // initialize state of 48 -> 16 resampler void WebRtcSpl_ResetResample48khzTo16khz(WebRtcSpl_State48khzTo16khz* state) { memset(state->S_48_48, 0, 16 * sizeof(int32_t)); memset(state->S_48_32, 0, 8 * sizeof(int32_t)); memset(state->S_32_16, 0, 8 * sizeof(int32_t)); } //////////////////////////// ///// 16 kHz -> 48 kHz ///// //////////////////////////// // 16 -> 48 resampler void WebRtcSpl_Resample16khzTo48khz(const int16_t* in, int16_t* out, WebRtcSpl_State16khzTo48khz* state, int32_t* tmpmem) { ///// 16 --> 32 ///// // int16_t in[160] // int32_t out[320] ///// WebRtcSpl_UpBy2ShortToInt(in, 160, tmpmem + 16, state->S_16_32); ///// 32 --> 24 ///// // int32_t in[320] // int32_t out[240] // copy state to and from input array ///// memcpy(tmpmem + 8, state->S_32_24, 8 * sizeof(int32_t)); memcpy(state->S_32_24, tmpmem + 328, 8 * sizeof(int32_t)); WebRtcSpl_Resample32khzTo24khz(tmpmem + 8, tmpmem, 80); ///// 24 --> 48 ///// // int32_t in[240] // int16_t out[480] ///// WebRtcSpl_UpBy2IntToShort(tmpmem, 240, out, state->S_24_48); } // initialize state of 16 -> 48 resampler void WebRtcSpl_ResetResample16khzTo48khz(WebRtcSpl_State16khzTo48khz* state) { memset(state->S_16_32, 0, 8 * sizeof(int32_t)); memset(state->S_32_24, 0, 8 * sizeof(int32_t)); memset(state->S_24_48, 0, 8 * sizeof(int32_t)); } //////////////////////////// ///// 48 kHz -> 8 kHz ///// //////////////////////////// // 48 -> 8 resampler void WebRtcSpl_Resample48khzTo8khz(const int16_t* in, int16_t* out, WebRtcSpl_State48khzTo8khz* state, int32_t* tmpmem) { ///// 48 --> 24 ///// // int16_t in[480] // int32_t out[240] ///// WebRtcSpl_DownBy2ShortToInt(in, 480, tmpmem + 256, state->S_48_24); ///// 24 --> 24(LP) ///// // int32_t in[240] // int32_t out[240] ///// WebRtcSpl_LPBy2IntToInt(tmpmem + 256, 240, tmpmem + 16, state->S_24_24); ///// 24 --> 16 ///// // int32_t in[240] // int32_t out[160] ///// // copy state to and from input array memcpy(tmpmem + 8, state->S_24_16, 8 * sizeof(int32_t)); memcpy(state->S_24_16, tmpmem + 248, 8 * sizeof(int32_t)); WebRtcSpl_Resample48khzTo32khz(tmpmem + 8, tmpmem, 80); ///// 16 --> 8 ///// // int32_t in[160] // int16_t out[80] ///// WebRtcSpl_DownBy2IntToShort(tmpmem, 160, out, state->S_16_8); } // initialize state of 48 -> 8 resampler void WebRtcSpl_ResetResample48khzTo8khz(WebRtcSpl_State48khzTo8khz* state) { memset(state->S_48_24, 0, 8 * sizeof(int32_t)); memset(state->S_24_24, 0, 16 * sizeof(int32_t)); memset(state->S_24_16, 0, 8 * sizeof(int32_t)); memset(state->S_16_8, 0, 8 * sizeof(int32_t)); } //////////////////////////// ///// 8 kHz -> 48 kHz ///// //////////////////////////// // 8 -> 48 resampler void WebRtcSpl_Resample8khzTo48khz(const int16_t* in, int16_t* out, WebRtcSpl_State8khzTo48khz* state, int32_t* tmpmem) { ///// 8 --> 16 ///// // int16_t in[80] // int32_t out[160] ///// WebRtcSpl_UpBy2ShortToInt(in, 80, tmpmem + 264, state->S_8_16); ///// 16 --> 12 ///// // int32_t in[160] // int32_t out[120] ///// // copy state to and from input array memcpy(tmpmem + 256, state->S_16_12, 8 * sizeof(int32_t)); memcpy(state->S_16_12, tmpmem + 416, 8 * sizeof(int32_t)); WebRtcSpl_Resample32khzTo24khz(tmpmem + 256, tmpmem + 240, 40); ///// 12 --> 24 ///// // int32_t in[120] // int16_t out[240] ///// WebRtcSpl_UpBy2IntToInt(tmpmem + 240, 120, tmpmem, state->S_12_24); ///// 24 --> 48 ///// // int32_t in[240] // int16_t out[480] ///// WebRtcSpl_UpBy2IntToShort(tmpmem, 240, out, state->S_24_48); } // initialize state of 8 -> 48 resampler void WebRtcSpl_ResetResample8khzTo48khz(WebRtcSpl_State8khzTo48khz* state) { memset(state->S_8_16, 0, 8 * sizeof(int32_t)); memset(state->S_16_12, 0, 8 * sizeof(int32_t)); memset(state->S_12_24, 0, 8 * sizeof(int32_t)); memset(state->S_24_48, 0, 8 * sizeof(int32_t)); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/resample_by_2.c0000664000175000017500000001351514475643423027232 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the resampling by two functions. * The description header can be found in signal_processing_library.h * */ #include "common_audio/signal_processing/include/signal_processing_library.h" #ifdef WEBRTC_ARCH_ARM_V7 // allpass filter coefficients. static const uint32_t kResampleAllpass1[3] = {3284, 24441, 49528 << 15}; static const uint32_t kResampleAllpass2[3] = {12199, 37471 << 15, 60255 << 15}; // Multiply two 32-bit values and accumulate to another input value. // Return: state + ((diff * tbl_value) >> 16) static __inline int32_t MUL_ACCUM_1(int32_t tbl_value, int32_t diff, int32_t state) { int32_t result; __asm __volatile ("smlawb %0, %1, %2, %3": "=r"(result): "r"(diff), "r"(tbl_value), "r"(state)); return result; } // Multiply two 32-bit values and accumulate to another input value. // Return: Return: state + (((diff << 1) * tbl_value) >> 32) // // The reason to introduce this function is that, in case we can't use smlawb // instruction (in MUL_ACCUM_1) due to input value range, we can still use // smmla to save some cycles. static __inline int32_t MUL_ACCUM_2(int32_t tbl_value, int32_t diff, int32_t state) { int32_t result; __asm __volatile ("smmla %0, %1, %2, %3": "=r"(result): "r"(diff << 1), "r"(tbl_value), "r"(state)); return result; } #else // allpass filter coefficients. static const uint16_t kResampleAllpass1[3] = {3284, 24441, 49528}; static const uint16_t kResampleAllpass2[3] = {12199, 37471, 60255}; // Multiply a 32-bit value with a 16-bit value and accumulate to another input: #define MUL_ACCUM_1(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c) #define MUL_ACCUM_2(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c) #endif // WEBRTC_ARCH_ARM_V7 // decimator #if !defined(MIPS32_LE) void WebRtcSpl_DownsampleBy2(const int16_t* in, size_t len, int16_t* out, int32_t* filtState) { int32_t tmp1, tmp2, diff, in32, out32; size_t i; register int32_t state0 = filtState[0]; register int32_t state1 = filtState[1]; register int32_t state2 = filtState[2]; register int32_t state3 = filtState[3]; register int32_t state4 = filtState[4]; register int32_t state5 = filtState[5]; register int32_t state6 = filtState[6]; register int32_t state7 = filtState[7]; for (i = (len >> 1); i > 0; i--) { // lower allpass filter in32 = (int32_t)(*in++) * (1 << 10); diff = in32 - state1; tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0); state0 = in32; diff = tmp1 - state2; tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1); state1 = tmp1; diff = tmp2 - state3; state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2); state2 = tmp2; // upper allpass filter in32 = (int32_t)(*in++) * (1 << 10); diff = in32 - state5; tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4); state4 = in32; diff = tmp1 - state6; tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5); state5 = tmp1; diff = tmp2 - state7; state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6); state6 = tmp2; // add two allpass outputs, divide by two and round out32 = (state3 + state7 + 1024) >> 11; // limit amplitude to prevent wrap-around, and write to output array *out++ = WebRtcSpl_SatW32ToW16(out32); } filtState[0] = state0; filtState[1] = state1; filtState[2] = state2; filtState[3] = state3; filtState[4] = state4; filtState[5] = state5; filtState[6] = state6; filtState[7] = state7; } #endif // #if defined(MIPS32_LE) void WebRtcSpl_UpsampleBy2(const int16_t* in, size_t len, int16_t* out, int32_t* filtState) { int32_t tmp1, tmp2, diff, in32, out32; size_t i; register int32_t state0 = filtState[0]; register int32_t state1 = filtState[1]; register int32_t state2 = filtState[2]; register int32_t state3 = filtState[3]; register int32_t state4 = filtState[4]; register int32_t state5 = filtState[5]; register int32_t state6 = filtState[6]; register int32_t state7 = filtState[7]; for (i = len; i > 0; i--) { // lower allpass filter in32 = (int32_t)(*in++) * (1 << 10); diff = in32 - state1; tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state0); state0 = in32; diff = tmp1 - state2; tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state1); state1 = tmp1; diff = tmp2 - state3; state3 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state2); state2 = tmp2; // round; limit amplitude to prevent wrap-around; write to output array out32 = (state3 + 512) >> 10; *out++ = WebRtcSpl_SatW32ToW16(out32); // upper allpass filter diff = in32 - state5; tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state4); state4 = in32; diff = tmp1 - state6; tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state5); state5 = tmp1; diff = tmp2 - state7; state7 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state6); state6 = tmp2; // round; limit amplitude to prevent wrap-around; write to output array out32 = (state7 + 512) >> 10; *out++ = WebRtcSpl_SatW32ToW16(out32); } filtState[0] = state0; filtState[1] = state1; filtState[2] = state2; filtState[3] = state3; filtState[4] = state4; filtState[5] = state5; filtState[6] = state6; filtState[7] = state7; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/resample_by_2_internal.c0000664000175000017500000005020114475643423031117 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This header file contains some internal resampling functions. * */ #include "common_audio/signal_processing/resample_by_2_internal.h" #include "rtc_base/sanitizer.h" // allpass filter coefficients. static const int16_t kResampleAllpass[2][3] = { {821, 6110, 12382}, {3050, 9368, 15063} }; // // decimator // input: int32_t (shifted 15 positions to the left, + offset 16384) OVERWRITTEN! // output: int16_t (saturated) (of length len/2) // state: filter state array; length = 8 void RTC_NO_SANITIZE("signed-integer-overflow") // bugs.webrtc.org/5486 WebRtcSpl_DownBy2IntToShort(int32_t *in, int32_t len, int16_t *out, int32_t *state) { int32_t tmp0, tmp1, diff; int32_t i; len >>= 1; // lower allpass filter (operates on even input samples) for (i = 0; i < len; i++) { tmp0 = in[i << 1]; diff = tmp0 - state[1]; // UBSan: -1771017321 - 999586185 cannot be represented in type 'int' // scale down and round diff = (diff + (1 << 13)) >> 14; tmp1 = state[0] + diff * kResampleAllpass[1][0]; state[0] = tmp0; diff = tmp1 - state[2]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; tmp0 = state[1] + diff * kResampleAllpass[1][1]; state[1] = tmp1; diff = tmp0 - state[3]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; state[3] = state[2] + diff * kResampleAllpass[1][2]; state[2] = tmp0; // divide by two and store temporarily in[i << 1] = (state[3] >> 1); } in++; // upper allpass filter (operates on odd input samples) for (i = 0; i < len; i++) { tmp0 = in[i << 1]; diff = tmp0 - state[5]; // scale down and round diff = (diff + (1 << 13)) >> 14; tmp1 = state[4] + diff * kResampleAllpass[0][0]; state[4] = tmp0; diff = tmp1 - state[6]; // scale down and round diff = diff >> 14; if (diff < 0) diff += 1; tmp0 = state[5] + diff * kResampleAllpass[0][1]; state[5] = tmp1; diff = tmp0 - state[7]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; state[7] = state[6] + diff * kResampleAllpass[0][2]; state[6] = tmp0; // divide by two and store temporarily in[i << 1] = (state[7] >> 1); } in--; // combine allpass outputs for (i = 0; i < len; i += 2) { // divide by two, add both allpass outputs and round tmp0 = (in[i << 1] + in[(i << 1) + 1]) >> 15; tmp1 = (in[(i << 1) + 2] + in[(i << 1) + 3]) >> 15; if (tmp0 > (int32_t)0x00007FFF) tmp0 = 0x00007FFF; if (tmp0 < (int32_t)0xFFFF8000) tmp0 = 0xFFFF8000; out[i] = (int16_t)tmp0; if (tmp1 > (int32_t)0x00007FFF) tmp1 = 0x00007FFF; if (tmp1 < (int32_t)0xFFFF8000) tmp1 = 0xFFFF8000; out[i + 1] = (int16_t)tmp1; } } // // decimator // input: int16_t // output: int32_t (shifted 15 positions to the left, + offset 16384) (of length len/2) // state: filter state array; length = 8 void RTC_NO_SANITIZE("signed-integer-overflow") // bugs.webrtc.org/5486 WebRtcSpl_DownBy2ShortToInt(const int16_t *in, int32_t len, int32_t *out, int32_t *state) { int32_t tmp0, tmp1, diff; int32_t i; len >>= 1; // lower allpass filter (operates on even input samples) for (i = 0; i < len; i++) { tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14); diff = tmp0 - state[1]; // scale down and round diff = (diff + (1 << 13)) >> 14; tmp1 = state[0] + diff * kResampleAllpass[1][0]; state[0] = tmp0; diff = tmp1 - state[2]; // UBSan: -1379909682 - 834099714 cannot be represented in type 'int' // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; tmp0 = state[1] + diff * kResampleAllpass[1][1]; state[1] = tmp1; diff = tmp0 - state[3]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; state[3] = state[2] + diff * kResampleAllpass[1][2]; state[2] = tmp0; // divide by two and store temporarily out[i] = (state[3] >> 1); } in++; // upper allpass filter (operates on odd input samples) for (i = 0; i < len; i++) { tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14); diff = tmp0 - state[5]; // scale down and round diff = (diff + (1 << 13)) >> 14; tmp1 = state[4] + diff * kResampleAllpass[0][0]; state[4] = tmp0; diff = tmp1 - state[6]; // scale down and round diff = diff >> 14; if (diff < 0) diff += 1; tmp0 = state[5] + diff * kResampleAllpass[0][1]; state[5] = tmp1; diff = tmp0 - state[7]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; state[7] = state[6] + diff * kResampleAllpass[0][2]; state[6] = tmp0; // divide by two and store temporarily out[i] += (state[7] >> 1); } in--; } // // interpolator // input: int16_t // output: int32_t (normalized, not saturated) (of length len*2) // state: filter state array; length = 8 void WebRtcSpl_UpBy2ShortToInt(const int16_t *in, int32_t len, int32_t *out, int32_t *state) { int32_t tmp0, tmp1, diff; int32_t i; // upper allpass filter (generates odd output samples) for (i = 0; i < len; i++) { tmp0 = ((int32_t)in[i] << 15) + (1 << 14); diff = tmp0 - state[5]; // scale down and round diff = (diff + (1 << 13)) >> 14; tmp1 = state[4] + diff * kResampleAllpass[0][0]; state[4] = tmp0; diff = tmp1 - state[6]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; tmp0 = state[5] + diff * kResampleAllpass[0][1]; state[5] = tmp1; diff = tmp0 - state[7]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; state[7] = state[6] + diff * kResampleAllpass[0][2]; state[6] = tmp0; // scale down, round and store out[i << 1] = state[7] >> 15; } out++; // lower allpass filter (generates even output samples) for (i = 0; i < len; i++) { tmp0 = ((int32_t)in[i] << 15) + (1 << 14); diff = tmp0 - state[1]; // scale down and round diff = (diff + (1 << 13)) >> 14; tmp1 = state[0] + diff * kResampleAllpass[1][0]; state[0] = tmp0; diff = tmp1 - state[2]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; tmp0 = state[1] + diff * kResampleAllpass[1][1]; state[1] = tmp1; diff = tmp0 - state[3]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; state[3] = state[2] + diff * kResampleAllpass[1][2]; state[2] = tmp0; // scale down, round and store out[i << 1] = state[3] >> 15; } } // // interpolator // input: int32_t (shifted 15 positions to the left, + offset 16384) // output: int32_t (shifted 15 positions to the left, + offset 16384) (of length len*2) // state: filter state array; length = 8 void WebRtcSpl_UpBy2IntToInt(const int32_t *in, int32_t len, int32_t *out, int32_t *state) { int32_t tmp0, tmp1, diff; int32_t i; // upper allpass filter (generates odd output samples) for (i = 0; i < len; i++) { tmp0 = in[i]; diff = tmp0 - state[5]; // scale down and round diff = (diff + (1 << 13)) >> 14; tmp1 = state[4] + diff * kResampleAllpass[0][0]; state[4] = tmp0; diff = tmp1 - state[6]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; tmp0 = state[5] + diff * kResampleAllpass[0][1]; state[5] = tmp1; diff = tmp0 - state[7]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; state[7] = state[6] + diff * kResampleAllpass[0][2]; state[6] = tmp0; // scale down, round and store out[i << 1] = state[7]; } out++; // lower allpass filter (generates even output samples) for (i = 0; i < len; i++) { tmp0 = in[i]; diff = tmp0 - state[1]; // scale down and round diff = (diff + (1 << 13)) >> 14; tmp1 = state[0] + diff * kResampleAllpass[1][0]; state[0] = tmp0; diff = tmp1 - state[2]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; tmp0 = state[1] + diff * kResampleAllpass[1][1]; state[1] = tmp1; diff = tmp0 - state[3]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; state[3] = state[2] + diff * kResampleAllpass[1][2]; state[2] = tmp0; // scale down, round and store out[i << 1] = state[3]; } } // // interpolator // input: int32_t (shifted 15 positions to the left, + offset 16384) // output: int16_t (saturated) (of length len*2) // state: filter state array; length = 8 void WebRtcSpl_UpBy2IntToShort(const int32_t *in, int32_t len, int16_t *out, int32_t *state) { int32_t tmp0, tmp1, diff; int32_t i; // upper allpass filter (generates odd output samples) for (i = 0; i < len; i++) { tmp0 = in[i]; diff = tmp0 - state[5]; // scale down and round diff = (diff + (1 << 13)) >> 14; tmp1 = state[4] + diff * kResampleAllpass[0][0]; state[4] = tmp0; diff = tmp1 - state[6]; // scale down and round diff = diff >> 14; if (diff < 0) diff += 1; tmp0 = state[5] + diff * kResampleAllpass[0][1]; state[5] = tmp1; diff = tmp0 - state[7]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; state[7] = state[6] + diff * kResampleAllpass[0][2]; state[6] = tmp0; // scale down, saturate and store tmp1 = state[7] >> 15; if (tmp1 > (int32_t)0x00007FFF) tmp1 = 0x00007FFF; if (tmp1 < (int32_t)0xFFFF8000) tmp1 = 0xFFFF8000; out[i << 1] = (int16_t)tmp1; } out++; // lower allpass filter (generates even output samples) for (i = 0; i < len; i++) { tmp0 = in[i]; diff = tmp0 - state[1]; // scale down and round diff = (diff + (1 << 13)) >> 14; tmp1 = state[0] + diff * kResampleAllpass[1][0]; state[0] = tmp0; diff = tmp1 - state[2]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; tmp0 = state[1] + diff * kResampleAllpass[1][1]; state[1] = tmp1; diff = tmp0 - state[3]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; state[3] = state[2] + diff * kResampleAllpass[1][2]; state[2] = tmp0; // scale down, saturate and store tmp1 = state[3] >> 15; if (tmp1 > (int32_t)0x00007FFF) tmp1 = 0x00007FFF; if (tmp1 < (int32_t)0xFFFF8000) tmp1 = 0xFFFF8000; out[i << 1] = (int16_t)tmp1; } } // lowpass filter // input: int16_t // output: int32_t (normalized, not saturated) // state: filter state array; length = 8 void WebRtcSpl_LPBy2ShortToInt(const int16_t* in, int32_t len, int32_t* out, int32_t* state) { int32_t tmp0, tmp1, diff; int32_t i; len >>= 1; // lower allpass filter: odd input -> even output samples in++; // initial state of polyphase delay element tmp0 = state[12]; for (i = 0; i < len; i++) { diff = tmp0 - state[1]; // scale down and round diff = (diff + (1 << 13)) >> 14; tmp1 = state[0] + diff * kResampleAllpass[1][0]; state[0] = tmp0; diff = tmp1 - state[2]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; tmp0 = state[1] + diff * kResampleAllpass[1][1]; state[1] = tmp1; diff = tmp0 - state[3]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; state[3] = state[2] + diff * kResampleAllpass[1][2]; state[2] = tmp0; // scale down, round and store out[i << 1] = state[3] >> 1; tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14); } in--; // upper allpass filter: even input -> even output samples for (i = 0; i < len; i++) { tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14); diff = tmp0 - state[5]; // scale down and round diff = (diff + (1 << 13)) >> 14; tmp1 = state[4] + diff * kResampleAllpass[0][0]; state[4] = tmp0; diff = tmp1 - state[6]; // scale down and round diff = diff >> 14; if (diff < 0) diff += 1; tmp0 = state[5] + diff * kResampleAllpass[0][1]; state[5] = tmp1; diff = tmp0 - state[7]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; state[7] = state[6] + diff * kResampleAllpass[0][2]; state[6] = tmp0; // average the two allpass outputs, scale down and store out[i << 1] = (out[i << 1] + (state[7] >> 1)) >> 15; } // switch to odd output samples out++; // lower allpass filter: even input -> odd output samples for (i = 0; i < len; i++) { tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14); diff = tmp0 - state[9]; // scale down and round diff = (diff + (1 << 13)) >> 14; tmp1 = state[8] + diff * kResampleAllpass[1][0]; state[8] = tmp0; diff = tmp1 - state[10]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; tmp0 = state[9] + diff * kResampleAllpass[1][1]; state[9] = tmp1; diff = tmp0 - state[11]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; state[11] = state[10] + diff * kResampleAllpass[1][2]; state[10] = tmp0; // scale down, round and store out[i << 1] = state[11] >> 1; } // upper allpass filter: odd input -> odd output samples in++; for (i = 0; i < len; i++) { tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14); diff = tmp0 - state[13]; // scale down and round diff = (diff + (1 << 13)) >> 14; tmp1 = state[12] + diff * kResampleAllpass[0][0]; state[12] = tmp0; diff = tmp1 - state[14]; // scale down and round diff = diff >> 14; if (diff < 0) diff += 1; tmp0 = state[13] + diff * kResampleAllpass[0][1]; state[13] = tmp1; diff = tmp0 - state[15]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; state[15] = state[14] + diff * kResampleAllpass[0][2]; state[14] = tmp0; // average the two allpass outputs, scale down and store out[i << 1] = (out[i << 1] + (state[15] >> 1)) >> 15; } } // lowpass filter // input: int32_t (shifted 15 positions to the left, + offset 16384) // output: int32_t (normalized, not saturated) // state: filter state array; length = 8 void RTC_NO_SANITIZE("signed-integer-overflow") // bugs.webrtc.org/5486 WebRtcSpl_LPBy2IntToInt(const int32_t* in, int32_t len, int32_t* out, int32_t* state) { int32_t tmp0, tmp1, diff; int32_t i; len >>= 1; // lower allpass filter: odd input -> even output samples in++; // initial state of polyphase delay element tmp0 = state[12]; for (i = 0; i < len; i++) { diff = tmp0 - state[1]; // scale down and round diff = (diff + (1 << 13)) >> 14; tmp1 = state[0] + diff * kResampleAllpass[1][0]; state[0] = tmp0; diff = tmp1 - state[2]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; tmp0 = state[1] + diff * kResampleAllpass[1][1]; state[1] = tmp1; diff = tmp0 - state[3]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; state[3] = state[2] + diff * kResampleAllpass[1][2]; state[2] = tmp0; // scale down, round and store out[i << 1] = state[3] >> 1; tmp0 = in[i << 1]; } in--; // upper allpass filter: even input -> even output samples for (i = 0; i < len; i++) { tmp0 = in[i << 1]; diff = tmp0 - state[5]; // UBSan: -794814117 - 1566149201 cannot be represented in type 'int' // scale down and round diff = (diff + (1 << 13)) >> 14; tmp1 = state[4] + diff * kResampleAllpass[0][0]; state[4] = tmp0; diff = tmp1 - state[6]; // scale down and round diff = diff >> 14; if (diff < 0) diff += 1; tmp0 = state[5] + diff * kResampleAllpass[0][1]; state[5] = tmp1; diff = tmp0 - state[7]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; state[7] = state[6] + diff * kResampleAllpass[0][2]; state[6] = tmp0; // average the two allpass outputs, scale down and store out[i << 1] = (out[i << 1] + (state[7] >> 1)) >> 15; } // switch to odd output samples out++; // lower allpass filter: even input -> odd output samples for (i = 0; i < len; i++) { tmp0 = in[i << 1]; diff = tmp0 - state[9]; // scale down and round diff = (diff + (1 << 13)) >> 14; tmp1 = state[8] + diff * kResampleAllpass[1][0]; state[8] = tmp0; diff = tmp1 - state[10]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; tmp0 = state[9] + diff * kResampleAllpass[1][1]; state[9] = tmp1; diff = tmp0 - state[11]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; state[11] = state[10] + diff * kResampleAllpass[1][2]; state[10] = tmp0; // scale down, round and store out[i << 1] = state[11] >> 1; } // upper allpass filter: odd input -> odd output samples in++; for (i = 0; i < len; i++) { tmp0 = in[i << 1]; diff = tmp0 - state[13]; // scale down and round diff = (diff + (1 << 13)) >> 14; tmp1 = state[12] + diff * kResampleAllpass[0][0]; state[12] = tmp0; diff = tmp1 - state[14]; // scale down and round diff = diff >> 14; if (diff < 0) diff += 1; tmp0 = state[13] + diff * kResampleAllpass[0][1]; state[13] = tmp1; diff = tmp0 - state[15]; // scale down and truncate diff = diff >> 14; if (diff < 0) diff += 1; state[15] = state[14] + diff * kResampleAllpass[0][2]; state[14] = tmp0; // average the two allpass outputs, scale down and store out[i << 1] = (out[i << 1] + (state[15] >> 1)) >> 15; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/resample_by_2_internal.h0000664000175000017500000000430414475643423031127 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This header file contains some internal resampling functions. * */ #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_RESAMPLE_BY_2_INTERNAL_H_ #define COMMON_AUDIO_SIGNAL_PROCESSING_RESAMPLE_BY_2_INTERNAL_H_ #include /******************************************************************* * resample_by_2_fast.c * Functions for internal use in the other resample functions ******************************************************************/ void WebRtcSpl_DownBy2IntToShort(int32_t* in, int32_t len, int16_t* out, int32_t* state); void WebRtcSpl_DownBy2ShortToInt(const int16_t* in, int32_t len, int32_t* out, int32_t* state); void WebRtcSpl_UpBy2ShortToInt(const int16_t* in, int32_t len, int32_t* out, int32_t* state); void WebRtcSpl_UpBy2IntToInt(const int32_t* in, int32_t len, int32_t* out, int32_t* state); void WebRtcSpl_UpBy2IntToShort(const int32_t* in, int32_t len, int16_t* out, int32_t* state); void WebRtcSpl_LPBy2ShortToInt(const int16_t* in, int32_t len, int32_t* out, int32_t* state); void WebRtcSpl_LPBy2IntToInt(const int32_t* in, int32_t len, int32_t* out, int32_t* state); #endif // COMMON_AUDIO_SIGNAL_PROCESSING_RESAMPLE_BY_2_INTERNAL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/resample_by_2_mips.c0000664000175000017500000002462014475643423030261 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the resampling by two functions. * The description header can be found in signal_processing_library.h * */ #if defined(MIPS32_LE) #include "common_audio/signal_processing/include/signal_processing_library.h" #if !defined(MIPS_DSP_R2_LE) // allpass filter coefficients. static const uint16_t kResampleAllpass1[3] = {3284, 24441, 49528}; static const uint16_t kResampleAllpass2[3] = {12199, 37471, 60255}; #endif // Multiply a 32-bit value with a 16-bit value and accumulate to another input: #define MUL_ACCUM_1(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c) #define MUL_ACCUM_2(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c) // decimator void WebRtcSpl_DownsampleBy2(const int16_t* in, size_t len, int16_t* out, int32_t* filtState) { int32_t out32; size_t i, len1; register int32_t state0 = filtState[0]; register int32_t state1 = filtState[1]; register int32_t state2 = filtState[2]; register int32_t state3 = filtState[3]; register int32_t state4 = filtState[4]; register int32_t state5 = filtState[5]; register int32_t state6 = filtState[6]; register int32_t state7 = filtState[7]; #if defined(MIPS_DSP_R2_LE) int32_t k1Res0, k1Res1, k1Res2, k2Res0, k2Res1, k2Res2; k1Res0= 3284; k1Res1= 24441; k1Res2= 49528; k2Res0= 12199; k2Res1= 37471; k2Res2= 60255; len1 = (len >> 1); const int32_t* inw = (int32_t*)in; int32_t tmp11, tmp12, tmp21, tmp22; int32_t in322, in321; int32_t diff1, diff2; for (i = len1; i > 0; i--) { __asm__ volatile ( "lh %[in321], 0(%[inw]) \n\t" "lh %[in322], 2(%[inw]) \n\t" "sll %[in321], %[in321], 10 \n\t" "sll %[in322], %[in322], 10 \n\t" "addiu %[inw], %[inw], 4 \n\t" "subu %[diff1], %[in321], %[state1] \n\t" "subu %[diff2], %[in322], %[state5] \n\t" : [in322] "=&r" (in322), [in321] "=&r" (in321), [diff1] "=&r" (diff1), [diff2] "=r" (diff2), [inw] "+r" (inw) : [state1] "r" (state1), [state5] "r" (state5) : "memory" ); __asm__ volatile ( "mult $ac0, %[diff1], %[k2Res0] \n\t" "mult $ac1, %[diff2], %[k1Res0] \n\t" "extr.w %[tmp11], $ac0, 16 \n\t" "extr.w %[tmp12], $ac1, 16 \n\t" "addu %[tmp11], %[state0], %[tmp11] \n\t" "addu %[tmp12], %[state4], %[tmp12] \n\t" "addiu %[state0], %[in321], 0 \n\t" "addiu %[state4], %[in322], 0 \n\t" "subu %[diff1], %[tmp11], %[state2] \n\t" "subu %[diff2], %[tmp12], %[state6] \n\t" "mult $ac0, %[diff1], %[k2Res1] \n\t" "mult $ac1, %[diff2], %[k1Res1] \n\t" "extr.w %[tmp21], $ac0, 16 \n\t" "extr.w %[tmp22], $ac1, 16 \n\t" "addu %[tmp21], %[state1], %[tmp21] \n\t" "addu %[tmp22], %[state5], %[tmp22] \n\t" "addiu %[state1], %[tmp11], 0 \n\t" "addiu %[state5], %[tmp12], 0 \n\t" : [tmp22] "=r" (tmp22), [tmp21] "=&r" (tmp21), [tmp11] "=&r" (tmp11), [state0] "+r" (state0), [state1] "+r" (state1), [state2] "+r" (state2), [state4] "+r" (state4), [tmp12] "=&r" (tmp12), [state6] "+r" (state6), [state5] "+r" (state5) : [k1Res1] "r" (k1Res1), [k2Res1] "r" (k2Res1), [k2Res0] "r" (k2Res0), [diff2] "r" (diff2), [diff1] "r" (diff1), [in322] "r" (in322), [in321] "r" (in321), [k1Res0] "r" (k1Res0) : "hi", "lo", "$ac1hi", "$ac1lo" ); // upper allpass filter __asm__ volatile ( "subu %[diff1], %[tmp21], %[state3] \n\t" "subu %[diff2], %[tmp22], %[state7] \n\t" "mult $ac0, %[diff1], %[k2Res2] \n\t" "mult $ac1, %[diff2], %[k1Res2] \n\t" "extr.w %[state3], $ac0, 16 \n\t" "extr.w %[state7], $ac1, 16 \n\t" "addu %[state3], %[state2], %[state3] \n\t" "addu %[state7], %[state6], %[state7] \n\t" "addiu %[state2], %[tmp21], 0 \n\t" "addiu %[state6], %[tmp22], 0 \n\t" // add two allpass outputs, divide by two and round "addu %[out32], %[state3], %[state7] \n\t" "addiu %[out32], %[out32], 1024 \n\t" "sra %[out32], %[out32], 11 \n\t" : [state3] "+r" (state3), [state6] "+r" (state6), [state2] "+r" (state2), [diff2] "=&r" (diff2), [out32] "=r" (out32), [diff1] "=&r" (diff1), [state7] "+r" (state7) : [tmp22] "r" (tmp22), [tmp21] "r" (tmp21), [k1Res2] "r" (k1Res2), [k2Res2] "r" (k2Res2) : "hi", "lo", "$ac1hi", "$ac1lo" ); // limit amplitude to prevent wrap-around, and write to output array *out++ = WebRtcSpl_SatW32ToW16(out32); } #else // #if defined(MIPS_DSP_R2_LE) int32_t tmp1, tmp2, diff; int32_t in32; len1 = (len >> 1)/4; for (i = len1; i > 0; i--) { // lower allpass filter in32 = (int32_t)(*in++) << 10; diff = in32 - state1; tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0); state0 = in32; diff = tmp1 - state2; tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1); state1 = tmp1; diff = tmp2 - state3; state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2); state2 = tmp2; // upper allpass filter in32 = (int32_t)(*in++) << 10; diff = in32 - state5; tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4); state4 = in32; diff = tmp1 - state6; tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5); state5 = tmp1; diff = tmp2 - state7; state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6); state6 = tmp2; // add two allpass outputs, divide by two and round out32 = (state3 + state7 + 1024) >> 11; // limit amplitude to prevent wrap-around, and write to output array *out++ = WebRtcSpl_SatW32ToW16(out32); // lower allpass filter in32 = (int32_t)(*in++) << 10; diff = in32 - state1; tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0); state0 = in32; diff = tmp1 - state2; tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1); state1 = tmp1; diff = tmp2 - state3; state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2); state2 = tmp2; // upper allpass filter in32 = (int32_t)(*in++) << 10; diff = in32 - state5; tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4); state4 = in32; diff = tmp1 - state6; tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5); state5 = tmp1; diff = tmp2 - state7; state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6); state6 = tmp2; // add two allpass outputs, divide by two and round out32 = (state3 + state7 + 1024) >> 11; // limit amplitude to prevent wrap-around, and write to output array *out++ = WebRtcSpl_SatW32ToW16(out32); // lower allpass filter in32 = (int32_t)(*in++) << 10; diff = in32 - state1; tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0); state0 = in32; diff = tmp1 - state2; tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1); state1 = tmp1; diff = tmp2 - state3; state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2); state2 = tmp2; // upper allpass filter in32 = (int32_t)(*in++) << 10; diff = in32 - state5; tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4); state4 = in32; diff = tmp1 - state6; tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5); state5 = tmp1; diff = tmp2 - state7; state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6); state6 = tmp2; // add two allpass outputs, divide by two and round out32 = (state3 + state7 + 1024) >> 11; // limit amplitude to prevent wrap-around, and write to output array *out++ = WebRtcSpl_SatW32ToW16(out32); // lower allpass filter in32 = (int32_t)(*in++) << 10; diff = in32 - state1; tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0); state0 = in32; diff = tmp1 - state2; tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1); state1 = tmp1; diff = tmp2 - state3; state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2); state2 = tmp2; // upper allpass filter in32 = (int32_t)(*in++) << 10; diff = in32 - state5; tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4); state4 = in32; diff = tmp1 - state6; tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5); state5 = tmp1; diff = tmp2 - state7; state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6); state6 = tmp2; // add two allpass outputs, divide by two and round out32 = (state3 + state7 + 1024) >> 11; // limit amplitude to prevent wrap-around, and write to output array *out++ = WebRtcSpl_SatW32ToW16(out32); } #endif // #if defined(MIPS_DSP_R2_LE) __asm__ volatile ( "sw %[state0], 0(%[filtState]) \n\t" "sw %[state1], 4(%[filtState]) \n\t" "sw %[state2], 8(%[filtState]) \n\t" "sw %[state3], 12(%[filtState]) \n\t" "sw %[state4], 16(%[filtState]) \n\t" "sw %[state5], 20(%[filtState]) \n\t" "sw %[state6], 24(%[filtState]) \n\t" "sw %[state7], 28(%[filtState]) \n\t" : : [state0] "r" (state0), [state1] "r" (state1), [state2] "r" (state2), [state3] "r" (state3), [state4] "r" (state4), [state5] "r" (state5), [state6] "r" (state6), [state7] "r" (state7), [filtState] "r" (filtState) : "memory" ); } #endif // #if defined(MIPS32_LE) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/resample_fractional.c0000664000175000017500000001723214475643423030521 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the resampling functions between 48, 44, 32 and 24 kHz. * The description headers can be found in signal_processing_library.h * */ #include "common_audio/signal_processing/include/signal_processing_library.h" // interpolation coefficients static const int16_t kCoefficients48To32[2][8] = { {778, -2050, 1087, 23285, 12903, -3783, 441, 222}, {222, 441, -3783, 12903, 23285, 1087, -2050, 778} }; static const int16_t kCoefficients32To24[3][8] = { {767, -2362, 2434, 24406, 10620, -3838, 721, 90}, {386, -381, -2646, 19062, 19062, -2646, -381, 386}, {90, 721, -3838, 10620, 24406, 2434, -2362, 767} }; static const int16_t kCoefficients44To32[4][9] = { {117, -669, 2245, -6183, 26267, 13529, -3245, 845, -138}, {-101, 612, -2283, 8532, 29790, -5138, 1789, -524, 91}, {50, -292, 1016, -3064, 32010, 3933, -1147, 315, -53}, {-156, 974, -3863, 18603, 21691, -6246, 2353, -712, 126} }; // Resampling ratio: 2/3 // input: int32_t (normalized, not saturated) :: size 3 * K // output: int32_t (shifted 15 positions to the left, + offset 16384) :: size 2 * K // K: number of blocks void WebRtcSpl_Resample48khzTo32khz(const int32_t *In, int32_t *Out, size_t K) { ///////////////////////////////////////////////////////////// // Filter operation: // // Perform resampling (3 input samples -> 2 output samples); // process in sub blocks of size 3 samples. int32_t tmp; size_t m; for (m = 0; m < K; m++) { tmp = 1 << 14; tmp += kCoefficients48To32[0][0] * In[0]; tmp += kCoefficients48To32[0][1] * In[1]; tmp += kCoefficients48To32[0][2] * In[2]; tmp += kCoefficients48To32[0][3] * In[3]; tmp += kCoefficients48To32[0][4] * In[4]; tmp += kCoefficients48To32[0][5] * In[5]; tmp += kCoefficients48To32[0][6] * In[6]; tmp += kCoefficients48To32[0][7] * In[7]; Out[0] = tmp; tmp = 1 << 14; tmp += kCoefficients48To32[1][0] * In[1]; tmp += kCoefficients48To32[1][1] * In[2]; tmp += kCoefficients48To32[1][2] * In[3]; tmp += kCoefficients48To32[1][3] * In[4]; tmp += kCoefficients48To32[1][4] * In[5]; tmp += kCoefficients48To32[1][5] * In[6]; tmp += kCoefficients48To32[1][6] * In[7]; tmp += kCoefficients48To32[1][7] * In[8]; Out[1] = tmp; // update pointers In += 3; Out += 2; } } // Resampling ratio: 3/4 // input: int32_t (normalized, not saturated) :: size 4 * K // output: int32_t (shifted 15 positions to the left, + offset 16384) :: size 3 * K // K: number of blocks void WebRtcSpl_Resample32khzTo24khz(const int32_t *In, int32_t *Out, size_t K) { ///////////////////////////////////////////////////////////// // Filter operation: // // Perform resampling (4 input samples -> 3 output samples); // process in sub blocks of size 4 samples. size_t m; int32_t tmp; for (m = 0; m < K; m++) { tmp = 1 << 14; tmp += kCoefficients32To24[0][0] * In[0]; tmp += kCoefficients32To24[0][1] * In[1]; tmp += kCoefficients32To24[0][2] * In[2]; tmp += kCoefficients32To24[0][3] * In[3]; tmp += kCoefficients32To24[0][4] * In[4]; tmp += kCoefficients32To24[0][5] * In[5]; tmp += kCoefficients32To24[0][6] * In[6]; tmp += kCoefficients32To24[0][7] * In[7]; Out[0] = tmp; tmp = 1 << 14; tmp += kCoefficients32To24[1][0] * In[1]; tmp += kCoefficients32To24[1][1] * In[2]; tmp += kCoefficients32To24[1][2] * In[3]; tmp += kCoefficients32To24[1][3] * In[4]; tmp += kCoefficients32To24[1][4] * In[5]; tmp += kCoefficients32To24[1][5] * In[6]; tmp += kCoefficients32To24[1][6] * In[7]; tmp += kCoefficients32To24[1][7] * In[8]; Out[1] = tmp; tmp = 1 << 14; tmp += kCoefficients32To24[2][0] * In[2]; tmp += kCoefficients32To24[2][1] * In[3]; tmp += kCoefficients32To24[2][2] * In[4]; tmp += kCoefficients32To24[2][3] * In[5]; tmp += kCoefficients32To24[2][4] * In[6]; tmp += kCoefficients32To24[2][5] * In[7]; tmp += kCoefficients32To24[2][6] * In[8]; tmp += kCoefficients32To24[2][7] * In[9]; Out[2] = tmp; // update pointers In += 4; Out += 3; } } // // fractional resampling filters // Fout = 11/16 * Fin // Fout = 8/11 * Fin // // compute two inner-products and store them to output array static void WebRtcSpl_ResampDotProduct(const int32_t *in1, const int32_t *in2, const int16_t *coef_ptr, int32_t *out1, int32_t *out2) { int32_t tmp1 = 16384; int32_t tmp2 = 16384; int16_t coef; coef = coef_ptr[0]; tmp1 += coef * in1[0]; tmp2 += coef * in2[-0]; coef = coef_ptr[1]; tmp1 += coef * in1[1]; tmp2 += coef * in2[-1]; coef = coef_ptr[2]; tmp1 += coef * in1[2]; tmp2 += coef * in2[-2]; coef = coef_ptr[3]; tmp1 += coef * in1[3]; tmp2 += coef * in2[-3]; coef = coef_ptr[4]; tmp1 += coef * in1[4]; tmp2 += coef * in2[-4]; coef = coef_ptr[5]; tmp1 += coef * in1[5]; tmp2 += coef * in2[-5]; coef = coef_ptr[6]; tmp1 += coef * in1[6]; tmp2 += coef * in2[-6]; coef = coef_ptr[7]; tmp1 += coef * in1[7]; tmp2 += coef * in2[-7]; coef = coef_ptr[8]; *out1 = tmp1 + coef * in1[8]; *out2 = tmp2 + coef * in2[-8]; } // Resampling ratio: 8/11 // input: int32_t (normalized, not saturated) :: size 11 * K // output: int32_t (shifted 15 positions to the left, + offset 16384) :: size 8 * K // K: number of blocks void WebRtcSpl_Resample44khzTo32khz(const int32_t *In, int32_t *Out, size_t K) { ///////////////////////////////////////////////////////////// // Filter operation: // // Perform resampling (11 input samples -> 8 output samples); // process in sub blocks of size 11 samples. int32_t tmp; size_t m; for (m = 0; m < K; m++) { tmp = 1 << 14; // first output sample Out[0] = ((int32_t)In[3] << 15) + tmp; // sum and accumulate filter coefficients and input samples tmp += kCoefficients44To32[3][0] * In[5]; tmp += kCoefficients44To32[3][1] * In[6]; tmp += kCoefficients44To32[3][2] * In[7]; tmp += kCoefficients44To32[3][3] * In[8]; tmp += kCoefficients44To32[3][4] * In[9]; tmp += kCoefficients44To32[3][5] * In[10]; tmp += kCoefficients44To32[3][6] * In[11]; tmp += kCoefficients44To32[3][7] * In[12]; tmp += kCoefficients44To32[3][8] * In[13]; Out[4] = tmp; // sum and accumulate filter coefficients and input samples WebRtcSpl_ResampDotProduct(&In[0], &In[17], kCoefficients44To32[0], &Out[1], &Out[7]); // sum and accumulate filter coefficients and input samples WebRtcSpl_ResampDotProduct(&In[2], &In[15], kCoefficients44To32[1], &Out[2], &Out[6]); // sum and accumulate filter coefficients and input samples WebRtcSpl_ResampDotProduct(&In[3], &In[14], kCoefficients44To32[2], &Out[3], &Out[5]); // update pointers In += 11; Out += 8; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/spl_init.c0000664000175000017500000000604114475643423026324 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Some code came from common/rtcd.c in the WebM project. #include "common_audio/signal_processing/include/signal_processing_library.h" // TODO(bugs.webrtc.org/9553): These function pointers are useless. Refactor // things so that we simply have a bunch of regular functions with different // implementations for different platforms. #if defined(WEBRTC_HAS_NEON) const MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16Neon; const MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32Neon; const MaxValueW16 WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16Neon; const MaxValueW32 WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32Neon; const MinValueW16 WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16Neon; const MinValueW32 WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32Neon; const CrossCorrelation WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelationNeon; const DownsampleFast WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFastNeon; const ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound = WebRtcSpl_ScaleAndAddVectorsWithRoundC; #elif defined(MIPS32_LE) const MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16_mips; const MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32 = #ifdef MIPS_DSP_R1_LE WebRtcSpl_MaxAbsValueW32_mips; #else WebRtcSpl_MaxAbsValueW32C; #endif const MaxValueW16 WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16_mips; const MaxValueW32 WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32_mips; const MinValueW16 WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16_mips; const MinValueW32 WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32_mips; const CrossCorrelation WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelation_mips; const DownsampleFast WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFast_mips; const ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound = #ifdef MIPS_DSP_R1_LE WebRtcSpl_ScaleAndAddVectorsWithRound_mips; #else WebRtcSpl_ScaleAndAddVectorsWithRoundC; #endif #else const MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16C; const MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32C; const MaxValueW16 WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16C; const MaxValueW32 WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32C; const MinValueW16 WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16C; const MinValueW32 WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32C; const CrossCorrelation WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelationC; const DownsampleFast WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFastC; const ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound = WebRtcSpl_ScaleAndAddVectorsWithRoundC; #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/spl_inl.c0000664000175000017500000000205614475643423026145 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include #include "common_audio/signal_processing/include/spl_inl.h" // Table used by WebRtcSpl_CountLeadingZeros32_NotBuiltin. For each uint32_t n // that's a sequence of 0 bits followed by a sequence of 1 bits, the entry at // index (n * 0x8c0b2891) >> 26 in this table gives the number of zero bits in // n. const int8_t kWebRtcSpl_CountLeadingZeros32_Table[64] = { 32, 8, 17, -1, -1, 14, -1, -1, -1, 20, -1, -1, -1, 28, -1, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 26, 25, 24, 4, 11, 23, 31, 3, 7, 10, 16, 22, 30, -1, -1, 2, 6, 13, 9, -1, 15, -1, 21, -1, 29, 19, -1, -1, -1, -1, -1, 1, 27, 5, 12, }; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/spl_sqrt.c0000664000175000017500000001166414475643423026361 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the function WebRtcSpl_Sqrt(). * The description header can be found in signal_processing_library.h * */ #include "rtc_base/checks.h" #include "common_audio/signal_processing/include/signal_processing_library.h" int32_t WebRtcSpl_SqrtLocal(int32_t in); int32_t WebRtcSpl_SqrtLocal(int32_t in) { int16_t x_half, t16; int32_t A, B, x2; /* The following block performs: y=in/2 x=y-2^30 x_half=x/2^31 t = 1 + (x_half) - 0.5*((x_half)^2) + 0.5*((x_half)^3) - 0.625*((x_half)^4) + 0.875*((x_half)^5) */ B = in / 2; B = B - ((int32_t)0x40000000); // B = in/2 - 1/2 x_half = (int16_t)(B >> 16); // x_half = x/2 = (in-1)/2 B = B + ((int32_t)0x40000000); // B = 1 + x/2 B = B + ((int32_t)0x40000000); // Add 0.5 twice (since 1.0 does not exist in Q31) x2 = ((int32_t)x_half) * ((int32_t)x_half) * 2; // A = (x/2)^2 A = -x2; // A = -(x/2)^2 B = B + (A >> 1); // B = 1 + x/2 - 0.5*(x/2)^2 A >>= 16; A = A * A * 2; // A = (x/2)^4 t16 = (int16_t)(A >> 16); B += -20480 * t16 * 2; // B = B - 0.625*A // After this, B = 1 + x/2 - 0.5*(x/2)^2 - 0.625*(x/2)^4 A = x_half * t16 * 2; // A = (x/2)^5 t16 = (int16_t)(A >> 16); B += 28672 * t16 * 2; // B = B + 0.875*A // After this, B = 1 + x/2 - 0.5*(x/2)^2 - 0.625*(x/2)^4 + 0.875*(x/2)^5 t16 = (int16_t)(x2 >> 16); A = x_half * t16 * 2; // A = x/2^3 B = B + (A >> 1); // B = B + 0.5*A // After this, B = 1 + x/2 - 0.5*(x/2)^2 + 0.5*(x/2)^3 - 0.625*(x/2)^4 + 0.875*(x/2)^5 B = B + ((int32_t)32768); // Round off bit return B; } int32_t WebRtcSpl_Sqrt(int32_t value) { /* Algorithm: Six term Taylor Series is used here to compute the square root of a number y^0.5 = (1+x)^0.5 where x = y-1 = 1+(x/2)-0.5*((x/2)^2+0.5*((x/2)^3-0.625*((x/2)^4+0.875*((x/2)^5) 0.5 <= x < 1 Example of how the algorithm works, with ut=sqrt(in), and with in=73632 and ut=271 (even shift value case): in=73632 y= in/131072 x=y-1 t = 1 + (x/2) - 0.5*((x/2)^2) + 0.5*((x/2)^3) - 0.625*((x/2)^4) + 0.875*((x/2)^5) ut=t*(1/sqrt(2))*512 or: in=73632 in2=73632*2^14 y= in2/2^31 x=y-1 t = 1 + (x/2) - 0.5*((x/2)^2) + 0.5*((x/2)^3) - 0.625*((x/2)^4) + 0.875*((x/2)^5) ut=t*(1/sqrt(2)) ut2=ut*2^9 which gives: in = 73632 in2 = 1206386688 y = 0.56176757812500 x = -0.43823242187500 t = 0.74973506527313 ut = 0.53014274874797 ut2 = 2.714330873589594e+002 or: in=73632 in2=73632*2^14 y=in2/2 x=y-2^30 x_half=x/2^31 t = 1 + (x_half) - 0.5*((x_half)^2) + 0.5*((x_half)^3) - 0.625*((x_half)^4) + 0.875*((x_half)^5) ut=t*(1/sqrt(2)) ut2=ut*2^9 which gives: in = 73632 in2 = 1206386688 y = 603193344 x = -470548480 x_half = -0.21911621093750 t = 0.74973506527313 ut = 0.53014274874797 ut2 = 2.714330873589594e+002 */ int16_t x_norm, nshift, t16, sh; int32_t A; int16_t k_sqrt_2 = 23170; // 1/sqrt2 (==5a82) A = value; // The convention in this function is to calculate sqrt(abs(A)). Negate the // input if it is negative. if (A < 0) { if (A == WEBRTC_SPL_WORD32_MIN) { // This number cannot be held in an int32_t after negating. // Map it to the maximum positive value. A = WEBRTC_SPL_WORD32_MAX; } else { A = -A; } } else if (A == 0) { return 0; // sqrt(0) = 0 } sh = WebRtcSpl_NormW32(A); // # shifts to normalize A A = WEBRTC_SPL_LSHIFT_W32(A, sh); // Normalize A if (A < (WEBRTC_SPL_WORD32_MAX - 32767)) { A = A + ((int32_t)32768); // Round off bit } else { A = WEBRTC_SPL_WORD32_MAX; } x_norm = (int16_t)(A >> 16); // x_norm = AH nshift = (sh / 2); RTC_DCHECK_GE(nshift, 0); A = (int32_t)WEBRTC_SPL_LSHIFT_W32((int32_t)x_norm, 16); A = WEBRTC_SPL_ABS_W32(A); // A = abs(x_norm<<16) A = WebRtcSpl_SqrtLocal(A); // A = sqrt(A) if (2 * nshift == sh) { // Even shift value case t16 = (int16_t)(A >> 16); // t16 = AH A = k_sqrt_2 * t16 * 2; // A = 1/sqrt(2)*t16 A = A + ((int32_t)32768); // Round off A = A & ((int32_t)0x7fff0000); // Round off A >>= 15; // A = A>>16 } else { A >>= 16; // A = A>>16 } A = A & ((int32_t)0x0000ffff); A >>= nshift; // De-normalize the result. return A; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/splitting_filter.c0000664000175000017500000002046614475643423030074 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the splitting filter functions. * */ #include "rtc_base/checks.h" #include "common_audio/signal_processing/include/signal_processing_library.h" // Maximum number of samples in a low/high-band frame. enum { kMaxBandFrameLength = 320 // 10 ms at 64 kHz. }; // QMF filter coefficients in Q16. static const uint16_t WebRtcSpl_kAllPassFilter1[3] = {6418, 36982, 57261}; static const uint16_t WebRtcSpl_kAllPassFilter2[3] = {21333, 49062, 63010}; /////////////////////////////////////////////////////////////////////////////////////////////// // WebRtcSpl_AllPassQMF(...) // // Allpass filter used by the analysis and synthesis parts of the QMF filter. // // Input: // - in_data : Input data sequence (Q10) // - data_length : Length of data sequence (>2) // - filter_coefficients : Filter coefficients (length 3, Q16) // // Input & Output: // - filter_state : Filter state (length 6, Q10). // // Output: // - out_data : Output data sequence (Q10), length equal to // |data_length| // void WebRtcSpl_AllPassQMF(int32_t* in_data, size_t data_length, int32_t* out_data, const uint16_t* filter_coefficients, int32_t* filter_state) { // The procedure is to filter the input with three first order all pass filters // (cascade operations). // // a_3 + q^-1 a_2 + q^-1 a_1 + q^-1 // y[n] = ----------- ----------- ----------- x[n] // 1 + a_3q^-1 1 + a_2q^-1 1 + a_1q^-1 // // The input vector |filter_coefficients| includes these three filter coefficients. // The filter state contains the in_data state, in_data[-1], followed by // the out_data state, out_data[-1]. This is repeated for each cascade. // The first cascade filter will filter the |in_data| and store the output in // |out_data|. The second will the take the |out_data| as input and make an // intermediate storage in |in_data|, to save memory. The third, and final, cascade // filter operation takes the |in_data| (which is the output from the previous cascade // filter) and store the output in |out_data|. // Note that the input vector values are changed during the process. size_t k; int32_t diff; // First all-pass cascade; filter from in_data to out_data. // Let y_i[n] indicate the output of cascade filter i (with filter coefficient a_i) at // vector position n. Then the final output will be y[n] = y_3[n] // First loop, use the states stored in memory. // "diff" should be safe from wrap around since max values are 2^25 // diff = (x[0] - y_1[-1]) diff = WebRtcSpl_SubSatW32(in_data[0], filter_state[1]); // y_1[0] = x[-1] + a_1 * (x[0] - y_1[-1]) out_data[0] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[0], diff, filter_state[0]); // For the remaining loops, use previous values. for (k = 1; k < data_length; k++) { // diff = (x[n] - y_1[n-1]) diff = WebRtcSpl_SubSatW32(in_data[k], out_data[k - 1]); // y_1[n] = x[n-1] + a_1 * (x[n] - y_1[n-1]) out_data[k] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[0], diff, in_data[k - 1]); } // Update states. filter_state[0] = in_data[data_length - 1]; // x[N-1], becomes x[-1] next time filter_state[1] = out_data[data_length - 1]; // y_1[N-1], becomes y_1[-1] next time // Second all-pass cascade; filter from out_data to in_data. // diff = (y_1[0] - y_2[-1]) diff = WebRtcSpl_SubSatW32(out_data[0], filter_state[3]); // y_2[0] = y_1[-1] + a_2 * (y_1[0] - y_2[-1]) in_data[0] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[1], diff, filter_state[2]); for (k = 1; k < data_length; k++) { // diff = (y_1[n] - y_2[n-1]) diff = WebRtcSpl_SubSatW32(out_data[k], in_data[k - 1]); // y_2[0] = y_1[-1] + a_2 * (y_1[0] - y_2[-1]) in_data[k] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[1], diff, out_data[k-1]); } filter_state[2] = out_data[data_length - 1]; // y_1[N-1], becomes y_1[-1] next time filter_state[3] = in_data[data_length - 1]; // y_2[N-1], becomes y_2[-1] next time // Third all-pass cascade; filter from in_data to out_data. // diff = (y_2[0] - y[-1]) diff = WebRtcSpl_SubSatW32(in_data[0], filter_state[5]); // y[0] = y_2[-1] + a_3 * (y_2[0] - y[-1]) out_data[0] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[2], diff, filter_state[4]); for (k = 1; k < data_length; k++) { // diff = (y_2[n] - y[n-1]) diff = WebRtcSpl_SubSatW32(in_data[k], out_data[k - 1]); // y[n] = y_2[n-1] + a_3 * (y_2[n] - y[n-1]) out_data[k] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[2], diff, in_data[k-1]); } filter_state[4] = in_data[data_length - 1]; // y_2[N-1], becomes y_2[-1] next time filter_state[5] = out_data[data_length - 1]; // y[N-1], becomes y[-1] next time } void WebRtcSpl_AnalysisQMF(const int16_t* in_data, size_t in_data_length, int16_t* low_band, int16_t* high_band, int32_t* filter_state1, int32_t* filter_state2) { size_t i; int16_t k; int32_t tmp; int32_t half_in1[kMaxBandFrameLength]; int32_t half_in2[kMaxBandFrameLength]; int32_t filter1[kMaxBandFrameLength]; int32_t filter2[kMaxBandFrameLength]; const size_t band_length = in_data_length / 2; RTC_DCHECK_EQ(0, in_data_length % 2); RTC_DCHECK_LE(band_length, kMaxBandFrameLength); // Split even and odd samples. Also shift them to Q10. for (i = 0, k = 0; i < band_length; i++, k += 2) { half_in2[i] = ((int32_t)in_data[k]) * (1 << 10); half_in1[i] = ((int32_t)in_data[k + 1]) * (1 << 10); } // All pass filter even and odd samples, independently. WebRtcSpl_AllPassQMF(half_in1, band_length, filter1, WebRtcSpl_kAllPassFilter1, filter_state1); WebRtcSpl_AllPassQMF(half_in2, band_length, filter2, WebRtcSpl_kAllPassFilter2, filter_state2); // Take the sum and difference of filtered version of odd and even // branches to get upper & lower band. for (i = 0; i < band_length; i++) { tmp = (filter1[i] + filter2[i] + 1024) >> 11; low_band[i] = WebRtcSpl_SatW32ToW16(tmp); tmp = (filter1[i] - filter2[i] + 1024) >> 11; high_band[i] = WebRtcSpl_SatW32ToW16(tmp); } } void WebRtcSpl_SynthesisQMF(const int16_t* low_band, const int16_t* high_band, size_t band_length, int16_t* out_data, int32_t* filter_state1, int32_t* filter_state2) { int32_t tmp; int32_t half_in1[kMaxBandFrameLength]; int32_t half_in2[kMaxBandFrameLength]; int32_t filter1[kMaxBandFrameLength]; int32_t filter2[kMaxBandFrameLength]; size_t i; int16_t k; RTC_DCHECK_LE(band_length, kMaxBandFrameLength); // Obtain the sum and difference channels out of upper and lower-band channels. // Also shift to Q10 domain. for (i = 0; i < band_length; i++) { tmp = (int32_t)low_band[i] + (int32_t)high_band[i]; half_in1[i] = tmp * (1 << 10); tmp = (int32_t)low_band[i] - (int32_t)high_band[i]; half_in2[i] = tmp * (1 << 10); } // all-pass filter the sum and difference channels WebRtcSpl_AllPassQMF(half_in1, band_length, filter1, WebRtcSpl_kAllPassFilter2, filter_state1); WebRtcSpl_AllPassQMF(half_in2, band_length, filter2, WebRtcSpl_kAllPassFilter1, filter_state2); // The filtered signals are even and odd samples of the output. Combine // them. The signals are Q10 should shift them back to Q0 and take care of // saturation. for (i = 0, k = 0; i < band_length; i++) { tmp = (filter2[i] + 512) >> 10; out_data[k++] = WebRtcSpl_SatW32ToW16(tmp); tmp = (filter1[i] + 512) >> 10; out_data[k++] = WebRtcSpl_SatW32ToW16(tmp); } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c0000664000175000017500000000213014475643423032302 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains the function WebRtcSpl_SqrtOfOneMinusXSquared(). * The description header can be found in signal_processing_library.h * */ #include "common_audio/signal_processing/include/signal_processing_library.h" void WebRtcSpl_SqrtOfOneMinusXSquared(int16_t *xQ15, size_t vector_length, int16_t *yQ15) { int32_t sq; size_t m; int16_t tmp; for (m = 0; m < vector_length; m++) { tmp = xQ15[m]; sq = tmp * tmp; // x^2 in Q30 sq = 1073741823 - sq; // 1-x^2, where 1 ~= 0.99999999906 is 1073741823 in Q30 sq = WebRtcSpl_Sqrt(sq); // sqrt(1-x^2) in Q15 yQ15[m] = (int16_t)sq; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/vector_scaling_operations.c0000664000175000017500000001145514475643423031755 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains implementations of the functions * WebRtcSpl_VectorBitShiftW16() * WebRtcSpl_VectorBitShiftW32() * WebRtcSpl_VectorBitShiftW32ToW16() * WebRtcSpl_ScaleVector() * WebRtcSpl_ScaleVectorWithSat() * WebRtcSpl_ScaleAndAddVectors() * WebRtcSpl_ScaleAndAddVectorsWithRoundC() */ #include "common_audio/signal_processing/include/signal_processing_library.h" void WebRtcSpl_VectorBitShiftW16(int16_t *res, size_t length, const int16_t *in, int16_t right_shifts) { size_t i; if (right_shifts > 0) { for (i = length; i > 0; i--) { (*res++) = ((*in++) >> right_shifts); } } else { for (i = length; i > 0; i--) { (*res++) = ((*in++) * (1 << (-right_shifts))); } } } void WebRtcSpl_VectorBitShiftW32(int32_t *out_vector, size_t vector_length, const int32_t *in_vector, int16_t right_shifts) { size_t i; if (right_shifts > 0) { for (i = vector_length; i > 0; i--) { (*out_vector++) = ((*in_vector++) >> right_shifts); } } else { for (i = vector_length; i > 0; i--) { (*out_vector++) = ((*in_vector++) << (-right_shifts)); } } } void WebRtcSpl_VectorBitShiftW32ToW16(int16_t* out, size_t length, const int32_t* in, int right_shifts) { size_t i; int32_t tmp_w32; if (right_shifts >= 0) { for (i = length; i > 0; i--) { tmp_w32 = (*in++) >> right_shifts; (*out++) = WebRtcSpl_SatW32ToW16(tmp_w32); } } else { int left_shifts = -right_shifts; for (i = length; i > 0; i--) { tmp_w32 = (*in++) << left_shifts; (*out++) = WebRtcSpl_SatW32ToW16(tmp_w32); } } } void WebRtcSpl_ScaleVector(const int16_t *in_vector, int16_t *out_vector, int16_t gain, size_t in_vector_length, int16_t right_shifts) { // Performs vector operation: out_vector = (gain*in_vector)>>right_shifts size_t i; const int16_t *inptr; int16_t *outptr; inptr = in_vector; outptr = out_vector; for (i = 0; i < in_vector_length; i++) { *outptr++ = (int16_t)((*inptr++ * gain) >> right_shifts); } } void WebRtcSpl_ScaleVectorWithSat(const int16_t *in_vector, int16_t *out_vector, int16_t gain, size_t in_vector_length, int16_t right_shifts) { // Performs vector operation: out_vector = (gain*in_vector)>>right_shifts size_t i; const int16_t *inptr; int16_t *outptr; inptr = in_vector; outptr = out_vector; for (i = 0; i < in_vector_length; i++) { *outptr++ = WebRtcSpl_SatW32ToW16((*inptr++ * gain) >> right_shifts); } } void WebRtcSpl_ScaleAndAddVectors(const int16_t *in1, int16_t gain1, int shift1, const int16_t *in2, int16_t gain2, int shift2, int16_t *out, size_t vector_length) { // Performs vector operation: out = (gain1*in1)>>shift1 + (gain2*in2)>>shift2 size_t i; const int16_t *in1ptr; const int16_t *in2ptr; int16_t *outptr; in1ptr = in1; in2ptr = in2; outptr = out; for (i = 0; i < vector_length; i++) { *outptr++ = (int16_t)((gain1 * *in1ptr++) >> shift1) + (int16_t)((gain2 * *in2ptr++) >> shift2); } } // C version of WebRtcSpl_ScaleAndAddVectorsWithRound() for generic platforms. int WebRtcSpl_ScaleAndAddVectorsWithRoundC(const int16_t* in_vector1, int16_t in_vector1_scale, const int16_t* in_vector2, int16_t in_vector2_scale, int right_shifts, int16_t* out_vector, size_t length) { size_t i = 0; int round_value = (1 << right_shifts) >> 1; if (in_vector1 == NULL || in_vector2 == NULL || out_vector == NULL || length == 0 || right_shifts < 0) { return -1; } for (i = 0; i < length; i++) { out_vector[i] = (int16_t)(( in_vector1[i] * in_vector1_scale + in_vector2[i] * in_vector2_scale + round_value) >> right_shifts); } return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/signal_processing/vector_scaling_operations_mips.c0000664000175000017500000000470514475643423033005 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file contains implementations of the functions * WebRtcSpl_ScaleAndAddVectorsWithRound_mips() */ #include "common_audio/signal_processing/include/signal_processing_library.h" int WebRtcSpl_ScaleAndAddVectorsWithRound_mips(const int16_t* in_vector1, int16_t in_vector1_scale, const int16_t* in_vector2, int16_t in_vector2_scale, int right_shifts, int16_t* out_vector, size_t length) { int16_t r0 = 0, r1 = 0; int16_t *in1 = (int16_t*)in_vector1; int16_t *in2 = (int16_t*)in_vector2; int16_t *out = out_vector; size_t i = 0; int value32 = 0; if (in_vector1 == NULL || in_vector2 == NULL || out_vector == NULL || length == 0 || right_shifts < 0) { return -1; } for (i = 0; i < length; i++) { __asm __volatile ( "lh %[r0], 0(%[in1]) \n\t" "lh %[r1], 0(%[in2]) \n\t" "mult %[r0], %[in_vector1_scale] \n\t" "madd %[r1], %[in_vector2_scale] \n\t" "extrv_r.w %[value32], $ac0, %[right_shifts] \n\t" "addiu %[in1], %[in1], 2 \n\t" "addiu %[in2], %[in2], 2 \n\t" "sh %[value32], 0(%[out]) \n\t" "addiu %[out], %[out], 2 \n\t" : [value32] "=&r" (value32), [out] "+r" (out), [in1] "+r" (in1), [in2] "+r" (in2), [r0] "=&r" (r0), [r1] "=&r" (r1) : [in_vector1_scale] "r" (in_vector1_scale), [in_vector2_scale] "r" (in_vector2_scale), [right_shifts] "r" (right_shifts) : "hi", "lo", "memory" ); } return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/smoothing_filter.cc0000664000175000017500000001223314475643423024511 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/smoothing_filter.h" #include #include #include "rtc_base/checks.h" #include "rtc_base/time_utils.h" namespace webrtc { SmoothingFilterImpl::SmoothingFilterImpl(int init_time_ms) : init_time_ms_(init_time_ms), // Duing the initalization time, we use an increasing alpha. Specifically, // alpha(n) = exp(-powf(init_factor_, n)), // where |init_factor_| is chosen such that // alpha(init_time_ms_) = exp(-1.0f / init_time_ms_), init_factor_(init_time_ms_ == 0 ? 0.0f : powf(init_time_ms_, -1.0f / init_time_ms_)), // |init_const_| is to a factor to help the calculation during // initialization phase. init_const_(init_time_ms_ == 0 ? 0.0f : init_time_ms_ - powf(init_time_ms_, 1.0f - 1.0f / init_time_ms_)) { UpdateAlpha(init_time_ms_); } SmoothingFilterImpl::~SmoothingFilterImpl() = default; void SmoothingFilterImpl::AddSample(float sample) { const int64_t now_ms = rtc::TimeMillis(); if (!init_end_time_ms_) { // This is equivalent to assuming the filter has been receiving the same // value as the first sample since time -infinity. state_ = last_sample_ = sample; init_end_time_ms_ = now_ms + init_time_ms_; last_state_time_ms_ = now_ms; return; } ExtrapolateLastSample(now_ms); last_sample_ = sample; } absl::optional SmoothingFilterImpl::GetAverage() { if (!init_end_time_ms_) { // |init_end_time_ms_| undefined since we have not received any sample. return absl::nullopt; } ExtrapolateLastSample(rtc::TimeMillis()); return state_; } bool SmoothingFilterImpl::SetTimeConstantMs(int time_constant_ms) { if (!init_end_time_ms_ || last_state_time_ms_ < *init_end_time_ms_) { return false; } UpdateAlpha(time_constant_ms); return true; } void SmoothingFilterImpl::UpdateAlpha(int time_constant_ms) { alpha_ = time_constant_ms == 0 ? 0.0f : std::exp(-1.0f / time_constant_ms); } void SmoothingFilterImpl::ExtrapolateLastSample(int64_t time_ms) { RTC_DCHECK_GE(time_ms, last_state_time_ms_); RTC_DCHECK(init_end_time_ms_); float multiplier = 0.0f; if (time_ms <= *init_end_time_ms_) { // Current update is to be made during initialization phase. // We update the state as if the |alpha| has been increased according // alpha(n) = exp(-powf(init_factor_, n)), // where n is the time (in millisecond) since the first sample received. // With algebraic derivation as shown in the Appendix, we can find that the // state can be updated in a similar manner as if alpha is a constant, // except for a different multiplier. if (init_time_ms_ == 0) { // This means |init_factor_| = 0. multiplier = 0.0f; } else if (init_time_ms_ == 1) { // This means |init_factor_| = 1. multiplier = std::exp(last_state_time_ms_ - time_ms); } else { multiplier = std::exp( -(powf(init_factor_, last_state_time_ms_ - *init_end_time_ms_) - powf(init_factor_, time_ms - *init_end_time_ms_)) / init_const_); } } else { if (last_state_time_ms_ < *init_end_time_ms_) { // The latest state update was made during initialization phase. // We first extrapolate to the initialization time. ExtrapolateLastSample(*init_end_time_ms_); // Then extrapolate the rest by the following. } multiplier = powf(alpha_, time_ms - last_state_time_ms_); } state_ = multiplier * state_ + (1.0f - multiplier) * last_sample_; last_state_time_ms_ = time_ms; } } // namespace webrtc // Appendix: derivation of extrapolation during initialization phase. // (LaTeX syntax) // Assuming // \begin{align} // y(n) &= \alpha_{n-1} y(n-1) + \left(1 - \alpha_{n-1}\right) x(m) \\* // &= \left(\prod_{i=m}^{n-1} \alpha_i\right) y(m) + // \left(1 - \prod_{i=m}^{n-1} \alpha_i \right) x(m) // \end{align} // Taking $\alpha_{n} = \exp(-\gamma^n)$, $\gamma$ denotes init\_factor\_, the // multiplier becomes // \begin{align} // \prod_{i=m}^{n-1} \alpha_i // &= \exp\left(-\sum_{i=m}^{n-1} \gamma^i \right) \\* // &= \begin{cases} // \exp\left(-\frac{\gamma^m - \gamma^n}{1 - \gamma} \right) // & \gamma \neq 1 \\* // m-n & \gamma = 1 // \end{cases} // \end{align} // We know $\gamma = T^{-\frac{1}{T}}$, where $T$ denotes init\_time\_ms\_. Then // $1 - \gamma$ approaches zero when $T$ increases. This can cause numerical // difficulties. We multiply $T$ (if $T > 0$) to both numerator and denominator // in the fraction. See. // \begin{align} // \frac{\gamma^m - \gamma^n}{1 - \gamma} // &= \frac{T^\frac{T-m}{T} - T^\frac{T-n}{T}}{T - T^{1-\frac{1}{T}}} // \end{align} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/smoothing_filter.h0000664000175000017500000000477714475643423024371 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_SMOOTHING_FILTER_H_ #define COMMON_AUDIO_SMOOTHING_FILTER_H_ #include #include "absl/types/optional.h" namespace webrtc { class SmoothingFilter { public: virtual ~SmoothingFilter() = default; virtual void AddSample(float sample) = 0; virtual absl::optional GetAverage() = 0; virtual bool SetTimeConstantMs(int time_constant_ms) = 0; }; // SmoothingFilterImpl applies an exponential filter // alpha = exp(-1.0 / time_constant_ms); // y[t] = alpha * y[t-1] + (1 - alpha) * sample; // This implies a sample rate of 1000 Hz, i.e., 1 sample / ms. // But SmoothingFilterImpl allows sparse samples. All missing samples will be // assumed to equal the last received sample. class SmoothingFilterImpl final : public SmoothingFilter { public: // |init_time_ms| is initialization time. It defines a period starting from // the arriving time of the first sample. During this period, the exponential // filter uses a varying time constant so that a smaller time constant will be // applied to the earlier samples. This is to allow the the filter to adapt to // earlier samples quickly. After the initialization period, the time constant // will be set to |init_time_ms| first and can be changed through // |SetTimeConstantMs|. explicit SmoothingFilterImpl(int init_time_ms); SmoothingFilterImpl() = delete; SmoothingFilterImpl(const SmoothingFilterImpl&) = delete; SmoothingFilterImpl& operator=(const SmoothingFilterImpl&) = delete; ~SmoothingFilterImpl() override; void AddSample(float sample) override; absl::optional GetAverage() override; bool SetTimeConstantMs(int time_constant_ms) override; // Methods used for unittests. float alpha() const { return alpha_; } private: void UpdateAlpha(int time_constant_ms); void ExtrapolateLastSample(int64_t time_ms); const int init_time_ms_; const float init_factor_; const float init_const_; absl::optional init_end_time_ms_; float last_sample_; float alpha_; float state_; int64_t last_state_time_ms_; }; } // namespace webrtc #endif // COMMON_AUDIO_SMOOTHING_FILTER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/0000775000175000017500000000000014475643423023156 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/ooura/0000775000175000017500000000000014475643423024303 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/ooura/BUILD.gn0000664000175000017500000000302414475643423025467 0ustar00arunarun# Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the ../../../LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../../../webrtc.gni") rtc_library("fft_size_128") { sources = [ "fft_size_128/ooura_fft.cc", "fft_size_128/ooura_fft.h", "fft_size_128/ooura_fft_tables_common.h", ] deps = [ "../../../rtc_base/system:arch", "../../../system_wrappers", ] cflags = [] if (current_cpu == "x86" || current_cpu == "x64") { sources += [ "fft_size_128/ooura_fft_sse2.cc", "fft_size_128/ooura_fft_tables_neon_sse2.h", ] if (is_posix || is_fuchsia) { cflags += [ "-msse2" ] } } if (rtc_build_with_neon) { sources += [ "fft_size_128/ooura_fft_neon.cc", "fft_size_128/ooura_fft_tables_neon_sse2.h", ] deps += [ "../../../common_audio" ] if (current_cpu != "arm64") { # Enable compilation for the NEON instruction set. suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ] cflags += [ "-mfpu=neon" ] } } if (current_cpu == "mipsel" && mips_float_abi == "hard") { sources += [ "fft_size_128/ooura_fft_mips.cc" ] } } rtc_library("fft_size_256") { sources = [ "fft_size_256/fft4g.cc", "fft_size_256/fft4g.h", ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/ooura/LICENSE0000664000175000017500000000042014475643423025304 0ustar00arunarun/* * http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html * Copyright Takuya OOURA, 1996-2001 * * You may use, copy, modify and distribute this code for any purpose (include * commercial use) and without fee. Please refer to this package when you modify * this code. */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/ooura/fft_size_128/0000775000175000017500000000000014475643423026506 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft.cc0000664000175000017500000003304414475643423031005 0ustar00arunarun/* * http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html * Copyright Takuya OOURA, 1996-2001 * * You may use, copy, modify and distribute this code for any purpose (include * commercial use) and without fee. Please refer to this package when you modify * this code. * * Changes by the WebRTC authors: * - Trivial type modifications. * - Minimal code subset to do rdft of length 128. * - Optimizations because of known length. * - Removed the global variables by moving the code in to a class in order * to make it thread safe. * * All changes are covered by the WebRTC license and IP grant: * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h" #include "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h" #include "rtc_base/system/arch.h" #include "system_wrappers/include/cpu_features_wrapper.h" namespace webrtc { namespace { #if !(defined(MIPS_FPU_LE) || defined(WEBRTC_HAS_NEON)) static void cft1st_128_C(float* a) { const int n = 128; int j, k1, k2; float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; // The processing of the first set of elements was simplified in C to avoid // some operations (multiplication by zero or one, addition of two elements // multiplied by the same weight, ...). x0r = a[0] + a[2]; x0i = a[1] + a[3]; x1r = a[0] - a[2]; x1i = a[1] - a[3]; x2r = a[4] + a[6]; x2i = a[5] + a[7]; x3r = a[4] - a[6]; x3i = a[5] - a[7]; a[0] = x0r + x2r; a[1] = x0i + x2i; a[4] = x0r - x2r; a[5] = x0i - x2i; a[2] = x1r - x3i; a[3] = x1i + x3r; a[6] = x1r + x3i; a[7] = x1i - x3r; wk1r = rdft_w[2]; x0r = a[8] + a[10]; x0i = a[9] + a[11]; x1r = a[8] - a[10]; x1i = a[9] - a[11]; x2r = a[12] + a[14]; x2i = a[13] + a[15]; x3r = a[12] - a[14]; x3i = a[13] - a[15]; a[8] = x0r + x2r; a[9] = x0i + x2i; a[12] = x2i - x0i; a[13] = x0r - x2r; x0r = x1r - x3i; x0i = x1i + x3r; a[10] = wk1r * (x0r - x0i); a[11] = wk1r * (x0r + x0i); x0r = x3i + x1r; x0i = x3r - x1i; a[14] = wk1r * (x0i - x0r); a[15] = wk1r * (x0i + x0r); k1 = 0; for (j = 16; j < n; j += 16) { k1 += 2; k2 = 2 * k1; wk2r = rdft_w[k1 + 0]; wk2i = rdft_w[k1 + 1]; wk1r = rdft_w[k2 + 0]; wk1i = rdft_w[k2 + 1]; wk3r = rdft_wk3ri_first[k1 + 0]; wk3i = rdft_wk3ri_first[k1 + 1]; x0r = a[j + 0] + a[j + 2]; x0i = a[j + 1] + a[j + 3]; x1r = a[j + 0] - a[j + 2]; x1i = a[j + 1] - a[j + 3]; x2r = a[j + 4] + a[j + 6]; x2i = a[j + 5] + a[j + 7]; x3r = a[j + 4] - a[j + 6]; x3i = a[j + 5] - a[j + 7]; a[j + 0] = x0r + x2r; a[j + 1] = x0i + x2i; x0r -= x2r; x0i -= x2i; a[j + 4] = wk2r * x0r - wk2i * x0i; a[j + 5] = wk2r * x0i + wk2i * x0r; x0r = x1r - x3i; x0i = x1i + x3r; a[j + 2] = wk1r * x0r - wk1i * x0i; a[j + 3] = wk1r * x0i + wk1i * x0r; x0r = x1r + x3i; x0i = x1i - x3r; a[j + 6] = wk3r * x0r - wk3i * x0i; a[j + 7] = wk3r * x0i + wk3i * x0r; wk1r = rdft_w[k2 + 2]; wk1i = rdft_w[k2 + 3]; wk3r = rdft_wk3ri_second[k1 + 0]; wk3i = rdft_wk3ri_second[k1 + 1]; x0r = a[j + 8] + a[j + 10]; x0i = a[j + 9] + a[j + 11]; x1r = a[j + 8] - a[j + 10]; x1i = a[j + 9] - a[j + 11]; x2r = a[j + 12] + a[j + 14]; x2i = a[j + 13] + a[j + 15]; x3r = a[j + 12] - a[j + 14]; x3i = a[j + 13] - a[j + 15]; a[j + 8] = x0r + x2r; a[j + 9] = x0i + x2i; x0r -= x2r; x0i -= x2i; a[j + 12] = -wk2i * x0r - wk2r * x0i; a[j + 13] = -wk2i * x0i + wk2r * x0r; x0r = x1r - x3i; x0i = x1i + x3r; a[j + 10] = wk1r * x0r - wk1i * x0i; a[j + 11] = wk1r * x0i + wk1i * x0r; x0r = x1r + x3i; x0i = x1i - x3r; a[j + 14] = wk3r * x0r - wk3i * x0i; a[j + 15] = wk3r * x0i + wk3i * x0r; } } static void cftmdl_128_C(float* a) { const int l = 8; const int n = 128; const int m = 32; int j0, j1, j2, j3, k, k1, k2, m2; float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; for (j0 = 0; j0 < l; j0 += 2) { j1 = j0 + 8; j2 = j0 + 16; j3 = j0 + 24; x0r = a[j0 + 0] + a[j1 + 0]; x0i = a[j0 + 1] + a[j1 + 1]; x1r = a[j0 + 0] - a[j1 + 0]; x1i = a[j0 + 1] - a[j1 + 1]; x2r = a[j2 + 0] + a[j3 + 0]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2 + 0] - a[j3 + 0]; x3i = a[j2 + 1] - a[j3 + 1]; a[j0 + 0] = x0r + x2r; a[j0 + 1] = x0i + x2i; a[j2 + 0] = x0r - x2r; a[j2 + 1] = x0i - x2i; a[j1 + 0] = x1r - x3i; a[j1 + 1] = x1i + x3r; a[j3 + 0] = x1r + x3i; a[j3 + 1] = x1i - x3r; } wk1r = rdft_w[2]; for (j0 = m; j0 < l + m; j0 += 2) { j1 = j0 + 8; j2 = j0 + 16; j3 = j0 + 24; x0r = a[j0 + 0] + a[j1 + 0]; x0i = a[j0 + 1] + a[j1 + 1]; x1r = a[j0 + 0] - a[j1 + 0]; x1i = a[j0 + 1] - a[j1 + 1]; x2r = a[j2 + 0] + a[j3 + 0]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2 + 0] - a[j3 + 0]; x3i = a[j2 + 1] - a[j3 + 1]; a[j0 + 0] = x0r + x2r; a[j0 + 1] = x0i + x2i; a[j2 + 0] = x2i - x0i; a[j2 + 1] = x0r - x2r; x0r = x1r - x3i; x0i = x1i + x3r; a[j1 + 0] = wk1r * (x0r - x0i); a[j1 + 1] = wk1r * (x0r + x0i); x0r = x3i + x1r; x0i = x3r - x1i; a[j3 + 0] = wk1r * (x0i - x0r); a[j3 + 1] = wk1r * (x0i + x0r); } k1 = 0; m2 = 2 * m; for (k = m2; k < n; k += m2) { k1 += 2; k2 = 2 * k1; wk2r = rdft_w[k1 + 0]; wk2i = rdft_w[k1 + 1]; wk1r = rdft_w[k2 + 0]; wk1i = rdft_w[k2 + 1]; wk3r = rdft_wk3ri_first[k1 + 0]; wk3i = rdft_wk3ri_first[k1 + 1]; for (j0 = k; j0 < l + k; j0 += 2) { j1 = j0 + 8; j2 = j0 + 16; j3 = j0 + 24; x0r = a[j0 + 0] + a[j1 + 0]; x0i = a[j0 + 1] + a[j1 + 1]; x1r = a[j0 + 0] - a[j1 + 0]; x1i = a[j0 + 1] - a[j1 + 1]; x2r = a[j2 + 0] + a[j3 + 0]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2 + 0] - a[j3 + 0]; x3i = a[j2 + 1] - a[j3 + 1]; a[j0 + 0] = x0r + x2r; a[j0 + 1] = x0i + x2i; x0r -= x2r; x0i -= x2i; a[j2 + 0] = wk2r * x0r - wk2i * x0i; a[j2 + 1] = wk2r * x0i + wk2i * x0r; x0r = x1r - x3i; x0i = x1i + x3r; a[j1 + 0] = wk1r * x0r - wk1i * x0i; a[j1 + 1] = wk1r * x0i + wk1i * x0r; x0r = x1r + x3i; x0i = x1i - x3r; a[j3 + 0] = wk3r * x0r - wk3i * x0i; a[j3 + 1] = wk3r * x0i + wk3i * x0r; } wk1r = rdft_w[k2 + 2]; wk1i = rdft_w[k2 + 3]; wk3r = rdft_wk3ri_second[k1 + 0]; wk3i = rdft_wk3ri_second[k1 + 1]; for (j0 = k + m; j0 < l + (k + m); j0 += 2) { j1 = j0 + 8; j2 = j0 + 16; j3 = j0 + 24; x0r = a[j0 + 0] + a[j1 + 0]; x0i = a[j0 + 1] + a[j1 + 1]; x1r = a[j0 + 0] - a[j1 + 0]; x1i = a[j0 + 1] - a[j1 + 1]; x2r = a[j2 + 0] + a[j3 + 0]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2 + 0] - a[j3 + 0]; x3i = a[j2 + 1] - a[j3 + 1]; a[j0 + 0] = x0r + x2r; a[j0 + 1] = x0i + x2i; x0r -= x2r; x0i -= x2i; a[j2 + 0] = -wk2i * x0r - wk2r * x0i; a[j2 + 1] = -wk2i * x0i + wk2r * x0r; x0r = x1r - x3i; x0i = x1i + x3r; a[j1 + 0] = wk1r * x0r - wk1i * x0i; a[j1 + 1] = wk1r * x0i + wk1i * x0r; x0r = x1r + x3i; x0i = x1i - x3r; a[j3 + 0] = wk3r * x0r - wk3i * x0i; a[j3 + 1] = wk3r * x0i + wk3i * x0r; } } } static void rftfsub_128_C(float* a) { const float* c = rdft_w + 32; int j1, j2, k1, k2; float wkr, wki, xr, xi, yr, yi; for (j1 = 1, j2 = 2; j2 < 64; j1 += 1, j2 += 2) { k2 = 128 - j2; k1 = 32 - j1; wkr = 0.5f - c[k1]; wki = c[j1]; xr = a[j2 + 0] - a[k2 + 0]; xi = a[j2 + 1] + a[k2 + 1]; yr = wkr * xr - wki * xi; yi = wkr * xi + wki * xr; a[j2 + 0] -= yr; a[j2 + 1] -= yi; a[k2 + 0] += yr; a[k2 + 1] -= yi; } } static void rftbsub_128_C(float* a) { const float* c = rdft_w + 32; int j1, j2, k1, k2; float wkr, wki, xr, xi, yr, yi; a[1] = -a[1]; for (j1 = 1, j2 = 2; j2 < 64; j1 += 1, j2 += 2) { k2 = 128 - j2; k1 = 32 - j1; wkr = 0.5f - c[k1]; wki = c[j1]; xr = a[j2 + 0] - a[k2 + 0]; xi = a[j2 + 1] + a[k2 + 1]; yr = wkr * xr + wki * xi; yi = wkr * xi - wki * xr; a[j2 + 0] = a[j2 + 0] - yr; a[j2 + 1] = yi - a[j2 + 1]; a[k2 + 0] = yr + a[k2 + 0]; a[k2 + 1] = yi - a[k2 + 1]; } a[65] = -a[65]; } #endif } // namespace OouraFft::OouraFft(bool sse2_available) { #if defined(WEBRTC_ARCH_X86_FAMILY) use_sse2_ = sse2_available; #else use_sse2_ = false; #endif } OouraFft::OouraFft() { #if defined(WEBRTC_ARCH_X86_FAMILY) use_sse2_ = (GetCPUInfo(kSSE2) != 0); #else use_sse2_ = false; #endif } OouraFft::~OouraFft() = default; void OouraFft::Fft(float* a) const { float xi; bitrv2_128(a); cftfsub_128(a); rftfsub_128(a); xi = a[0] - a[1]; a[0] += a[1]; a[1] = xi; } void OouraFft::InverseFft(float* a) const { a[1] = 0.5f * (a[0] - a[1]); a[0] -= a[1]; rftbsub_128(a); bitrv2_128(a); cftbsub_128(a); } void OouraFft::cft1st_128(float* a) const { #if defined(MIPS_FPU_LE) cft1st_128_mips(a); #elif defined(WEBRTC_HAS_NEON) cft1st_128_neon(a); #elif defined(WEBRTC_ARCH_X86_FAMILY) if (use_sse2_) { cft1st_128_SSE2(a); } else { cft1st_128_C(a); } #else cft1st_128_C(a); #endif } void OouraFft::cftmdl_128(float* a) const { #if defined(MIPS_FPU_LE) cftmdl_128_mips(a); #elif defined(WEBRTC_HAS_NEON) cftmdl_128_neon(a); #elif defined(WEBRTC_ARCH_X86_FAMILY) if (use_sse2_) { cftmdl_128_SSE2(a); } else { cftmdl_128_C(a); } #else cftmdl_128_C(a); #endif } void OouraFft::rftfsub_128(float* a) const { #if defined(MIPS_FPU_LE) rftfsub_128_mips(a); #elif defined(WEBRTC_HAS_NEON) rftfsub_128_neon(a); #elif defined(WEBRTC_ARCH_X86_FAMILY) if (use_sse2_) { rftfsub_128_SSE2(a); } else { rftfsub_128_C(a); } #else rftfsub_128_C(a); #endif } void OouraFft::rftbsub_128(float* a) const { #if defined(MIPS_FPU_LE) rftbsub_128_mips(a); #elif defined(WEBRTC_HAS_NEON) rftbsub_128_neon(a); #elif defined(WEBRTC_ARCH_X86_FAMILY) if (use_sse2_) { rftbsub_128_SSE2(a); } else { rftbsub_128_C(a); } #else rftbsub_128_C(a); #endif } void OouraFft::cftbsub_128(float* a) const { int j, j1, j2, j3, l; float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; cft1st_128(a); cftmdl_128(a); l = 32; for (j = 0; j < l; j += 2) { j1 = j + l; j2 = j1 + l; j3 = j2 + l; x0r = a[j] + a[j1]; x0i = -a[j + 1] - a[j1 + 1]; x1r = a[j] - a[j1]; x1i = -a[j + 1] + a[j1 + 1]; x2r = a[j2] + a[j3]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2] - a[j3]; x3i = a[j2 + 1] - a[j3 + 1]; a[j] = x0r + x2r; a[j + 1] = x0i - x2i; a[j2] = x0r - x2r; a[j2 + 1] = x0i + x2i; a[j1] = x1r - x3i; a[j1 + 1] = x1i - x3r; a[j3] = x1r + x3i; a[j3 + 1] = x1i + x3r; } } void OouraFft::cftfsub_128(float* a) const { int j, j1, j2, j3, l; float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; cft1st_128(a); cftmdl_128(a); l = 32; for (j = 0; j < l; j += 2) { j1 = j + l; j2 = j1 + l; j3 = j2 + l; x0r = a[j] + a[j1]; x0i = a[j + 1] + a[j1 + 1]; x1r = a[j] - a[j1]; x1i = a[j + 1] - a[j1 + 1]; x2r = a[j2] + a[j3]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2] - a[j3]; x3i = a[j2 + 1] - a[j3 + 1]; a[j] = x0r + x2r; a[j + 1] = x0i + x2i; a[j2] = x0r - x2r; a[j2 + 1] = x0i - x2i; a[j1] = x1r - x3i; a[j1 + 1] = x1i + x3r; a[j3] = x1r + x3i; a[j3 + 1] = x1i - x3r; } } void OouraFft::bitrv2_128(float* a) const { /* Following things have been attempted but are no faster: (a) Storing the swap indexes in a LUT (index calculations are done for 'free' while waiting on memory/L1). (b) Consolidate the load/store of two consecutive floats by a 64 bit integer (execution is memory/L1 bound). (c) Do a mix of floats and 64 bit integer to maximize register utilization (execution is memory/L1 bound). (d) Replacing ip[i] by ((k<<31)>>25) + ((k >> 1)<<5). (e) Hard-coding of the offsets to completely eliminates index calculations. */ unsigned int j, j1, k, k1; float xr, xi, yr, yi; const int ip[4] = {0, 64, 32, 96}; for (k = 0; k < 4; k++) { for (j = 0; j < k; j++) { j1 = 2 * j + ip[k]; k1 = 2 * k + ip[j]; xr = a[j1 + 0]; xi = a[j1 + 1]; yr = a[k1 + 0]; yi = a[k1 + 1]; a[j1 + 0] = yr; a[j1 + 1] = yi; a[k1 + 0] = xr; a[k1 + 1] = xi; j1 += 8; k1 += 16; xr = a[j1 + 0]; xi = a[j1 + 1]; yr = a[k1 + 0]; yi = a[k1 + 1]; a[j1 + 0] = yr; a[j1 + 1] = yi; a[k1 + 0] = xr; a[k1 + 1] = xi; j1 += 8; k1 -= 8; xr = a[j1 + 0]; xi = a[j1 + 1]; yr = a[k1 + 0]; yi = a[k1 + 1]; a[j1 + 0] = yr; a[j1 + 1] = yi; a[k1 + 0] = xr; a[k1 + 1] = xi; j1 += 8; k1 += 16; xr = a[j1 + 0]; xi = a[j1 + 1]; yr = a[k1 + 0]; yi = a[k1 + 1]; a[j1 + 0] = yr; a[j1 + 1] = yi; a[k1 + 0] = xr; a[k1 + 1] = xi; } j1 = 2 * k + 8 + ip[k]; k1 = j1 + 8; xr = a[j1 + 0]; xi = a[j1 + 1]; yr = a[k1 + 0]; yi = a[k1 + 1]; a[j1 + 0] = yr; a[j1 + 1] = yi; a[k1 + 0] = xr; a[k1 + 1] = xi; } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft.h0000664000175000017500000000327514475643423030652 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_H_ #define MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_H_ #include "rtc_base/system/arch.h" namespace webrtc { #if defined(WEBRTC_ARCH_X86_FAMILY) void cft1st_128_SSE2(float* a); void cftmdl_128_SSE2(float* a); void rftfsub_128_SSE2(float* a); void rftbsub_128_SSE2(float* a); #endif #if defined(MIPS_FPU_LE) void cft1st_128_mips(float* a); void cftmdl_128_mips(float* a); void rftfsub_128_mips(float* a); void rftbsub_128_mips(float* a); #endif #if defined(WEBRTC_HAS_NEON) void cft1st_128_neon(float* a); void cftmdl_128_neon(float* a); void rftfsub_128_neon(float* a); void rftbsub_128_neon(float* a); #endif class OouraFft { public: // Ctor allowing the availability of SSE2 support to be specified. explicit OouraFft(bool sse2_available); // Deprecated: This Ctor will soon be removed. OouraFft(); ~OouraFft(); void Fft(float* a) const; void InverseFft(float* a) const; private: void cft1st_128(float* a) const; void cftmdl_128(float* a) const; void rftfsub_128(float* a) const; void rftbsub_128(float* a) const; void cftfsub_128(float* a) const; void cftbsub_128(float* a) const; void bitrv2_128(float* a) const; bool use_sse2_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_mips.cc0000664000175000017500000017566714475643423032057 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h" #include "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h" namespace webrtc { #if defined(MIPS_FPU_LE) void bitrv2_128_mips(float* a) { // n is 128 float xr, xi, yr, yi; xr = a[8]; xi = a[9]; yr = a[16]; yi = a[17]; a[8] = yr; a[9] = yi; a[16] = xr; a[17] = xi; xr = a[64]; xi = a[65]; yr = a[2]; yi = a[3]; a[64] = yr; a[65] = yi; a[2] = xr; a[3] = xi; xr = a[72]; xi = a[73]; yr = a[18]; yi = a[19]; a[72] = yr; a[73] = yi; a[18] = xr; a[19] = xi; xr = a[80]; xi = a[81]; yr = a[10]; yi = a[11]; a[80] = yr; a[81] = yi; a[10] = xr; a[11] = xi; xr = a[88]; xi = a[89]; yr = a[26]; yi = a[27]; a[88] = yr; a[89] = yi; a[26] = xr; a[27] = xi; xr = a[74]; xi = a[75]; yr = a[82]; yi = a[83]; a[74] = yr; a[75] = yi; a[82] = xr; a[83] = xi; xr = a[32]; xi = a[33]; yr = a[4]; yi = a[5]; a[32] = yr; a[33] = yi; a[4] = xr; a[5] = xi; xr = a[40]; xi = a[41]; yr = a[20]; yi = a[21]; a[40] = yr; a[41] = yi; a[20] = xr; a[21] = xi; xr = a[48]; xi = a[49]; yr = a[12]; yi = a[13]; a[48] = yr; a[49] = yi; a[12] = xr; a[13] = xi; xr = a[56]; xi = a[57]; yr = a[28]; yi = a[29]; a[56] = yr; a[57] = yi; a[28] = xr; a[29] = xi; xr = a[34]; xi = a[35]; yr = a[68]; yi = a[69]; a[34] = yr; a[35] = yi; a[68] = xr; a[69] = xi; xr = a[42]; xi = a[43]; yr = a[84]; yi = a[85]; a[42] = yr; a[43] = yi; a[84] = xr; a[85] = xi; xr = a[50]; xi = a[51]; yr = a[76]; yi = a[77]; a[50] = yr; a[51] = yi; a[76] = xr; a[77] = xi; xr = a[58]; xi = a[59]; yr = a[92]; yi = a[93]; a[58] = yr; a[59] = yi; a[92] = xr; a[93] = xi; xr = a[44]; xi = a[45]; yr = a[52]; yi = a[53]; a[44] = yr; a[45] = yi; a[52] = xr; a[53] = xi; xr = a[96]; xi = a[97]; yr = a[6]; yi = a[7]; a[96] = yr; a[97] = yi; a[6] = xr; a[7] = xi; xr = a[104]; xi = a[105]; yr = a[22]; yi = a[23]; a[104] = yr; a[105] = yi; a[22] = xr; a[23] = xi; xr = a[112]; xi = a[113]; yr = a[14]; yi = a[15]; a[112] = yr; a[113] = yi; a[14] = xr; a[15] = xi; xr = a[120]; xi = a[121]; yr = a[30]; yi = a[31]; a[120] = yr; a[121] = yi; a[30] = xr; a[31] = xi; xr = a[98]; xi = a[99]; yr = a[70]; yi = a[71]; a[98] = yr; a[99] = yi; a[70] = xr; a[71] = xi; xr = a[106]; xi = a[107]; yr = a[86]; yi = a[87]; a[106] = yr; a[107] = yi; a[86] = xr; a[87] = xi; xr = a[114]; xi = a[115]; yr = a[78]; yi = a[79]; a[114] = yr; a[115] = yi; a[78] = xr; a[79] = xi; xr = a[122]; xi = a[123]; yr = a[94]; yi = a[95]; a[122] = yr; a[123] = yi; a[94] = xr; a[95] = xi; xr = a[100]; xi = a[101]; yr = a[38]; yi = a[39]; a[100] = yr; a[101] = yi; a[38] = xr; a[39] = xi; xr = a[108]; xi = a[109]; yr = a[54]; yi = a[55]; a[108] = yr; a[109] = yi; a[54] = xr; a[55] = xi; xr = a[116]; xi = a[117]; yr = a[46]; yi = a[47]; a[116] = yr; a[117] = yi; a[46] = xr; a[47] = xi; xr = a[124]; xi = a[125]; yr = a[62]; yi = a[63]; a[124] = yr; a[125] = yi; a[62] = xr; a[63] = xi; xr = a[110]; xi = a[111]; yr = a[118]; yi = a[119]; a[110] = yr; a[111] = yi; a[118] = xr; a[119] = xi; } void cft1st_128_mips(float* a) { float f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14; int a_ptr, p1_rdft, p2_rdft, count; const float* first = rdft_wk3ri_first; const float* second = rdft_wk3ri_second; __asm __volatile( ".set push \n\t" ".set noreorder \n\t" // first 8 "lwc1 %[f0], 0(%[a]) \n\t" "lwc1 %[f1], 4(%[a]) \n\t" "lwc1 %[f2], 8(%[a]) \n\t" "lwc1 %[f3], 12(%[a]) \n\t" "lwc1 %[f4], 16(%[a]) \n\t" "lwc1 %[f5], 20(%[a]) \n\t" "lwc1 %[f6], 24(%[a]) \n\t" "lwc1 %[f7], 28(%[a]) \n\t" "add.s %[f8], %[f0], %[f2] \n\t" "sub.s %[f0], %[f0], %[f2] \n\t" "add.s %[f2], %[f4], %[f6] \n\t" "sub.s %[f4], %[f4], %[f6] \n\t" "add.s %[f6], %[f1], %[f3] \n\t" "sub.s %[f1], %[f1], %[f3] \n\t" "add.s %[f3], %[f5], %[f7] \n\t" "sub.s %[f5], %[f5], %[f7] \n\t" "add.s %[f7], %[f8], %[f2] \n\t" "sub.s %[f8], %[f8], %[f2] \n\t" "sub.s %[f2], %[f1], %[f4] \n\t" "add.s %[f1], %[f1], %[f4] \n\t" "add.s %[f4], %[f6], %[f3] \n\t" "sub.s %[f6], %[f6], %[f3] \n\t" "sub.s %[f3], %[f0], %[f5] \n\t" "add.s %[f0], %[f0], %[f5] \n\t" "swc1 %[f7], 0(%[a]) \n\t" "swc1 %[f8], 16(%[a]) \n\t" "swc1 %[f2], 28(%[a]) \n\t" "swc1 %[f1], 12(%[a]) \n\t" "swc1 %[f4], 4(%[a]) \n\t" "swc1 %[f6], 20(%[a]) \n\t" "swc1 %[f3], 8(%[a]) \n\t" "swc1 %[f0], 24(%[a]) \n\t" // second 8 "lwc1 %[f0], 32(%[a]) \n\t" "lwc1 %[f1], 36(%[a]) \n\t" "lwc1 %[f2], 40(%[a]) \n\t" "lwc1 %[f3], 44(%[a]) \n\t" "lwc1 %[f4], 48(%[a]) \n\t" "lwc1 %[f5], 52(%[a]) \n\t" "lwc1 %[f6], 56(%[a]) \n\t" "lwc1 %[f7], 60(%[a]) \n\t" "add.s %[f8], %[f4], %[f6] \n\t" "sub.s %[f4], %[f4], %[f6] \n\t" "add.s %[f6], %[f1], %[f3] \n\t" "sub.s %[f1], %[f1], %[f3] \n\t" "add.s %[f3], %[f0], %[f2] \n\t" "sub.s %[f0], %[f0], %[f2] \n\t" "add.s %[f2], %[f5], %[f7] \n\t" "sub.s %[f5], %[f5], %[f7] \n\t" "add.s %[f7], %[f4], %[f1] \n\t" "sub.s %[f4], %[f4], %[f1] \n\t" "add.s %[f1], %[f3], %[f8] \n\t" "sub.s %[f3], %[f3], %[f8] \n\t" "sub.s %[f8], %[f0], %[f5] \n\t" "add.s %[f0], %[f0], %[f5] \n\t" "add.s %[f5], %[f6], %[f2] \n\t" "sub.s %[f6], %[f2], %[f6] \n\t" "lwc1 %[f9], 8(%[rdft_w]) \n\t" "sub.s %[f2], %[f8], %[f7] \n\t" "add.s %[f8], %[f8], %[f7] \n\t" "sub.s %[f7], %[f4], %[f0] \n\t" "add.s %[f4], %[f4], %[f0] \n\t" // prepare for loop "addiu %[a_ptr], %[a], 64 \n\t" "addiu %[p1_rdft], %[rdft_w], 8 \n\t" "addiu %[p2_rdft], %[rdft_w], 16 \n\t" "addiu %[count], $zero, 7 \n\t" // finish second 8 "mul.s %[f2], %[f9], %[f2] \n\t" "mul.s %[f8], %[f9], %[f8] \n\t" "mul.s %[f7], %[f9], %[f7] \n\t" "mul.s %[f4], %[f9], %[f4] \n\t" "swc1 %[f1], 32(%[a]) \n\t" "swc1 %[f3], 52(%[a]) \n\t" "swc1 %[f5], 36(%[a]) \n\t" "swc1 %[f6], 48(%[a]) \n\t" "swc1 %[f2], 40(%[a]) \n\t" "swc1 %[f8], 44(%[a]) \n\t" "swc1 %[f7], 56(%[a]) \n\t" "swc1 %[f4], 60(%[a]) \n\t" // loop "1: \n\t" "lwc1 %[f0], 0(%[a_ptr]) \n\t" "lwc1 %[f1], 4(%[a_ptr]) \n\t" "lwc1 %[f2], 8(%[a_ptr]) \n\t" "lwc1 %[f3], 12(%[a_ptr]) \n\t" "lwc1 %[f4], 16(%[a_ptr]) \n\t" "lwc1 %[f5], 20(%[a_ptr]) \n\t" "lwc1 %[f6], 24(%[a_ptr]) \n\t" "lwc1 %[f7], 28(%[a_ptr]) \n\t" "add.s %[f8], %[f0], %[f2] \n\t" "sub.s %[f0], %[f0], %[f2] \n\t" "add.s %[f2], %[f4], %[f6] \n\t" "sub.s %[f4], %[f4], %[f6] \n\t" "add.s %[f6], %[f1], %[f3] \n\t" "sub.s %[f1], %[f1], %[f3] \n\t" "add.s %[f3], %[f5], %[f7] \n\t" "sub.s %[f5], %[f5], %[f7] \n\t" "lwc1 %[f10], 4(%[p1_rdft]) \n\t" "lwc1 %[f11], 0(%[p2_rdft]) \n\t" "lwc1 %[f12], 4(%[p2_rdft]) \n\t" "lwc1 %[f13], 8(%[first]) \n\t" "lwc1 %[f14], 12(%[first]) \n\t" "add.s %[f7], %[f8], %[f2] \n\t" "sub.s %[f8], %[f8], %[f2] \n\t" "add.s %[f2], %[f6], %[f3] \n\t" "sub.s %[f6], %[f6], %[f3] \n\t" "add.s %[f3], %[f0], %[f5] \n\t" "sub.s %[f0], %[f0], %[f5] \n\t" "add.s %[f5], %[f1], %[f4] \n\t" "sub.s %[f1], %[f1], %[f4] \n\t" "swc1 %[f7], 0(%[a_ptr]) \n\t" "swc1 %[f2], 4(%[a_ptr]) \n\t" "mul.s %[f4], %[f9], %[f8] \n\t" #if defined(MIPS32_R2_LE) "mul.s %[f8], %[f10], %[f8] \n\t" "mul.s %[f7], %[f11], %[f0] \n\t" "mul.s %[f0], %[f12], %[f0] \n\t" "mul.s %[f2], %[f13], %[f3] \n\t" "mul.s %[f3], %[f14], %[f3] \n\t" "nmsub.s %[f4], %[f4], %[f10], %[f6] \n\t" "madd.s %[f8], %[f8], %[f9], %[f6] \n\t" "nmsub.s %[f7], %[f7], %[f12], %[f5] \n\t" "madd.s %[f0], %[f0], %[f11], %[f5] \n\t" "nmsub.s %[f2], %[f2], %[f14], %[f1] \n\t" "madd.s %[f3], %[f3], %[f13], %[f1] \n\t" #else "mul.s %[f7], %[f10], %[f6] \n\t" "mul.s %[f6], %[f9], %[f6] \n\t" "mul.s %[f8], %[f10], %[f8] \n\t" "mul.s %[f2], %[f11], %[f0] \n\t" "mul.s %[f11], %[f11], %[f5] \n\t" "mul.s %[f5], %[f12], %[f5] \n\t" "mul.s %[f0], %[f12], %[f0] \n\t" "mul.s %[f12], %[f13], %[f3] \n\t" "mul.s %[f13], %[f13], %[f1] \n\t" "mul.s %[f1], %[f14], %[f1] \n\t" "mul.s %[f3], %[f14], %[f3] \n\t" "sub.s %[f4], %[f4], %[f7] \n\t" "add.s %[f8], %[f6], %[f8] \n\t" "sub.s %[f7], %[f2], %[f5] \n\t" "add.s %[f0], %[f11], %[f0] \n\t" "sub.s %[f2], %[f12], %[f1] \n\t" "add.s %[f3], %[f13], %[f3] \n\t" #endif "swc1 %[f4], 16(%[a_ptr]) \n\t" "swc1 %[f8], 20(%[a_ptr]) \n\t" "swc1 %[f7], 8(%[a_ptr]) \n\t" "swc1 %[f0], 12(%[a_ptr]) \n\t" "swc1 %[f2], 24(%[a_ptr]) \n\t" "swc1 %[f3], 28(%[a_ptr]) \n\t" "lwc1 %[f0], 32(%[a_ptr]) \n\t" "lwc1 %[f1], 36(%[a_ptr]) \n\t" "lwc1 %[f2], 40(%[a_ptr]) \n\t" "lwc1 %[f3], 44(%[a_ptr]) \n\t" "lwc1 %[f4], 48(%[a_ptr]) \n\t" "lwc1 %[f5], 52(%[a_ptr]) \n\t" "lwc1 %[f6], 56(%[a_ptr]) \n\t" "lwc1 %[f7], 60(%[a_ptr]) \n\t" "add.s %[f8], %[f0], %[f2] \n\t" "sub.s %[f0], %[f0], %[f2] \n\t" "add.s %[f2], %[f4], %[f6] \n\t" "sub.s %[f4], %[f4], %[f6] \n\t" "add.s %[f6], %[f1], %[f3] \n\t" "sub.s %[f1], %[f1], %[f3] \n\t" "add.s %[f3], %[f5], %[f7] \n\t" "sub.s %[f5], %[f5], %[f7] \n\t" "lwc1 %[f11], 8(%[p2_rdft]) \n\t" "lwc1 %[f12], 12(%[p2_rdft]) \n\t" "lwc1 %[f13], 8(%[second]) \n\t" "lwc1 %[f14], 12(%[second]) \n\t" "add.s %[f7], %[f8], %[f2] \n\t" "sub.s %[f8], %[f2], %[f8] \n\t" "add.s %[f2], %[f6], %[f3] \n\t" "sub.s %[f6], %[f3], %[f6] \n\t" "add.s %[f3], %[f0], %[f5] \n\t" "sub.s %[f0], %[f0], %[f5] \n\t" "add.s %[f5], %[f1], %[f4] \n\t" "sub.s %[f1], %[f1], %[f4] \n\t" "swc1 %[f7], 32(%[a_ptr]) \n\t" "swc1 %[f2], 36(%[a_ptr]) \n\t" "mul.s %[f4], %[f10], %[f8] \n\t" #if defined(MIPS32_R2_LE) "mul.s %[f10], %[f10], %[f6] \n\t" "mul.s %[f7], %[f11], %[f0] \n\t" "mul.s %[f11], %[f11], %[f5] \n\t" "mul.s %[f2], %[f13], %[f3] \n\t" "mul.s %[f13], %[f13], %[f1] \n\t" "madd.s %[f4], %[f4], %[f9], %[f6] \n\t" "nmsub.s %[f10], %[f10], %[f9], %[f8] \n\t" "nmsub.s %[f7], %[f7], %[f12], %[f5] \n\t" "madd.s %[f11], %[f11], %[f12], %[f0] \n\t" "nmsub.s %[f2], %[f2], %[f14], %[f1] \n\t" "madd.s %[f13], %[f13], %[f14], %[f3] \n\t" #else "mul.s %[f2], %[f9], %[f6] \n\t" "mul.s %[f10], %[f10], %[f6] \n\t" "mul.s %[f9], %[f9], %[f8] \n\t" "mul.s %[f7], %[f11], %[f0] \n\t" "mul.s %[f8], %[f12], %[f5] \n\t" "mul.s %[f11], %[f11], %[f5] \n\t" "mul.s %[f12], %[f12], %[f0] \n\t" "mul.s %[f5], %[f13], %[f3] \n\t" "mul.s %[f0], %[f14], %[f1] \n\t" "mul.s %[f13], %[f13], %[f1] \n\t" "mul.s %[f14], %[f14], %[f3] \n\t" "add.s %[f4], %[f4], %[f2] \n\t" "sub.s %[f10], %[f10], %[f9] \n\t" "sub.s %[f7], %[f7], %[f8] \n\t" "add.s %[f11], %[f11], %[f12] \n\t" "sub.s %[f2], %[f5], %[f0] \n\t" "add.s %[f13], %[f13], %[f14] \n\t" #endif "swc1 %[f4], 48(%[a_ptr]) \n\t" "swc1 %[f10], 52(%[a_ptr]) \n\t" "swc1 %[f7], 40(%[a_ptr]) \n\t" "swc1 %[f11], 44(%[a_ptr]) \n\t" "swc1 %[f2], 56(%[a_ptr]) \n\t" "swc1 %[f13], 60(%[a_ptr]) \n\t" "addiu %[count], %[count], -1 \n\t" "lwc1 %[f9], 8(%[p1_rdft]) \n\t" "addiu %[a_ptr], %[a_ptr], 64 \n\t" "addiu %[p1_rdft], %[p1_rdft], 8 \n\t" "addiu %[p2_rdft], %[p2_rdft], 16 \n\t" "addiu %[first], %[first], 8 \n\t" "bgtz %[count], 1b \n\t" " addiu %[second], %[second], 8 \n\t" ".set pop \n\t" : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), [f8] "=&f"(f8), [f9] "=&f"(f9), [f10] "=&f"(f10), [f11] "=&f"(f11), [f12] "=&f"(f12), [f13] "=&f"(f13), [f14] "=&f"(f14), [a_ptr] "=&r"(a_ptr), [p1_rdft] "=&r"(p1_rdft), [first] "+r"(first), [p2_rdft] "=&r"(p2_rdft), [count] "=&r"(count), [second] "+r"(second) : [a] "r"(a), [rdft_w] "r"(rdft_w) : "memory"); } void cftmdl_128_mips(float* a) { float f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14; int tmp_a, count; __asm __volatile( ".set push \n\t" ".set noreorder \n\t" "addiu %[tmp_a], %[a], 0 \n\t" "addiu %[count], $zero, 4 \n\t" "1: \n\t" "addiu %[count], %[count], -1 \n\t" "lwc1 %[f0], 0(%[tmp_a]) \n\t" "lwc1 %[f2], 32(%[tmp_a]) \n\t" "lwc1 %[f4], 64(%[tmp_a]) \n\t" "lwc1 %[f6], 96(%[tmp_a]) \n\t" "lwc1 %[f1], 4(%[tmp_a]) \n\t" "lwc1 %[f3], 36(%[tmp_a]) \n\t" "lwc1 %[f5], 68(%[tmp_a]) \n\t" "lwc1 %[f7], 100(%[tmp_a]) \n\t" "add.s %[f8], %[f0], %[f2] \n\t" "sub.s %[f0], %[f0], %[f2] \n\t" "add.s %[f2], %[f4], %[f6] \n\t" "sub.s %[f4], %[f4], %[f6] \n\t" "add.s %[f6], %[f1], %[f3] \n\t" "sub.s %[f1], %[f1], %[f3] \n\t" "add.s %[f3], %[f5], %[f7] \n\t" "sub.s %[f5], %[f5], %[f7] \n\t" "add.s %[f7], %[f8], %[f2] \n\t" "sub.s %[f8], %[f8], %[f2] \n\t" "add.s %[f2], %[f1], %[f4] \n\t" "sub.s %[f1], %[f1], %[f4] \n\t" "add.s %[f4], %[f6], %[f3] \n\t" "sub.s %[f6], %[f6], %[f3] \n\t" "sub.s %[f3], %[f0], %[f5] \n\t" "add.s %[f0], %[f0], %[f5] \n\t" "swc1 %[f7], 0(%[tmp_a]) \n\t" "swc1 %[f8], 64(%[tmp_a]) \n\t" "swc1 %[f2], 36(%[tmp_a]) \n\t" "swc1 %[f1], 100(%[tmp_a]) \n\t" "swc1 %[f4], 4(%[tmp_a]) \n\t" "swc1 %[f6], 68(%[tmp_a]) \n\t" "swc1 %[f3], 32(%[tmp_a]) \n\t" "swc1 %[f0], 96(%[tmp_a]) \n\t" "bgtz %[count], 1b \n\t" " addiu %[tmp_a], %[tmp_a], 8 \n\t" ".set pop \n\t" : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count) : [a] "r"(a) : "memory"); f9 = rdft_w[2]; __asm __volatile( ".set push \n\t" ".set noreorder \n\t" "addiu %[tmp_a], %[a], 128 \n\t" "addiu %[count], $zero, 4 \n\t" "1: \n\t" "addiu %[count], %[count], -1 \n\t" "lwc1 %[f0], 0(%[tmp_a]) \n\t" "lwc1 %[f2], 32(%[tmp_a]) \n\t" "lwc1 %[f5], 68(%[tmp_a]) \n\t" "lwc1 %[f7], 100(%[tmp_a]) \n\t" "lwc1 %[f1], 4(%[tmp_a]) \n\t" "lwc1 %[f3], 36(%[tmp_a]) \n\t" "lwc1 %[f4], 64(%[tmp_a]) \n\t" "lwc1 %[f6], 96(%[tmp_a]) \n\t" "sub.s %[f8], %[f0], %[f2] \n\t" "add.s %[f0], %[f0], %[f2] \n\t" "sub.s %[f2], %[f5], %[f7] \n\t" "add.s %[f5], %[f5], %[f7] \n\t" "sub.s %[f7], %[f1], %[f3] \n\t" "add.s %[f1], %[f1], %[f3] \n\t" "sub.s %[f3], %[f4], %[f6] \n\t" "add.s %[f4], %[f4], %[f6] \n\t" "sub.s %[f6], %[f8], %[f2] \n\t" "add.s %[f8], %[f8], %[f2] \n\t" "add.s %[f2], %[f5], %[f1] \n\t" "sub.s %[f5], %[f5], %[f1] \n\t" "add.s %[f1], %[f3], %[f7] \n\t" "sub.s %[f3], %[f3], %[f7] \n\t" "add.s %[f7], %[f0], %[f4] \n\t" "sub.s %[f0], %[f0], %[f4] \n\t" "sub.s %[f4], %[f6], %[f1] \n\t" "add.s %[f6], %[f6], %[f1] \n\t" "sub.s %[f1], %[f3], %[f8] \n\t" "add.s %[f3], %[f3], %[f8] \n\t" "mul.s %[f4], %[f4], %[f9] \n\t" "mul.s %[f6], %[f6], %[f9] \n\t" "mul.s %[f1], %[f1], %[f9] \n\t" "mul.s %[f3], %[f3], %[f9] \n\t" "swc1 %[f7], 0(%[tmp_a]) \n\t" "swc1 %[f2], 4(%[tmp_a]) \n\t" "swc1 %[f5], 64(%[tmp_a]) \n\t" "swc1 %[f0], 68(%[tmp_a]) \n\t" "swc1 %[f4], 32(%[tmp_a]) \n\t" "swc1 %[f6], 36(%[tmp_a]) \n\t" "swc1 %[f1], 96(%[tmp_a]) \n\t" "swc1 %[f3], 100(%[tmp_a]) \n\t" "bgtz %[count], 1b \n\t" " addiu %[tmp_a], %[tmp_a], 8 \n\t" ".set pop \n\t" : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count) : [a] "r"(a), [f9] "f"(f9) : "memory"); f10 = rdft_w[3]; f11 = rdft_w[4]; f12 = rdft_w[5]; f13 = rdft_wk3ri_first[2]; f14 = rdft_wk3ri_first[3]; __asm __volatile( ".set push \n\t" ".set noreorder \n\t" "addiu %[tmp_a], %[a], 256 \n\t" "addiu %[count], $zero, 4 \n\t" "1: \n\t" "addiu %[count], %[count], -1 \n\t" "lwc1 %[f0], 0(%[tmp_a]) \n\t" "lwc1 %[f2], 32(%[tmp_a]) \n\t" "lwc1 %[f4], 64(%[tmp_a]) \n\t" "lwc1 %[f6], 96(%[tmp_a]) \n\t" "lwc1 %[f1], 4(%[tmp_a]) \n\t" "lwc1 %[f3], 36(%[tmp_a]) \n\t" "lwc1 %[f5], 68(%[tmp_a]) \n\t" "lwc1 %[f7], 100(%[tmp_a]) \n\t" "add.s %[f8], %[f0], %[f2] \n\t" "sub.s %[f0], %[f0], %[f2] \n\t" "add.s %[f2], %[f4], %[f6] \n\t" "sub.s %[f4], %[f4], %[f6] \n\t" "add.s %[f6], %[f1], %[f3] \n\t" "sub.s %[f1], %[f1], %[f3] \n\t" "add.s %[f3], %[f5], %[f7] \n\t" "sub.s %[f5], %[f5], %[f7] \n\t" "sub.s %[f7], %[f8], %[f2] \n\t" "add.s %[f8], %[f8], %[f2] \n\t" "add.s %[f2], %[f1], %[f4] \n\t" "sub.s %[f1], %[f1], %[f4] \n\t" "sub.s %[f4], %[f6], %[f3] \n\t" "add.s %[f6], %[f6], %[f3] \n\t" "sub.s %[f3], %[f0], %[f5] \n\t" "add.s %[f0], %[f0], %[f5] \n\t" "swc1 %[f8], 0(%[tmp_a]) \n\t" "swc1 %[f6], 4(%[tmp_a]) \n\t" "mul.s %[f5], %[f9], %[f7] \n\t" #if defined(MIPS32_R2_LE) "mul.s %[f7], %[f10], %[f7] \n\t" "mul.s %[f8], %[f11], %[f3] \n\t" "mul.s %[f3], %[f12], %[f3] \n\t" "mul.s %[f6], %[f13], %[f0] \n\t" "mul.s %[f0], %[f14], %[f0] \n\t" "nmsub.s %[f5], %[f5], %[f10], %[f4] \n\t" "madd.s %[f7], %[f7], %[f9], %[f4] \n\t" "nmsub.s %[f8], %[f8], %[f12], %[f2] \n\t" "madd.s %[f3], %[f3], %[f11], %[f2] \n\t" "nmsub.s %[f6], %[f6], %[f14], %[f1] \n\t" "madd.s %[f0], %[f0], %[f13], %[f1] \n\t" "swc1 %[f5], 64(%[tmp_a]) \n\t" "swc1 %[f7], 68(%[tmp_a]) \n\t" #else "mul.s %[f8], %[f10], %[f4] \n\t" "mul.s %[f4], %[f9], %[f4] \n\t" "mul.s %[f7], %[f10], %[f7] \n\t" "mul.s %[f6], %[f11], %[f3] \n\t" "mul.s %[f3], %[f12], %[f3] \n\t" "sub.s %[f5], %[f5], %[f8] \n\t" "mul.s %[f8], %[f12], %[f2] \n\t" "mul.s %[f2], %[f11], %[f2] \n\t" "add.s %[f7], %[f4], %[f7] \n\t" "mul.s %[f4], %[f13], %[f0] \n\t" "mul.s %[f0], %[f14], %[f0] \n\t" "sub.s %[f8], %[f6], %[f8] \n\t" "mul.s %[f6], %[f14], %[f1] \n\t" "mul.s %[f1], %[f13], %[f1] \n\t" "add.s %[f3], %[f2], %[f3] \n\t" "swc1 %[f5], 64(%[tmp_a]) \n\t" "swc1 %[f7], 68(%[tmp_a]) \n\t" "sub.s %[f6], %[f4], %[f6] \n\t" "add.s %[f0], %[f1], %[f0] \n\t" #endif "swc1 %[f8], 32(%[tmp_a]) \n\t" "swc1 %[f3], 36(%[tmp_a]) \n\t" "swc1 %[f6], 96(%[tmp_a]) \n\t" "swc1 %[f0], 100(%[tmp_a]) \n\t" "bgtz %[count], 1b \n\t" " addiu %[tmp_a], %[tmp_a], 8 \n\t" ".set pop \n\t" : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count) : [a] "r"(a), [f9] "f"(f9), [f10] "f"(f10), [f11] "f"(f11), [f12] "f"(f12), [f13] "f"(f13), [f14] "f"(f14) : "memory"); f11 = rdft_w[6]; f12 = rdft_w[7]; f13 = rdft_wk3ri_second[2]; f14 = rdft_wk3ri_second[3]; __asm __volatile( ".set push " "\n\t" ".set noreorder " "\n\t" "addiu %[tmp_a], %[a], 384 " "\n\t" "addiu %[count], $zero, 4 " "\n\t" "1: " "\n\t" "addiu %[count], %[count], -1 " "\n\t" "lwc1 %[f0], 0(%[tmp_a]) " "\n\t" "lwc1 %[f1], 4(%[tmp_a]) " "\n\t" "lwc1 %[f2], 32(%[tmp_a]) " "\n\t" "lwc1 %[f3], 36(%[tmp_a]) " "\n\t" "lwc1 %[f4], 64(%[tmp_a]) " "\n\t" "lwc1 %[f5], 68(%[tmp_a]) " "\n\t" "lwc1 %[f6], 96(%[tmp_a]) " "\n\t" "lwc1 %[f7], 100(%[tmp_a]) " "\n\t" "add.s %[f8], %[f0], %[f2] " "\n\t" "sub.s %[f0], %[f0], %[f2] " "\n\t" "add.s %[f2], %[f4], %[f6] " "\n\t" "sub.s %[f4], %[f4], %[f6] " "\n\t" "add.s %[f6], %[f1], %[f3] " "\n\t" "sub.s %[f1], %[f1], %[f3] " "\n\t" "add.s %[f3], %[f5], %[f7] " "\n\t" "sub.s %[f5], %[f5], %[f7] " "\n\t" "sub.s %[f7], %[f2], %[f8] " "\n\t" "add.s %[f2], %[f2], %[f8] " "\n\t" "add.s %[f8], %[f1], %[f4] " "\n\t" "sub.s %[f1], %[f1], %[f4] " "\n\t" "sub.s %[f4], %[f3], %[f6] " "\n\t" "add.s %[f3], %[f3], %[f6] " "\n\t" "sub.s %[f6], %[f0], %[f5] " "\n\t" "add.s %[f0], %[f0], %[f5] " "\n\t" "swc1 %[f2], 0(%[tmp_a]) " "\n\t" "swc1 %[f3], 4(%[tmp_a]) " "\n\t" "mul.s %[f5], %[f10], %[f7] " "\n\t" #if defined(MIPS32_R2_LE) "mul.s %[f7], %[f9], %[f7] " "\n\t" "mul.s %[f2], %[f12], %[f8] " "\n\t" "mul.s %[f8], %[f11], %[f8] " "\n\t" "mul.s %[f3], %[f14], %[f1] " "\n\t" "mul.s %[f1], %[f13], %[f1] " "\n\t" "madd.s %[f5], %[f5], %[f9], %[f4] " "\n\t" "msub.s %[f7], %[f7], %[f10], %[f4] " "\n\t" "msub.s %[f2], %[f2], %[f11], %[f6] " "\n\t" "madd.s %[f8], %[f8], %[f12], %[f6] " "\n\t" "msub.s %[f3], %[f3], %[f13], %[f0] " "\n\t" "madd.s %[f1], %[f1], %[f14], %[f0] " "\n\t" "swc1 %[f5], 64(%[tmp_a]) " "\n\t" "swc1 %[f7], 68(%[tmp_a]) " "\n\t" #else "mul.s %[f2], %[f9], %[f4] " "\n\t" "mul.s %[f4], %[f10], %[f4] " "\n\t" "mul.s %[f7], %[f9], %[f7] " "\n\t" "mul.s %[f3], %[f11], %[f6] " "\n\t" "mul.s %[f6], %[f12], %[f6] " "\n\t" "add.s %[f5], %[f5], %[f2] " "\n\t" "sub.s %[f7], %[f4], %[f7] " "\n\t" "mul.s %[f2], %[f12], %[f8] " "\n\t" "mul.s %[f8], %[f11], %[f8] " "\n\t" "mul.s %[f4], %[f14], %[f1] " "\n\t" "mul.s %[f1], %[f13], %[f1] " "\n\t" "sub.s %[f2], %[f3], %[f2] " "\n\t" "mul.s %[f3], %[f13], %[f0] " "\n\t" "mul.s %[f0], %[f14], %[f0] " "\n\t" "add.s %[f8], %[f8], %[f6] " "\n\t" "swc1 %[f5], 64(%[tmp_a]) " "\n\t" "swc1 %[f7], 68(%[tmp_a]) " "\n\t" "sub.s %[f3], %[f3], %[f4] " "\n\t" "add.s %[f1], %[f1], %[f0] " "\n\t" #endif "swc1 %[f2], 32(%[tmp_a]) " "\n\t" "swc1 %[f8], 36(%[tmp_a]) " "\n\t" "swc1 %[f3], 96(%[tmp_a]) " "\n\t" "swc1 %[f1], 100(%[tmp_a]) " "\n\t" "bgtz %[count], 1b " "\n\t" " addiu %[tmp_a], %[tmp_a], 8 " "\n\t" ".set pop " "\n\t" : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count) : [a] "r"(a), [f9] "f"(f9), [f10] "f"(f10), [f11] "f"(f11), [f12] "f"(f12), [f13] "f"(f13), [f14] "f"(f14) : "memory"); } void cftfsub_128_mips(float* a) { float f0, f1, f2, f3, f4, f5, f6, f7, f8; int tmp_a, count; cft1st_128_mips(a); cftmdl_128_mips(a); __asm __volatile( ".set push \n\t" ".set noreorder \n\t" "addiu %[tmp_a], %[a], 0 \n\t" "addiu %[count], $zero, 16 \n\t" "1: \n\t" "addiu %[count], %[count], -1 \n\t" "lwc1 %[f0], 0(%[tmp_a]) \n\t" "lwc1 %[f2], 128(%[tmp_a]) \n\t" "lwc1 %[f4], 256(%[tmp_a]) \n\t" "lwc1 %[f6], 384(%[tmp_a]) \n\t" "lwc1 %[f1], 4(%[tmp_a]) \n\t" "lwc1 %[f3], 132(%[tmp_a]) \n\t" "lwc1 %[f5], 260(%[tmp_a]) \n\t" "lwc1 %[f7], 388(%[tmp_a]) \n\t" "add.s %[f8], %[f0], %[f2] \n\t" "sub.s %[f0], %[f0], %[f2] \n\t" "add.s %[f2], %[f4], %[f6] \n\t" "sub.s %[f4], %[f4], %[f6] \n\t" "add.s %[f6], %[f1], %[f3] \n\t" "sub.s %[f1], %[f1], %[f3] \n\t" "add.s %[f3], %[f5], %[f7] \n\t" "sub.s %[f5], %[f5], %[f7] \n\t" "add.s %[f7], %[f8], %[f2] \n\t" "sub.s %[f8], %[f8], %[f2] \n\t" "add.s %[f2], %[f1], %[f4] \n\t" "sub.s %[f1], %[f1], %[f4] \n\t" "add.s %[f4], %[f6], %[f3] \n\t" "sub.s %[f6], %[f6], %[f3] \n\t" "sub.s %[f3], %[f0], %[f5] \n\t" "add.s %[f0], %[f0], %[f5] \n\t" "swc1 %[f7], 0(%[tmp_a]) \n\t" "swc1 %[f8], 256(%[tmp_a]) \n\t" "swc1 %[f2], 132(%[tmp_a]) \n\t" "swc1 %[f1], 388(%[tmp_a]) \n\t" "swc1 %[f4], 4(%[tmp_a]) \n\t" "swc1 %[f6], 260(%[tmp_a]) \n\t" "swc1 %[f3], 128(%[tmp_a]) \n\t" "swc1 %[f0], 384(%[tmp_a]) \n\t" "bgtz %[count], 1b \n\t" " addiu %[tmp_a], %[tmp_a], 8 \n\t" ".set pop \n\t" : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count) : [a] "r"(a) : "memory"); } void cftbsub_128_mips(float* a) { float f0, f1, f2, f3, f4, f5, f6, f7, f8; int tmp_a, count; cft1st_128_mips(a); cftmdl_128_mips(a); __asm __volatile( ".set push \n\t" ".set noreorder \n\t" "addiu %[tmp_a], %[a], 0 \n\t" "addiu %[count], $zero, 16 \n\t" "1: \n\t" "addiu %[count], %[count], -1 \n\t" "lwc1 %[f0], 0(%[tmp_a]) \n\t" "lwc1 %[f2], 128(%[tmp_a]) \n\t" "lwc1 %[f4], 256(%[tmp_a]) \n\t" "lwc1 %[f6], 384(%[tmp_a]) \n\t" "lwc1 %[f1], 4(%[tmp_a]) \n\t" "lwc1 %[f3], 132(%[tmp_a]) \n\t" "lwc1 %[f5], 260(%[tmp_a]) \n\t" "lwc1 %[f7], 388(%[tmp_a]) \n\t" "add.s %[f8], %[f0], %[f2] \n\t" "sub.s %[f0], %[f0], %[f2] \n\t" "add.s %[f2], %[f4], %[f6] \n\t" "sub.s %[f4], %[f4], %[f6] \n\t" "add.s %[f6], %[f1], %[f3] \n\t" "sub.s %[f1], %[f3], %[f1] \n\t" "add.s %[f3], %[f5], %[f7] \n\t" "sub.s %[f5], %[f5], %[f7] \n\t" "add.s %[f7], %[f8], %[f2] \n\t" "sub.s %[f8], %[f8], %[f2] \n\t" "sub.s %[f2], %[f1], %[f4] \n\t" "add.s %[f1], %[f1], %[f4] \n\t" "add.s %[f4], %[f3], %[f6] \n\t" "sub.s %[f6], %[f3], %[f6] \n\t" "sub.s %[f3], %[f0], %[f5] \n\t" "add.s %[f0], %[f0], %[f5] \n\t" "neg.s %[f4], %[f4] \n\t" "swc1 %[f7], 0(%[tmp_a]) \n\t" "swc1 %[f8], 256(%[tmp_a]) \n\t" "swc1 %[f2], 132(%[tmp_a]) \n\t" "swc1 %[f1], 388(%[tmp_a]) \n\t" "swc1 %[f6], 260(%[tmp_a]) \n\t" "swc1 %[f3], 128(%[tmp_a]) \n\t" "swc1 %[f0], 384(%[tmp_a]) \n\t" "swc1 %[f4], 4(%[tmp_a]) \n\t" "bgtz %[count], 1b \n\t" " addiu %[tmp_a], %[tmp_a], 8 \n\t" ".set pop \n\t" : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count) : [a] "r"(a) : "memory"); } void rftfsub_128_mips(float* a) { const float* c = rdft_w + 32; const float f0 = 0.5f; float* a1 = &a[2]; float* a2 = &a[126]; const float* c1 = &c[1]; const float* c2 = &c[31]; float f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15; int count; __asm __volatile( ".set push \n\t" ".set noreorder \n\t" "lwc1 %[f6], 0(%[c2]) \n\t" "lwc1 %[f1], 0(%[a1]) \n\t" "lwc1 %[f2], 0(%[a2]) \n\t" "lwc1 %[f3], 4(%[a1]) \n\t" "lwc1 %[f4], 4(%[a2]) \n\t" "lwc1 %[f5], 0(%[c1]) \n\t" "sub.s %[f6], %[f0], %[f6] \n\t" "sub.s %[f7], %[f1], %[f2] \n\t" "add.s %[f8], %[f3], %[f4] \n\t" "addiu %[count], $zero, 15 \n\t" "mul.s %[f9], %[f6], %[f7] \n\t" "mul.s %[f6], %[f6], %[f8] \n\t" #if !defined(MIPS32_R2_LE) "mul.s %[f8], %[f5], %[f8] \n\t" "mul.s %[f5], %[f5], %[f7] \n\t" "sub.s %[f9], %[f9], %[f8] \n\t" "add.s %[f6], %[f6], %[f5] \n\t" #else "nmsub.s %[f9], %[f9], %[f5], %[f8] \n\t" "madd.s %[f6], %[f6], %[f5], %[f7] \n\t" #endif "sub.s %[f1], %[f1], %[f9] \n\t" "add.s %[f2], %[f2], %[f9] \n\t" "sub.s %[f3], %[f3], %[f6] \n\t" "sub.s %[f4], %[f4], %[f6] \n\t" "swc1 %[f1], 0(%[a1]) \n\t" "swc1 %[f2], 0(%[a2]) \n\t" "swc1 %[f3], 4(%[a1]) \n\t" "swc1 %[f4], 4(%[a2]) \n\t" "addiu %[a1], %[a1], 8 \n\t" "addiu %[a2], %[a2], -8 \n\t" "addiu %[c1], %[c1], 4 \n\t" "addiu %[c2], %[c2], -4 \n\t" "1: \n\t" "lwc1 %[f6], 0(%[c2]) \n\t" "lwc1 %[f1], 0(%[a1]) \n\t" "lwc1 %[f2], 0(%[a2]) \n\t" "lwc1 %[f3], 4(%[a1]) \n\t" "lwc1 %[f4], 4(%[a2]) \n\t" "lwc1 %[f5], 0(%[c1]) \n\t" "sub.s %[f6], %[f0], %[f6] \n\t" "sub.s %[f7], %[f1], %[f2] \n\t" "add.s %[f8], %[f3], %[f4] \n\t" "lwc1 %[f10], -4(%[c2]) \n\t" "lwc1 %[f11], 8(%[a1]) \n\t" "lwc1 %[f12], -8(%[a2]) \n\t" "mul.s %[f9], %[f6], %[f7] \n\t" "mul.s %[f6], %[f6], %[f8] \n\t" #if !defined(MIPS32_R2_LE) "mul.s %[f8], %[f5], %[f8] \n\t" "mul.s %[f5], %[f5], %[f7] \n\t" "lwc1 %[f13], 12(%[a1]) \n\t" "lwc1 %[f14], -4(%[a2]) \n\t" "lwc1 %[f15], 4(%[c1]) \n\t" "sub.s %[f9], %[f9], %[f8] \n\t" "add.s %[f6], %[f6], %[f5] \n\t" #else "lwc1 %[f13], 12(%[a1]) \n\t" "lwc1 %[f14], -4(%[a2]) \n\t" "lwc1 %[f15], 4(%[c1]) \n\t" "nmsub.s %[f9], %[f9], %[f5], %[f8] \n\t" "madd.s %[f6], %[f6], %[f5], %[f7] \n\t" #endif "sub.s %[f10], %[f0], %[f10] \n\t" "sub.s %[f5], %[f11], %[f12] \n\t" "add.s %[f7], %[f13], %[f14] \n\t" "sub.s %[f1], %[f1], %[f9] \n\t" "add.s %[f2], %[f2], %[f9] \n\t" "sub.s %[f3], %[f3], %[f6] \n\t" "mul.s %[f8], %[f10], %[f5] \n\t" "mul.s %[f10], %[f10], %[f7] \n\t" #if !defined(MIPS32_R2_LE) "mul.s %[f9], %[f15], %[f7] \n\t" "mul.s %[f15], %[f15], %[f5] \n\t" "sub.s %[f4], %[f4], %[f6] \n\t" "swc1 %[f1], 0(%[a1]) \n\t" "swc1 %[f2], 0(%[a2]) \n\t" "sub.s %[f8], %[f8], %[f9] \n\t" "add.s %[f10], %[f10], %[f15] \n\t" #else "swc1 %[f1], 0(%[a1]) \n\t" "swc1 %[f2], 0(%[a2]) \n\t" "sub.s %[f4], %[f4], %[f6] \n\t" "nmsub.s %[f8], %[f8], %[f15], %[f7] \n\t" "madd.s %[f10], %[f10], %[f15], %[f5] \n\t" #endif "swc1 %[f3], 4(%[a1]) \n\t" "swc1 %[f4], 4(%[a2]) \n\t" "sub.s %[f11], %[f11], %[f8] \n\t" "add.s %[f12], %[f12], %[f8] \n\t" "sub.s %[f13], %[f13], %[f10] \n\t" "sub.s %[f14], %[f14], %[f10] \n\t" "addiu %[c2], %[c2], -8 \n\t" "addiu %[c1], %[c1], 8 \n\t" "swc1 %[f11], 8(%[a1]) \n\t" "swc1 %[f12], -8(%[a2]) \n\t" "swc1 %[f13], 12(%[a1]) \n\t" "swc1 %[f14], -4(%[a2]) \n\t" "addiu %[a1], %[a1], 16 \n\t" "addiu %[count], %[count], -1 \n\t" "bgtz %[count], 1b \n\t" " addiu %[a2], %[a2], -16 \n\t" ".set pop \n\t" : [a1] "+r"(a1), [a2] "+r"(a2), [c1] "+r"(c1), [c2] "+r"(c2), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), [f8] "=&f"(f8), [f9] "=&f"(f9), [f10] "=&f"(f10), [f11] "=&f"(f11), [f12] "=&f"(f12), [f13] "=&f"(f13), [f14] "=&f"(f14), [f15] "=&f"(f15), [count] "=&r"(count) : [f0] "f"(f0) : "memory"); } void rftbsub_128_mips(float* a) { const float* c = rdft_w + 32; const float f0 = 0.5f; float* a1 = &a[2]; float* a2 = &a[126]; const float* c1 = &c[1]; const float* c2 = &c[31]; float f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15; int count; a[1] = -a[1]; a[65] = -a[65]; __asm __volatile( ".set push \n\t" ".set noreorder \n\t" "lwc1 %[f6], 0(%[c2]) \n\t" "lwc1 %[f1], 0(%[a1]) \n\t" "lwc1 %[f2], 0(%[a2]) \n\t" "lwc1 %[f3], 4(%[a1]) \n\t" "lwc1 %[f4], 4(%[a2]) \n\t" "lwc1 %[f5], 0(%[c1]) \n\t" "sub.s %[f6], %[f0], %[f6] \n\t" "sub.s %[f7], %[f1], %[f2] \n\t" "add.s %[f8], %[f3], %[f4] \n\t" "addiu %[count], $zero, 15 \n\t" "mul.s %[f9], %[f6], %[f7] \n\t" "mul.s %[f6], %[f6], %[f8] \n\t" #if !defined(MIPS32_R2_LE) "mul.s %[f8], %[f5], %[f8] \n\t" "mul.s %[f5], %[f5], %[f7] \n\t" "add.s %[f9], %[f9], %[f8] \n\t" "sub.s %[f6], %[f6], %[f5] \n\t" #else "madd.s %[f9], %[f9], %[f5], %[f8] \n\t" "nmsub.s %[f6], %[f6], %[f5], %[f7] \n\t" #endif "sub.s %[f1], %[f1], %[f9] \n\t" "add.s %[f2], %[f2], %[f9] \n\t" "sub.s %[f3], %[f6], %[f3] \n\t" "sub.s %[f4], %[f6], %[f4] \n\t" "swc1 %[f1], 0(%[a1]) \n\t" "swc1 %[f2], 0(%[a2]) \n\t" "swc1 %[f3], 4(%[a1]) \n\t" "swc1 %[f4], 4(%[a2]) \n\t" "addiu %[a1], %[a1], 8 \n\t" "addiu %[a2], %[a2], -8 \n\t" "addiu %[c1], %[c1], 4 \n\t" "addiu %[c2], %[c2], -4 \n\t" "1: \n\t" "lwc1 %[f6], 0(%[c2]) \n\t" "lwc1 %[f1], 0(%[a1]) \n\t" "lwc1 %[f2], 0(%[a2]) \n\t" "lwc1 %[f3], 4(%[a1]) \n\t" "lwc1 %[f4], 4(%[a2]) \n\t" "lwc1 %[f5], 0(%[c1]) \n\t" "sub.s %[f6], %[f0], %[f6] \n\t" "sub.s %[f7], %[f1], %[f2] \n\t" "add.s %[f8], %[f3], %[f4] \n\t" "lwc1 %[f10], -4(%[c2]) \n\t" "lwc1 %[f11], 8(%[a1]) \n\t" "lwc1 %[f12], -8(%[a2]) \n\t" "mul.s %[f9], %[f6], %[f7] \n\t" "mul.s %[f6], %[f6], %[f8] \n\t" #if !defined(MIPS32_R2_LE) "mul.s %[f8], %[f5], %[f8] \n\t" "mul.s %[f5], %[f5], %[f7] \n\t" "lwc1 %[f13], 12(%[a1]) \n\t" "lwc1 %[f14], -4(%[a2]) \n\t" "lwc1 %[f15], 4(%[c1]) \n\t" "add.s %[f9], %[f9], %[f8] \n\t" "sub.s %[f6], %[f6], %[f5] \n\t" #else "lwc1 %[f13], 12(%[a1]) \n\t" "lwc1 %[f14], -4(%[a2]) \n\t" "lwc1 %[f15], 4(%[c1]) \n\t" "madd.s %[f9], %[f9], %[f5], %[f8] \n\t" "nmsub.s %[f6], %[f6], %[f5], %[f7] \n\t" #endif "sub.s %[f10], %[f0], %[f10] \n\t" "sub.s %[f5], %[f11], %[f12] \n\t" "add.s %[f7], %[f13], %[f14] \n\t" "sub.s %[f1], %[f1], %[f9] \n\t" "add.s %[f2], %[f2], %[f9] \n\t" "sub.s %[f3], %[f6], %[f3] \n\t" "mul.s %[f8], %[f10], %[f5] \n\t" "mul.s %[f10], %[f10], %[f7] \n\t" #if !defined(MIPS32_R2_LE) "mul.s %[f9], %[f15], %[f7] \n\t" "mul.s %[f15], %[f15], %[f5] \n\t" "sub.s %[f4], %[f6], %[f4] \n\t" "swc1 %[f1], 0(%[a1]) \n\t" "swc1 %[f2], 0(%[a2]) \n\t" "add.s %[f8], %[f8], %[f9] \n\t" "sub.s %[f10], %[f10], %[f15] \n\t" #else "swc1 %[f1], 0(%[a1]) \n\t" "swc1 %[f2], 0(%[a2]) \n\t" "sub.s %[f4], %[f6], %[f4] \n\t" "madd.s %[f8], %[f8], %[f15], %[f7] \n\t" "nmsub.s %[f10], %[f10], %[f15], %[f5] \n\t" #endif "swc1 %[f3], 4(%[a1]) \n\t" "swc1 %[f4], 4(%[a2]) \n\t" "sub.s %[f11], %[f11], %[f8] \n\t" "add.s %[f12], %[f12], %[f8] \n\t" "sub.s %[f13], %[f10], %[f13] \n\t" "sub.s %[f14], %[f10], %[f14] \n\t" "addiu %[c2], %[c2], -8 \n\t" "addiu %[c1], %[c1], 8 \n\t" "swc1 %[f11], 8(%[a1]) \n\t" "swc1 %[f12], -8(%[a2]) \n\t" "swc1 %[f13], 12(%[a1]) \n\t" "swc1 %[f14], -4(%[a2]) \n\t" "addiu %[a1], %[a1], 16 \n\t" "addiu %[count], %[count], -1 \n\t" "bgtz %[count], 1b \n\t" " addiu %[a2], %[a2], -16 \n\t" ".set pop \n\t" : [a1] "+r"(a1), [a2] "+r"(a2), [c1] "+r"(c1), [c2] "+r"(c2), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), [f8] "=&f"(f8), [f9] "=&f"(f9), [f10] "=&f"(f10), [f11] "=&f"(f11), [f12] "=&f"(f12), [f13] "=&f"(f13), [f14] "=&f"(f14), [f15] "=&f"(f15), [count] "=&r"(count) : [f0] "f"(f0) : "memory"); } #endif } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_neon.cc0000664000175000017500000003571314475643423032031 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * The rdft AEC algorithm, neon version of speed-critical functions. * * Based on the sse2 version. */ #include #include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h" #include "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h" #include "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_neon_sse2.h" namespace webrtc { #if defined(WEBRTC_HAS_NEON) void cft1st_128_neon(float* a) { const float32x4_t vec_swap_sign = vld1q_f32((float32_t*)k_swap_sign); int j, k2; for (k2 = 0, j = 0; j < 128; j += 16, k2 += 4) { float32x4_t a00v = vld1q_f32(&a[j + 0]); float32x4_t a04v = vld1q_f32(&a[j + 4]); float32x4_t a08v = vld1q_f32(&a[j + 8]); float32x4_t a12v = vld1q_f32(&a[j + 12]); float32x4_t a01v = vcombine_f32(vget_low_f32(a00v), vget_low_f32(a08v)); float32x4_t a23v = vcombine_f32(vget_high_f32(a00v), vget_high_f32(a08v)); float32x4_t a45v = vcombine_f32(vget_low_f32(a04v), vget_low_f32(a12v)); float32x4_t a67v = vcombine_f32(vget_high_f32(a04v), vget_high_f32(a12v)); const float32x4_t wk1rv = vld1q_f32(&rdft_wk1r[k2]); const float32x4_t wk1iv = vld1q_f32(&rdft_wk1i[k2]); const float32x4_t wk2rv = vld1q_f32(&rdft_wk2r[k2]); const float32x4_t wk2iv = vld1q_f32(&rdft_wk2i[k2]); const float32x4_t wk3rv = vld1q_f32(&rdft_wk3r[k2]); const float32x4_t wk3iv = vld1q_f32(&rdft_wk3i[k2]); float32x4_t x0v = vaddq_f32(a01v, a23v); const float32x4_t x1v = vsubq_f32(a01v, a23v); const float32x4_t x2v = vaddq_f32(a45v, a67v); const float32x4_t x3v = vsubq_f32(a45v, a67v); const float32x4_t x3w = vrev64q_f32(x3v); float32x4_t x0w; a01v = vaddq_f32(x0v, x2v); x0v = vsubq_f32(x0v, x2v); x0w = vrev64q_f32(x0v); a45v = vmulq_f32(wk2rv, x0v); a45v = vmlaq_f32(a45v, wk2iv, x0w); x0v = vmlaq_f32(x1v, x3w, vec_swap_sign); x0w = vrev64q_f32(x0v); a23v = vmulq_f32(wk1rv, x0v); a23v = vmlaq_f32(a23v, wk1iv, x0w); x0v = vmlsq_f32(x1v, x3w, vec_swap_sign); x0w = vrev64q_f32(x0v); a67v = vmulq_f32(wk3rv, x0v); a67v = vmlaq_f32(a67v, wk3iv, x0w); a00v = vcombine_f32(vget_low_f32(a01v), vget_low_f32(a23v)); a04v = vcombine_f32(vget_low_f32(a45v), vget_low_f32(a67v)); a08v = vcombine_f32(vget_high_f32(a01v), vget_high_f32(a23v)); a12v = vcombine_f32(vget_high_f32(a45v), vget_high_f32(a67v)); vst1q_f32(&a[j + 0], a00v); vst1q_f32(&a[j + 4], a04v); vst1q_f32(&a[j + 8], a08v); vst1q_f32(&a[j + 12], a12v); } } void cftmdl_128_neon(float* a) { int j; const int l = 8; const float32x4_t vec_swap_sign = vld1q_f32((float32_t*)k_swap_sign); float32x4_t wk1rv = vld1q_f32(cftmdl_wk1r); for (j = 0; j < l; j += 2) { const float32x2_t a_00 = vld1_f32(&a[j + 0]); const float32x2_t a_08 = vld1_f32(&a[j + 8]); const float32x2_t a_32 = vld1_f32(&a[j + 32]); const float32x2_t a_40 = vld1_f32(&a[j + 40]); const float32x4_t a_00_32 = vcombine_f32(a_00, a_32); const float32x4_t a_08_40 = vcombine_f32(a_08, a_40); const float32x4_t x0r0_0i0_0r1_x0i1 = vaddq_f32(a_00_32, a_08_40); const float32x4_t x1r0_1i0_1r1_x1i1 = vsubq_f32(a_00_32, a_08_40); const float32x2_t a_16 = vld1_f32(&a[j + 16]); const float32x2_t a_24 = vld1_f32(&a[j + 24]); const float32x2_t a_48 = vld1_f32(&a[j + 48]); const float32x2_t a_56 = vld1_f32(&a[j + 56]); const float32x4_t a_16_48 = vcombine_f32(a_16, a_48); const float32x4_t a_24_56 = vcombine_f32(a_24, a_56); const float32x4_t x2r0_2i0_2r1_x2i1 = vaddq_f32(a_16_48, a_24_56); const float32x4_t x3r0_3i0_3r1_x3i1 = vsubq_f32(a_16_48, a_24_56); const float32x4_t xx0 = vaddq_f32(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); const float32x4_t xx1 = vsubq_f32(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); const float32x4_t x3i0_3r0_3i1_x3r1 = vrev64q_f32(x3r0_3i0_3r1_x3i1); const float32x4_t x1_x3_add = vmlaq_f32(x1r0_1i0_1r1_x1i1, vec_swap_sign, x3i0_3r0_3i1_x3r1); const float32x4_t x1_x3_sub = vmlsq_f32(x1r0_1i0_1r1_x1i1, vec_swap_sign, x3i0_3r0_3i1_x3r1); const float32x2_t yy0_a = vdup_lane_f32(vget_high_f32(x1_x3_add), 0); const float32x2_t yy0_s = vdup_lane_f32(vget_high_f32(x1_x3_sub), 0); const float32x4_t yy0_as = vcombine_f32(yy0_a, yy0_s); const float32x2_t yy1_a = vdup_lane_f32(vget_high_f32(x1_x3_add), 1); const float32x2_t yy1_s = vdup_lane_f32(vget_high_f32(x1_x3_sub), 1); const float32x4_t yy1_as = vcombine_f32(yy1_a, yy1_s); const float32x4_t yy0 = vmlaq_f32(yy0_as, vec_swap_sign, yy1_as); const float32x4_t yy4 = vmulq_f32(wk1rv, yy0); const float32x4_t xx1_rev = vrev64q_f32(xx1); const float32x4_t yy4_rev = vrev64q_f32(yy4); vst1_f32(&a[j + 0], vget_low_f32(xx0)); vst1_f32(&a[j + 32], vget_high_f32(xx0)); vst1_f32(&a[j + 16], vget_low_f32(xx1)); vst1_f32(&a[j + 48], vget_high_f32(xx1_rev)); a[j + 48] = -a[j + 48]; vst1_f32(&a[j + 8], vget_low_f32(x1_x3_add)); vst1_f32(&a[j + 24], vget_low_f32(x1_x3_sub)); vst1_f32(&a[j + 40], vget_low_f32(yy4)); vst1_f32(&a[j + 56], vget_high_f32(yy4_rev)); } { const int k = 64; const int k1 = 2; const int k2 = 2 * k1; const float32x4_t wk2rv = vld1q_f32(&rdft_wk2r[k2 + 0]); const float32x4_t wk2iv = vld1q_f32(&rdft_wk2i[k2 + 0]); const float32x4_t wk1iv = vld1q_f32(&rdft_wk1i[k2 + 0]); const float32x4_t wk3rv = vld1q_f32(&rdft_wk3r[k2 + 0]); const float32x4_t wk3iv = vld1q_f32(&rdft_wk3i[k2 + 0]); wk1rv = vld1q_f32(&rdft_wk1r[k2 + 0]); for (j = k; j < l + k; j += 2) { const float32x2_t a_00 = vld1_f32(&a[j + 0]); const float32x2_t a_08 = vld1_f32(&a[j + 8]); const float32x2_t a_32 = vld1_f32(&a[j + 32]); const float32x2_t a_40 = vld1_f32(&a[j + 40]); const float32x4_t a_00_32 = vcombine_f32(a_00, a_32); const float32x4_t a_08_40 = vcombine_f32(a_08, a_40); const float32x4_t x0r0_0i0_0r1_x0i1 = vaddq_f32(a_00_32, a_08_40); const float32x4_t x1r0_1i0_1r1_x1i1 = vsubq_f32(a_00_32, a_08_40); const float32x2_t a_16 = vld1_f32(&a[j + 16]); const float32x2_t a_24 = vld1_f32(&a[j + 24]); const float32x2_t a_48 = vld1_f32(&a[j + 48]); const float32x2_t a_56 = vld1_f32(&a[j + 56]); const float32x4_t a_16_48 = vcombine_f32(a_16, a_48); const float32x4_t a_24_56 = vcombine_f32(a_24, a_56); const float32x4_t x2r0_2i0_2r1_x2i1 = vaddq_f32(a_16_48, a_24_56); const float32x4_t x3r0_3i0_3r1_x3i1 = vsubq_f32(a_16_48, a_24_56); const float32x4_t xx = vaddq_f32(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); const float32x4_t xx1 = vsubq_f32(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); const float32x4_t x3i0_3r0_3i1_x3r1 = vrev64q_f32(x3r0_3i0_3r1_x3i1); const float32x4_t x1_x3_add = vmlaq_f32(x1r0_1i0_1r1_x1i1, vec_swap_sign, x3i0_3r0_3i1_x3r1); const float32x4_t x1_x3_sub = vmlsq_f32(x1r0_1i0_1r1_x1i1, vec_swap_sign, x3i0_3r0_3i1_x3r1); float32x4_t xx4 = vmulq_f32(wk2rv, xx1); float32x4_t xx12 = vmulq_f32(wk1rv, x1_x3_add); float32x4_t xx22 = vmulq_f32(wk3rv, x1_x3_sub); xx4 = vmlaq_f32(xx4, wk2iv, vrev64q_f32(xx1)); xx12 = vmlaq_f32(xx12, wk1iv, vrev64q_f32(x1_x3_add)); xx22 = vmlaq_f32(xx22, wk3iv, vrev64q_f32(x1_x3_sub)); vst1_f32(&a[j + 0], vget_low_f32(xx)); vst1_f32(&a[j + 32], vget_high_f32(xx)); vst1_f32(&a[j + 16], vget_low_f32(xx4)); vst1_f32(&a[j + 48], vget_high_f32(xx4)); vst1_f32(&a[j + 8], vget_low_f32(xx12)); vst1_f32(&a[j + 40], vget_high_f32(xx12)); vst1_f32(&a[j + 24], vget_low_f32(xx22)); vst1_f32(&a[j + 56], vget_high_f32(xx22)); } } } __inline static float32x4_t reverse_order_f32x4(float32x4_t in) { // A B C D -> C D A B const float32x4_t rev = vcombine_f32(vget_high_f32(in), vget_low_f32(in)); // C D A B -> D C B A return vrev64q_f32(rev); } void rftfsub_128_neon(float* a) { const float* c = rdft_w + 32; int j1, j2; const float32x4_t mm_half = vdupq_n_f32(0.5f); // Vectorized code (four at once). // Note: commented number are indexes for the first iteration of the loop. for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) { // Load 'wk'. const float32x4_t c_j1 = vld1q_f32(&c[j1]); // 1, 2, 3, 4, const float32x4_t c_k1 = vld1q_f32(&c[29 - j1]); // 28, 29, 30, 31, const float32x4_t wkrt = vsubq_f32(mm_half, c_k1); // 28, 29, 30, 31, const float32x4_t wkr_ = reverse_order_f32x4(wkrt); // 31, 30, 29, 28, const float32x4_t wki_ = c_j1; // 1, 2, 3, 4, // Load and shuffle 'a'. // 2, 4, 6, 8, 3, 5, 7, 9 float32x4x2_t a_j2_p = vld2q_f32(&a[0 + j2]); // 120, 122, 124, 126, 121, 123, 125, 127, const float32x4x2_t k2_0_4 = vld2q_f32(&a[122 - j2]); // 126, 124, 122, 120 const float32x4_t a_k2_p0 = reverse_order_f32x4(k2_0_4.val[0]); // 127, 125, 123, 121 const float32x4_t a_k2_p1 = reverse_order_f32x4(k2_0_4.val[1]); // Calculate 'x'. const float32x4_t xr_ = vsubq_f32(a_j2_p.val[0], a_k2_p0); // 2-126, 4-124, 6-122, 8-120, const float32x4_t xi_ = vaddq_f32(a_j2_p.val[1], a_k2_p1); // 3-127, 5-125, 7-123, 9-121, // Calculate product into 'y'. // yr = wkr * xr - wki * xi; // yi = wkr * xi + wki * xr; const float32x4_t a_ = vmulq_f32(wkr_, xr_); const float32x4_t b_ = vmulq_f32(wki_, xi_); const float32x4_t c_ = vmulq_f32(wkr_, xi_); const float32x4_t d_ = vmulq_f32(wki_, xr_); const float32x4_t yr_ = vsubq_f32(a_, b_); // 2-126, 4-124, 6-122, 8-120, const float32x4_t yi_ = vaddq_f32(c_, d_); // 3-127, 5-125, 7-123, 9-121, // Update 'a'. // a[j2 + 0] -= yr; // a[j2 + 1] -= yi; // a[k2 + 0] += yr; // a[k2 + 1] -= yi; // 126, 124, 122, 120, const float32x4_t a_k2_p0n = vaddq_f32(a_k2_p0, yr_); // 127, 125, 123, 121, const float32x4_t a_k2_p1n = vsubq_f32(a_k2_p1, yi_); // Shuffle in right order and store. const float32x4_t a_k2_p0nr = vrev64q_f32(a_k2_p0n); const float32x4_t a_k2_p1nr = vrev64q_f32(a_k2_p1n); // 124, 125, 126, 127, 120, 121, 122, 123 const float32x4x2_t a_k2_n = vzipq_f32(a_k2_p0nr, a_k2_p1nr); // 2, 4, 6, 8, a_j2_p.val[0] = vsubq_f32(a_j2_p.val[0], yr_); // 3, 5, 7, 9, a_j2_p.val[1] = vsubq_f32(a_j2_p.val[1], yi_); // 2, 3, 4, 5, 6, 7, 8, 9, vst2q_f32(&a[0 + j2], a_j2_p); vst1q_f32(&a[122 - j2], a_k2_n.val[1]); vst1q_f32(&a[126 - j2], a_k2_n.val[0]); } // Scalar code for the remaining items. for (; j2 < 64; j1 += 1, j2 += 2) { const int k2 = 128 - j2; const int k1 = 32 - j1; const float wkr = 0.5f - c[k1]; const float wki = c[j1]; const float xr = a[j2 + 0] - a[k2 + 0]; const float xi = a[j2 + 1] + a[k2 + 1]; const float yr = wkr * xr - wki * xi; const float yi = wkr * xi + wki * xr; a[j2 + 0] -= yr; a[j2 + 1] -= yi; a[k2 + 0] += yr; a[k2 + 1] -= yi; } } void rftbsub_128_neon(float* a) { const float* c = rdft_w + 32; int j1, j2; const float32x4_t mm_half = vdupq_n_f32(0.5f); a[1] = -a[1]; // Vectorized code (four at once). // Note: commented number are indexes for the first iteration of the loop. for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) { // Load 'wk'. const float32x4_t c_j1 = vld1q_f32(&c[j1]); // 1, 2, 3, 4, const float32x4_t c_k1 = vld1q_f32(&c[29 - j1]); // 28, 29, 30, 31, const float32x4_t wkrt = vsubq_f32(mm_half, c_k1); // 28, 29, 30, 31, const float32x4_t wkr_ = reverse_order_f32x4(wkrt); // 31, 30, 29, 28, const float32x4_t wki_ = c_j1; // 1, 2, 3, 4, // Load and shuffle 'a'. // 2, 4, 6, 8, 3, 5, 7, 9 float32x4x2_t a_j2_p = vld2q_f32(&a[0 + j2]); // 120, 122, 124, 126, 121, 123, 125, 127, const float32x4x2_t k2_0_4 = vld2q_f32(&a[122 - j2]); // 126, 124, 122, 120 const float32x4_t a_k2_p0 = reverse_order_f32x4(k2_0_4.val[0]); // 127, 125, 123, 121 const float32x4_t a_k2_p1 = reverse_order_f32x4(k2_0_4.val[1]); // Calculate 'x'. const float32x4_t xr_ = vsubq_f32(a_j2_p.val[0], a_k2_p0); // 2-126, 4-124, 6-122, 8-120, const float32x4_t xi_ = vaddq_f32(a_j2_p.val[1], a_k2_p1); // 3-127, 5-125, 7-123, 9-121, // Calculate product into 'y'. // yr = wkr * xr - wki * xi; // yi = wkr * xi + wki * xr; const float32x4_t a_ = vmulq_f32(wkr_, xr_); const float32x4_t b_ = vmulq_f32(wki_, xi_); const float32x4_t c_ = vmulq_f32(wkr_, xi_); const float32x4_t d_ = vmulq_f32(wki_, xr_); const float32x4_t yr_ = vaddq_f32(a_, b_); // 2-126, 4-124, 6-122, 8-120, const float32x4_t yi_ = vsubq_f32(c_, d_); // 3-127, 5-125, 7-123, 9-121, // Update 'a'. // a[j2 + 0] -= yr; // a[j2 + 1] -= yi; // a[k2 + 0] += yr; // a[k2 + 1] -= yi; // 126, 124, 122, 120, const float32x4_t a_k2_p0n = vaddq_f32(a_k2_p0, yr_); // 127, 125, 123, 121, const float32x4_t a_k2_p1n = vsubq_f32(yi_, a_k2_p1); // Shuffle in right order and store. // 2, 3, 4, 5, 6, 7, 8, 9, const float32x4_t a_k2_p0nr = vrev64q_f32(a_k2_p0n); const float32x4_t a_k2_p1nr = vrev64q_f32(a_k2_p1n); // 124, 125, 126, 127, 120, 121, 122, 123 const float32x4x2_t a_k2_n = vzipq_f32(a_k2_p0nr, a_k2_p1nr); // 2, 4, 6, 8, a_j2_p.val[0] = vsubq_f32(a_j2_p.val[0], yr_); // 3, 5, 7, 9, a_j2_p.val[1] = vsubq_f32(yi_, a_j2_p.val[1]); // 2, 3, 4, 5, 6, 7, 8, 9, vst2q_f32(&a[0 + j2], a_j2_p); vst1q_f32(&a[122 - j2], a_k2_n.val[1]); vst1q_f32(&a[126 - j2], a_k2_n.val[0]); } // Scalar code for the remaining items. for (; j2 < 64; j1 += 1, j2 += 2) { const int k2 = 128 - j2; const int k1 = 32 - j1; const float wkr = 0.5f - c[k1]; const float wki = c[j1]; const float xr = a[j2 + 0] - a[k2 + 0]; const float xi = a[j2 + 1] + a[k2 + 1]; const float yr = wkr * xr + wki * xi; const float yi = wkr * xi - wki * xr; a[j2 + 0] = a[j2 + 0] - yr; a[j2 + 1] = yi - a[j2 + 1]; a[k2 + 0] = yr + a[k2 + 0]; a[k2 + 1] = yi - a[k2 + 1]; } a[65] = -a[65]; } #endif } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_sse2.cc0000664000175000017500000004554614475643423031753 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include #include #include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h" #include "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h" #include "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_neon_sse2.h" #include "rtc_base/system/arch.h" namespace webrtc { #if defined(WEBRTC_ARCH_X86_FAMILY) namespace { // These intrinsics were unavailable before VS 2008. // TODO(andrew): move to a common file. #if defined(_MSC_VER) && _MSC_VER < 1500 static __inline __m128 _mm_castsi128_ps(__m128i a) { return *(__m128*)&a; } static __inline __m128i _mm_castps_si128(__m128 a) { return *(__m128i*)&a; } #endif } // namespace void cft1st_128_SSE2(float* a) { const __m128 mm_swap_sign = _mm_load_ps(k_swap_sign); int j, k2; for (k2 = 0, j = 0; j < 128; j += 16, k2 += 4) { __m128 a00v = _mm_loadu_ps(&a[j + 0]); __m128 a04v = _mm_loadu_ps(&a[j + 4]); __m128 a08v = _mm_loadu_ps(&a[j + 8]); __m128 a12v = _mm_loadu_ps(&a[j + 12]); __m128 a01v = _mm_shuffle_ps(a00v, a08v, _MM_SHUFFLE(1, 0, 1, 0)); __m128 a23v = _mm_shuffle_ps(a00v, a08v, _MM_SHUFFLE(3, 2, 3, 2)); __m128 a45v = _mm_shuffle_ps(a04v, a12v, _MM_SHUFFLE(1, 0, 1, 0)); __m128 a67v = _mm_shuffle_ps(a04v, a12v, _MM_SHUFFLE(3, 2, 3, 2)); const __m128 wk1rv = _mm_load_ps(&rdft_wk1r[k2]); const __m128 wk1iv = _mm_load_ps(&rdft_wk1i[k2]); const __m128 wk2rv = _mm_load_ps(&rdft_wk2r[k2]); const __m128 wk2iv = _mm_load_ps(&rdft_wk2i[k2]); const __m128 wk3rv = _mm_load_ps(&rdft_wk3r[k2]); const __m128 wk3iv = _mm_load_ps(&rdft_wk3i[k2]); __m128 x0v = _mm_add_ps(a01v, a23v); const __m128 x1v = _mm_sub_ps(a01v, a23v); const __m128 x2v = _mm_add_ps(a45v, a67v); const __m128 x3v = _mm_sub_ps(a45v, a67v); __m128 x0w; a01v = _mm_add_ps(x0v, x2v); x0v = _mm_sub_ps(x0v, x2v); x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0, 1)); { const __m128 a45_0v = _mm_mul_ps(wk2rv, x0v); const __m128 a45_1v = _mm_mul_ps(wk2iv, x0w); a45v = _mm_add_ps(a45_0v, a45_1v); } { __m128 a23_0v, a23_1v; const __m128 x3w = _mm_shuffle_ps(x3v, x3v, _MM_SHUFFLE(2, 3, 0, 1)); const __m128 x3s = _mm_mul_ps(mm_swap_sign, x3w); x0v = _mm_add_ps(x1v, x3s); x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0, 1)); a23_0v = _mm_mul_ps(wk1rv, x0v); a23_1v = _mm_mul_ps(wk1iv, x0w); a23v = _mm_add_ps(a23_0v, a23_1v); x0v = _mm_sub_ps(x1v, x3s); x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0, 1)); } { const __m128 a67_0v = _mm_mul_ps(wk3rv, x0v); const __m128 a67_1v = _mm_mul_ps(wk3iv, x0w); a67v = _mm_add_ps(a67_0v, a67_1v); } a00v = _mm_shuffle_ps(a01v, a23v, _MM_SHUFFLE(1, 0, 1, 0)); a04v = _mm_shuffle_ps(a45v, a67v, _MM_SHUFFLE(1, 0, 1, 0)); a08v = _mm_shuffle_ps(a01v, a23v, _MM_SHUFFLE(3, 2, 3, 2)); a12v = _mm_shuffle_ps(a45v, a67v, _MM_SHUFFLE(3, 2, 3, 2)); _mm_storeu_ps(&a[j + 0], a00v); _mm_storeu_ps(&a[j + 4], a04v); _mm_storeu_ps(&a[j + 8], a08v); _mm_storeu_ps(&a[j + 12], a12v); } } void cftmdl_128_SSE2(float* a) { const int l = 8; const __m128 mm_swap_sign = _mm_load_ps(k_swap_sign); int j0; __m128 wk1rv = _mm_load_ps(cftmdl_wk1r); for (j0 = 0; j0 < l; j0 += 2) { const __m128i a_00 = _mm_loadl_epi64((__m128i*)&a[j0 + 0]); const __m128i a_08 = _mm_loadl_epi64((__m128i*)&a[j0 + 8]); const __m128i a_32 = _mm_loadl_epi64((__m128i*)&a[j0 + 32]); const __m128i a_40 = _mm_loadl_epi64((__m128i*)&a[j0 + 40]); const __m128 a_00_32 = _mm_shuffle_ps(_mm_castsi128_ps(a_00), _mm_castsi128_ps(a_32), _MM_SHUFFLE(1, 0, 1, 0)); const __m128 a_08_40 = _mm_shuffle_ps(_mm_castsi128_ps(a_08), _mm_castsi128_ps(a_40), _MM_SHUFFLE(1, 0, 1, 0)); __m128 x0r0_0i0_0r1_x0i1 = _mm_add_ps(a_00_32, a_08_40); const __m128 x1r0_1i0_1r1_x1i1 = _mm_sub_ps(a_00_32, a_08_40); const __m128i a_16 = _mm_loadl_epi64((__m128i*)&a[j0 + 16]); const __m128i a_24 = _mm_loadl_epi64((__m128i*)&a[j0 + 24]); const __m128i a_48 = _mm_loadl_epi64((__m128i*)&a[j0 + 48]); const __m128i a_56 = _mm_loadl_epi64((__m128i*)&a[j0 + 56]); const __m128 a_16_48 = _mm_shuffle_ps(_mm_castsi128_ps(a_16), _mm_castsi128_ps(a_48), _MM_SHUFFLE(1, 0, 1, 0)); const __m128 a_24_56 = _mm_shuffle_ps(_mm_castsi128_ps(a_24), _mm_castsi128_ps(a_56), _MM_SHUFFLE(1, 0, 1, 0)); const __m128 x2r0_2i0_2r1_x2i1 = _mm_add_ps(a_16_48, a_24_56); const __m128 x3r0_3i0_3r1_x3i1 = _mm_sub_ps(a_16_48, a_24_56); const __m128 xx0 = _mm_add_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); const __m128 xx1 = _mm_sub_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); const __m128 x3i0_3r0_3i1_x3r1 = _mm_castsi128_ps(_mm_shuffle_epi32( _mm_castps_si128(x3r0_3i0_3r1_x3i1), _MM_SHUFFLE(2, 3, 0, 1))); const __m128 x3_swapped = _mm_mul_ps(mm_swap_sign, x3i0_3r0_3i1_x3r1); const __m128 x1_x3_add = _mm_add_ps(x1r0_1i0_1r1_x1i1, x3_swapped); const __m128 x1_x3_sub = _mm_sub_ps(x1r0_1i0_1r1_x1i1, x3_swapped); const __m128 yy0 = _mm_shuffle_ps(x1_x3_add, x1_x3_sub, _MM_SHUFFLE(2, 2, 2, 2)); const __m128 yy1 = _mm_shuffle_ps(x1_x3_add, x1_x3_sub, _MM_SHUFFLE(3, 3, 3, 3)); const __m128 yy2 = _mm_mul_ps(mm_swap_sign, yy1); const __m128 yy3 = _mm_add_ps(yy0, yy2); const __m128 yy4 = _mm_mul_ps(wk1rv, yy3); _mm_storel_epi64((__m128i*)&a[j0 + 0], _mm_castps_si128(xx0)); _mm_storel_epi64( (__m128i*)&a[j0 + 32], _mm_shuffle_epi32(_mm_castps_si128(xx0), _MM_SHUFFLE(3, 2, 3, 2))); _mm_storel_epi64((__m128i*)&a[j0 + 16], _mm_castps_si128(xx1)); _mm_storel_epi64( (__m128i*)&a[j0 + 48], _mm_shuffle_epi32(_mm_castps_si128(xx1), _MM_SHUFFLE(2, 3, 2, 3))); a[j0 + 48] = -a[j0 + 48]; _mm_storel_epi64((__m128i*)&a[j0 + 8], _mm_castps_si128(x1_x3_add)); _mm_storel_epi64((__m128i*)&a[j0 + 24], _mm_castps_si128(x1_x3_sub)); _mm_storel_epi64((__m128i*)&a[j0 + 40], _mm_castps_si128(yy4)); _mm_storel_epi64( (__m128i*)&a[j0 + 56], _mm_shuffle_epi32(_mm_castps_si128(yy4), _MM_SHUFFLE(2, 3, 2, 3))); } { int k = 64; int k1 = 2; int k2 = 2 * k1; const __m128 wk2rv = _mm_load_ps(&rdft_wk2r[k2 + 0]); const __m128 wk2iv = _mm_load_ps(&rdft_wk2i[k2 + 0]); const __m128 wk1iv = _mm_load_ps(&rdft_wk1i[k2 + 0]); const __m128 wk3rv = _mm_load_ps(&rdft_wk3r[k2 + 0]); const __m128 wk3iv = _mm_load_ps(&rdft_wk3i[k2 + 0]); wk1rv = _mm_load_ps(&rdft_wk1r[k2 + 0]); for (j0 = k; j0 < l + k; j0 += 2) { const __m128i a_00 = _mm_loadl_epi64((__m128i*)&a[j0 + 0]); const __m128i a_08 = _mm_loadl_epi64((__m128i*)&a[j0 + 8]); const __m128i a_32 = _mm_loadl_epi64((__m128i*)&a[j0 + 32]); const __m128i a_40 = _mm_loadl_epi64((__m128i*)&a[j0 + 40]); const __m128 a_00_32 = _mm_shuffle_ps(_mm_castsi128_ps(a_00), _mm_castsi128_ps(a_32), _MM_SHUFFLE(1, 0, 1, 0)); const __m128 a_08_40 = _mm_shuffle_ps(_mm_castsi128_ps(a_08), _mm_castsi128_ps(a_40), _MM_SHUFFLE(1, 0, 1, 0)); __m128 x0r0_0i0_0r1_x0i1 = _mm_add_ps(a_00_32, a_08_40); const __m128 x1r0_1i0_1r1_x1i1 = _mm_sub_ps(a_00_32, a_08_40); const __m128i a_16 = _mm_loadl_epi64((__m128i*)&a[j0 + 16]); const __m128i a_24 = _mm_loadl_epi64((__m128i*)&a[j0 + 24]); const __m128i a_48 = _mm_loadl_epi64((__m128i*)&a[j0 + 48]); const __m128i a_56 = _mm_loadl_epi64((__m128i*)&a[j0 + 56]); const __m128 a_16_48 = _mm_shuffle_ps(_mm_castsi128_ps(a_16), _mm_castsi128_ps(a_48), _MM_SHUFFLE(1, 0, 1, 0)); const __m128 a_24_56 = _mm_shuffle_ps(_mm_castsi128_ps(a_24), _mm_castsi128_ps(a_56), _MM_SHUFFLE(1, 0, 1, 0)); const __m128 x2r0_2i0_2r1_x2i1 = _mm_add_ps(a_16_48, a_24_56); const __m128 x3r0_3i0_3r1_x3i1 = _mm_sub_ps(a_16_48, a_24_56); const __m128 xx = _mm_add_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); const __m128 xx1 = _mm_sub_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); const __m128 xx2 = _mm_mul_ps(xx1, wk2rv); const __m128 xx3 = _mm_mul_ps( wk2iv, _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(xx1), _MM_SHUFFLE(2, 3, 0, 1)))); const __m128 xx4 = _mm_add_ps(xx2, xx3); const __m128 x3i0_3r0_3i1_x3r1 = _mm_castsi128_ps(_mm_shuffle_epi32( _mm_castps_si128(x3r0_3i0_3r1_x3i1), _MM_SHUFFLE(2, 3, 0, 1))); const __m128 x3_swapped = _mm_mul_ps(mm_swap_sign, x3i0_3r0_3i1_x3r1); const __m128 x1_x3_add = _mm_add_ps(x1r0_1i0_1r1_x1i1, x3_swapped); const __m128 x1_x3_sub = _mm_sub_ps(x1r0_1i0_1r1_x1i1, x3_swapped); const __m128 xx10 = _mm_mul_ps(x1_x3_add, wk1rv); const __m128 xx11 = _mm_mul_ps( wk1iv, _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(x1_x3_add), _MM_SHUFFLE(2, 3, 0, 1)))); const __m128 xx12 = _mm_add_ps(xx10, xx11); const __m128 xx20 = _mm_mul_ps(x1_x3_sub, wk3rv); const __m128 xx21 = _mm_mul_ps( wk3iv, _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(x1_x3_sub), _MM_SHUFFLE(2, 3, 0, 1)))); const __m128 xx22 = _mm_add_ps(xx20, xx21); _mm_storel_epi64((__m128i*)&a[j0 + 0], _mm_castps_si128(xx)); _mm_storel_epi64( (__m128i*)&a[j0 + 32], _mm_shuffle_epi32(_mm_castps_si128(xx), _MM_SHUFFLE(3, 2, 3, 2))); _mm_storel_epi64((__m128i*)&a[j0 + 16], _mm_castps_si128(xx4)); _mm_storel_epi64( (__m128i*)&a[j0 + 48], _mm_shuffle_epi32(_mm_castps_si128(xx4), _MM_SHUFFLE(3, 2, 3, 2))); _mm_storel_epi64((__m128i*)&a[j0 + 8], _mm_castps_si128(xx12)); _mm_storel_epi64( (__m128i*)&a[j0 + 40], _mm_shuffle_epi32(_mm_castps_si128(xx12), _MM_SHUFFLE(3, 2, 3, 2))); _mm_storel_epi64((__m128i*)&a[j0 + 24], _mm_castps_si128(xx22)); _mm_storel_epi64( (__m128i*)&a[j0 + 56], _mm_shuffle_epi32(_mm_castps_si128(xx22), _MM_SHUFFLE(3, 2, 3, 2))); } } } void rftfsub_128_SSE2(float* a) { const float* c = rdft_w + 32; int j1, j2, k1, k2; float wkr, wki, xr, xi, yr, yi; static const ALIGN16_BEG float ALIGN16_END k_half[4] = {0.5f, 0.5f, 0.5f, 0.5f}; const __m128 mm_half = _mm_load_ps(k_half); // Vectorized code (four at once). // Note: commented number are indexes for the first iteration of the loop. for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) { // Load 'wk'. const __m128 c_j1 = _mm_loadu_ps(&c[j1]); // 1, 2, 3, 4, const __m128 c_k1 = _mm_loadu_ps(&c[29 - j1]); // 28, 29, 30, 31, const __m128 wkrt = _mm_sub_ps(mm_half, c_k1); // 28, 29, 30, 31, const __m128 wkr_ = _mm_shuffle_ps(wkrt, wkrt, _MM_SHUFFLE(0, 1, 2, 3)); // 31, 30, 29, 28, const __m128 wki_ = c_j1; // 1, 2, 3, 4, // Load and shuffle 'a'. const __m128 a_j2_0 = _mm_loadu_ps(&a[0 + j2]); // 2, 3, 4, 5, const __m128 a_j2_4 = _mm_loadu_ps(&a[4 + j2]); // 6, 7, 8, 9, const __m128 a_k2_0 = _mm_loadu_ps(&a[122 - j2]); // 120, 121, 122, 123, const __m128 a_k2_4 = _mm_loadu_ps(&a[126 - j2]); // 124, 125, 126, 127, const __m128 a_j2_p0 = _mm_shuffle_ps( a_j2_0, a_j2_4, _MM_SHUFFLE(2, 0, 2, 0)); // 2, 4, 6, 8, const __m128 a_j2_p1 = _mm_shuffle_ps( a_j2_0, a_j2_4, _MM_SHUFFLE(3, 1, 3, 1)); // 3, 5, 7, 9, const __m128 a_k2_p0 = _mm_shuffle_ps( a_k2_4, a_k2_0, _MM_SHUFFLE(0, 2, 0, 2)); // 126, 124, 122, 120, const __m128 a_k2_p1 = _mm_shuffle_ps( a_k2_4, a_k2_0, _MM_SHUFFLE(1, 3, 1, 3)); // 127, 125, 123, 121, // Calculate 'x'. const __m128 xr_ = _mm_sub_ps(a_j2_p0, a_k2_p0); // 2-126, 4-124, 6-122, 8-120, const __m128 xi_ = _mm_add_ps(a_j2_p1, a_k2_p1); // 3-127, 5-125, 7-123, 9-121, // Calculate product into 'y'. // yr = wkr * xr - wki * xi; // yi = wkr * xi + wki * xr; const __m128 a_ = _mm_mul_ps(wkr_, xr_); const __m128 b_ = _mm_mul_ps(wki_, xi_); const __m128 c_ = _mm_mul_ps(wkr_, xi_); const __m128 d_ = _mm_mul_ps(wki_, xr_); const __m128 yr_ = _mm_sub_ps(a_, b_); // 2-126, 4-124, 6-122, 8-120, const __m128 yi_ = _mm_add_ps(c_, d_); // 3-127, 5-125, 7-123, 9-121, // Update 'a'. // a[j2 + 0] -= yr; // a[j2 + 1] -= yi; // a[k2 + 0] += yr; // a[k2 + 1] -= yi; const __m128 a_j2_p0n = _mm_sub_ps(a_j2_p0, yr_); // 2, 4, 6, 8, const __m128 a_j2_p1n = _mm_sub_ps(a_j2_p1, yi_); // 3, 5, 7, 9, const __m128 a_k2_p0n = _mm_add_ps(a_k2_p0, yr_); // 126, 124, 122, 120, const __m128 a_k2_p1n = _mm_sub_ps(a_k2_p1, yi_); // 127, 125, 123, 121, // Shuffle in right order and store. const __m128 a_j2_0n = _mm_unpacklo_ps(a_j2_p0n, a_j2_p1n); // 2, 3, 4, 5, const __m128 a_j2_4n = _mm_unpackhi_ps(a_j2_p0n, a_j2_p1n); // 6, 7, 8, 9, const __m128 a_k2_0nt = _mm_unpackhi_ps(a_k2_p0n, a_k2_p1n); // 122, 123, 120, 121, const __m128 a_k2_4nt = _mm_unpacklo_ps(a_k2_p0n, a_k2_p1n); // 126, 127, 124, 125, const __m128 a_k2_0n = _mm_shuffle_ps( a_k2_0nt, a_k2_0nt, _MM_SHUFFLE(1, 0, 3, 2)); // 120, 121, 122, 123, const __m128 a_k2_4n = _mm_shuffle_ps( a_k2_4nt, a_k2_4nt, _MM_SHUFFLE(1, 0, 3, 2)); // 124, 125, 126, 127, _mm_storeu_ps(&a[0 + j2], a_j2_0n); _mm_storeu_ps(&a[4 + j2], a_j2_4n); _mm_storeu_ps(&a[122 - j2], a_k2_0n); _mm_storeu_ps(&a[126 - j2], a_k2_4n); } // Scalar code for the remaining items. for (; j2 < 64; j1 += 1, j2 += 2) { k2 = 128 - j2; k1 = 32 - j1; wkr = 0.5f - c[k1]; wki = c[j1]; xr = a[j2 + 0] - a[k2 + 0]; xi = a[j2 + 1] + a[k2 + 1]; yr = wkr * xr - wki * xi; yi = wkr * xi + wki * xr; a[j2 + 0] -= yr; a[j2 + 1] -= yi; a[k2 + 0] += yr; a[k2 + 1] -= yi; } } void rftbsub_128_SSE2(float* a) { const float* c = rdft_w + 32; int j1, j2, k1, k2; float wkr, wki, xr, xi, yr, yi; static const ALIGN16_BEG float ALIGN16_END k_half[4] = {0.5f, 0.5f, 0.5f, 0.5f}; const __m128 mm_half = _mm_load_ps(k_half); a[1] = -a[1]; // Vectorized code (four at once). // Note: commented number are indexes for the first iteration of the loop. for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) { // Load 'wk'. const __m128 c_j1 = _mm_loadu_ps(&c[j1]); // 1, 2, 3, 4, const __m128 c_k1 = _mm_loadu_ps(&c[29 - j1]); // 28, 29, 30, 31, const __m128 wkrt = _mm_sub_ps(mm_half, c_k1); // 28, 29, 30, 31, const __m128 wkr_ = _mm_shuffle_ps(wkrt, wkrt, _MM_SHUFFLE(0, 1, 2, 3)); // 31, 30, 29, 28, const __m128 wki_ = c_j1; // 1, 2, 3, 4, // Load and shuffle 'a'. const __m128 a_j2_0 = _mm_loadu_ps(&a[0 + j2]); // 2, 3, 4, 5, const __m128 a_j2_4 = _mm_loadu_ps(&a[4 + j2]); // 6, 7, 8, 9, const __m128 a_k2_0 = _mm_loadu_ps(&a[122 - j2]); // 120, 121, 122, 123, const __m128 a_k2_4 = _mm_loadu_ps(&a[126 - j2]); // 124, 125, 126, 127, const __m128 a_j2_p0 = _mm_shuffle_ps( a_j2_0, a_j2_4, _MM_SHUFFLE(2, 0, 2, 0)); // 2, 4, 6, 8, const __m128 a_j2_p1 = _mm_shuffle_ps( a_j2_0, a_j2_4, _MM_SHUFFLE(3, 1, 3, 1)); // 3, 5, 7, 9, const __m128 a_k2_p0 = _mm_shuffle_ps( a_k2_4, a_k2_0, _MM_SHUFFLE(0, 2, 0, 2)); // 126, 124, 122, 120, const __m128 a_k2_p1 = _mm_shuffle_ps( a_k2_4, a_k2_0, _MM_SHUFFLE(1, 3, 1, 3)); // 127, 125, 123, 121, // Calculate 'x'. const __m128 xr_ = _mm_sub_ps(a_j2_p0, a_k2_p0); // 2-126, 4-124, 6-122, 8-120, const __m128 xi_ = _mm_add_ps(a_j2_p1, a_k2_p1); // 3-127, 5-125, 7-123, 9-121, // Calculate product into 'y'. // yr = wkr * xr + wki * xi; // yi = wkr * xi - wki * xr; const __m128 a_ = _mm_mul_ps(wkr_, xr_); const __m128 b_ = _mm_mul_ps(wki_, xi_); const __m128 c_ = _mm_mul_ps(wkr_, xi_); const __m128 d_ = _mm_mul_ps(wki_, xr_); const __m128 yr_ = _mm_add_ps(a_, b_); // 2-126, 4-124, 6-122, 8-120, const __m128 yi_ = _mm_sub_ps(c_, d_); // 3-127, 5-125, 7-123, 9-121, // Update 'a'. // a[j2 + 0] = a[j2 + 0] - yr; // a[j2 + 1] = yi - a[j2 + 1]; // a[k2 + 0] = yr + a[k2 + 0]; // a[k2 + 1] = yi - a[k2 + 1]; const __m128 a_j2_p0n = _mm_sub_ps(a_j2_p0, yr_); // 2, 4, 6, 8, const __m128 a_j2_p1n = _mm_sub_ps(yi_, a_j2_p1); // 3, 5, 7, 9, const __m128 a_k2_p0n = _mm_add_ps(a_k2_p0, yr_); // 126, 124, 122, 120, const __m128 a_k2_p1n = _mm_sub_ps(yi_, a_k2_p1); // 127, 125, 123, 121, // Shuffle in right order and store. const __m128 a_j2_0n = _mm_unpacklo_ps(a_j2_p0n, a_j2_p1n); // 2, 3, 4, 5, const __m128 a_j2_4n = _mm_unpackhi_ps(a_j2_p0n, a_j2_p1n); // 6, 7, 8, 9, const __m128 a_k2_0nt = _mm_unpackhi_ps(a_k2_p0n, a_k2_p1n); // 122, 123, 120, 121, const __m128 a_k2_4nt = _mm_unpacklo_ps(a_k2_p0n, a_k2_p1n); // 126, 127, 124, 125, const __m128 a_k2_0n = _mm_shuffle_ps( a_k2_0nt, a_k2_0nt, _MM_SHUFFLE(1, 0, 3, 2)); // 120, 121, 122, 123, const __m128 a_k2_4n = _mm_shuffle_ps( a_k2_4nt, a_k2_4nt, _MM_SHUFFLE(1, 0, 3, 2)); // 124, 125, 126, 127, _mm_storeu_ps(&a[0 + j2], a_j2_0n); _mm_storeu_ps(&a[4 + j2], a_j2_4n); _mm_storeu_ps(&a[122 - j2], a_k2_0n); _mm_storeu_ps(&a[126 - j2], a_k2_4n); } // Scalar code for the remaining items. for (; j2 < 64; j1 += 1, j2 += 2) { k2 = 128 - j2; k1 = 32 - j1; wkr = 0.5f - c[k1]; wki = c[j1]; xr = a[j2 + 0] - a[k2 + 0]; xi = a[j2 + 1] + a[k2 + 1]; yr = wkr * xr + wki * xi; yi = wkr * xi - wki * xr; a[j2 + 0] = a[j2 + 0] - yr; a[j2 + 1] = yi - a[j2 + 1]; a[k2 + 0] = yr + a[k2 + 0]; a[k2 + 1] = yi - a[k2 + 1]; } a[65] = -a[65]; } #endif } // namespace webrtc ././@PaxHeader0000000000000000000000000000021000000000000010206 xustar00114 path=webrtc-audio-processing-1.3/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_comm0000664000175000017500000000516014475643423032764 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_TABLES_COMMON_H_ #define MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_TABLES_COMMON_H_ #include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h" namespace webrtc { // This tables used to be computed at run-time. For example, refer to: // https://code.google.com/p/webrtc/source/browse/trunk/webrtc/modules/audio_processing/utility/apm_rdft.c?r=6564 // to see the initialization code. // Constants shared by all paths (C, SSE2, NEON). const float rdft_w[64] = { 1.0000000000f, 0.0000000000f, 0.7071067691f, 0.7071067691f, 0.9238795638f, 0.3826834559f, 0.3826834559f, 0.9238795638f, 0.9807852507f, 0.1950903237f, 0.5555702448f, 0.8314695954f, 0.8314695954f, 0.5555702448f, 0.1950903237f, 0.9807852507f, 0.9951847196f, 0.0980171412f, 0.6343933344f, 0.7730104327f, 0.8819212914f, 0.4713967443f, 0.2902846634f, 0.9569403529f, 0.9569403529f, 0.2902846634f, 0.4713967443f, 0.8819212914f, 0.7730104327f, 0.6343933344f, 0.0980171412f, 0.9951847196f, 0.7071067691f, 0.4993977249f, 0.4975923598f, 0.4945882559f, 0.4903926253f, 0.4850156307f, 0.4784701765f, 0.4707720280f, 0.4619397819f, 0.4519946277f, 0.4409606457f, 0.4288643003f, 0.4157347977f, 0.4016037583f, 0.3865052164f, 0.3704755902f, 0.3535533845f, 0.3357794881f, 0.3171966672f, 0.2978496552f, 0.2777851224f, 0.2570513785f, 0.2356983721f, 0.2137775421f, 0.1913417280f, 0.1684449315f, 0.1451423317f, 0.1214900985f, 0.0975451618f, 0.0733652338f, 0.0490085706f, 0.0245338380f, }; // Constants used by the C and MIPS paths. const float rdft_wk3ri_first[16] = { 1.000000000f, 0.000000000f, 0.382683456f, 0.923879564f, 0.831469536f, 0.555570245f, -0.195090353f, 0.980785251f, 0.956940353f, 0.290284693f, 0.098017156f, 0.995184720f, 0.634393334f, 0.773010492f, -0.471396863f, 0.881921172f, }; const float rdft_wk3ri_second[16] = { -0.707106769f, 0.707106769f, -0.923879564f, -0.382683456f, -0.980785251f, 0.195090353f, -0.555570245f, -0.831469536f, -0.881921172f, 0.471396863f, -0.773010492f, -0.634393334f, -0.995184720f, -0.098017156f, -0.290284693f, -0.956940353f, }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_TABLES_COMMON_H_ ././@PaxHeader0000000000000000000000000000021300000000000010211 xustar00117 path=webrtc-audio-processing-1.3/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_neon_sse2.h 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_neon0000664000175000017500000001141714475643423032772 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_TABLES_NEON_SSE2_H_ #define MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_TABLES_NEON_SSE2_H_ #include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h" #include "rtc_base/system/arch.h" #ifdef _MSC_VER /* visual c++ */ #define ALIGN16_BEG __declspec(align(16)) #define ALIGN16_END #else /* gcc or icc */ #define ALIGN16_BEG #define ALIGN16_END __attribute__((aligned(16))) #endif namespace webrtc { // These tables used to be computed at run-time. For example, refer to: // https://code.google.com/p/webrtc/source/browse/trunk/webrtc/modules/audio_processing/utility/apm_rdft.c?r=6564 // to see the initialization code. #if defined(WEBRTC_ARCH_X86_FAMILY) || defined(WEBRTC_HAS_NEON) // Constants used by SSE2 and NEON but initialized in the C path. const ALIGN16_BEG float ALIGN16_END k_swap_sign[4] = {-1.f, 1.f, -1.f, 1.f}; ALIGN16_BEG const float ALIGN16_END rdft_wk1r[32] = { 1.000000000f, 1.000000000f, 0.707106769f, 0.707106769f, 0.923879564f, 0.923879564f, 0.382683456f, 0.382683456f, 0.980785251f, 0.980785251f, 0.555570245f, 0.555570245f, 0.831469595f, 0.831469595f, 0.195090324f, 0.195090324f, 0.995184720f, 0.995184720f, 0.634393334f, 0.634393334f, 0.881921291f, 0.881921291f, 0.290284663f, 0.290284663f, 0.956940353f, 0.956940353f, 0.471396744f, 0.471396744f, 0.773010433f, 0.773010433f, 0.098017141f, 0.098017141f, }; ALIGN16_BEG const float ALIGN16_END rdft_wk2r[32] = { 1.000000000f, 1.000000000f, -0.000000000f, -0.000000000f, 0.707106769f, 0.707106769f, -0.707106769f, -0.707106769f, 0.923879564f, 0.923879564f, -0.382683456f, -0.382683456f, 0.382683456f, 0.382683456f, -0.923879564f, -0.923879564f, 0.980785251f, 0.980785251f, -0.195090324f, -0.195090324f, 0.555570245f, 0.555570245f, -0.831469595f, -0.831469595f, 0.831469595f, 0.831469595f, -0.555570245f, -0.555570245f, 0.195090324f, 0.195090324f, -0.980785251f, -0.980785251f, }; ALIGN16_BEG const float ALIGN16_END rdft_wk3r[32] = { 1.000000000f, 1.000000000f, -0.707106769f, -0.707106769f, 0.382683456f, 0.382683456f, -0.923879564f, -0.923879564f, 0.831469536f, 0.831469536f, -0.980785251f, -0.980785251f, -0.195090353f, -0.195090353f, -0.555570245f, -0.555570245f, 0.956940353f, 0.956940353f, -0.881921172f, -0.881921172f, 0.098017156f, 0.098017156f, -0.773010492f, -0.773010492f, 0.634393334f, 0.634393334f, -0.995184720f, -0.995184720f, -0.471396863f, -0.471396863f, -0.290284693f, -0.290284693f, }; ALIGN16_BEG const float ALIGN16_END rdft_wk1i[32] = { -0.000000000f, 0.000000000f, -0.707106769f, 0.707106769f, -0.382683456f, 0.382683456f, -0.923879564f, 0.923879564f, -0.195090324f, 0.195090324f, -0.831469595f, 0.831469595f, -0.555570245f, 0.555570245f, -0.980785251f, 0.980785251f, -0.098017141f, 0.098017141f, -0.773010433f, 0.773010433f, -0.471396744f, 0.471396744f, -0.956940353f, 0.956940353f, -0.290284663f, 0.290284663f, -0.881921291f, 0.881921291f, -0.634393334f, 0.634393334f, -0.995184720f, 0.995184720f, }; ALIGN16_BEG const float ALIGN16_END rdft_wk2i[32] = { -0.000000000f, 0.000000000f, -1.000000000f, 1.000000000f, -0.707106769f, 0.707106769f, -0.707106769f, 0.707106769f, -0.382683456f, 0.382683456f, -0.923879564f, 0.923879564f, -0.923879564f, 0.923879564f, -0.382683456f, 0.382683456f, -0.195090324f, 0.195090324f, -0.980785251f, 0.980785251f, -0.831469595f, 0.831469595f, -0.555570245f, 0.555570245f, -0.555570245f, 0.555570245f, -0.831469595f, 0.831469595f, -0.980785251f, 0.980785251f, -0.195090324f, 0.195090324f, }; ALIGN16_BEG const float ALIGN16_END rdft_wk3i[32] = { -0.000000000f, 0.000000000f, -0.707106769f, 0.707106769f, -0.923879564f, 0.923879564f, 0.382683456f, -0.382683456f, -0.555570245f, 0.555570245f, -0.195090353f, 0.195090353f, -0.980785251f, 0.980785251f, 0.831469536f, -0.831469536f, -0.290284693f, 0.290284693f, -0.471396863f, 0.471396863f, -0.995184720f, 0.995184720f, 0.634393334f, -0.634393334f, -0.773010492f, 0.773010492f, 0.098017156f, -0.098017156f, -0.881921172f, 0.881921172f, 0.956940353f, -0.956940353f, }; ALIGN16_BEG const float ALIGN16_END cftmdl_wk1r[4] = { 0.707106769f, 0.707106769f, 0.707106769f, -0.707106769f, }; #endif } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_TABLES_NEON_SSE2_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/ooura/fft_size_256/0000775000175000017500000000000014475643423026510 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/ooura/fft_size_256/fft4g.cc0000664000175000017500000005606214475643423030042 0ustar00arunarun/* * http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html * Copyright Takuya OOURA, 1996-2001 * * You may use, copy, modify and distribute this code for any purpose (include * commercial use) and without fee. Please refer to this package when you modify * this code. * * Changes: * Trivial type modifications by the WebRTC authors. */ /* Fast Fourier/Cosine/Sine Transform dimension :one data length :power of 2 decimation :frequency radix :4, 2 data :inplace table :use functions cdft: Complex Discrete Fourier Transform rdft: Real Discrete Fourier Transform ddct: Discrete Cosine Transform ddst: Discrete Sine Transform dfct: Cosine Transform of RDFT (Real Symmetric DFT) dfst: Sine Transform of RDFT (Real Anti-symmetric DFT) function prototypes void cdft(int, int, float *, int *, float *); void rdft(size_t, int, float *, size_t *, float *); void ddct(int, int, float *, int *, float *); void ddst(int, int, float *, int *, float *); void dfct(int, float *, float *, int *, float *); void dfst(int, float *, float *, int *, float *); -------- Complex DFT (Discrete Fourier Transform) -------- [definition] X[k] = sum_j=0^n-1 x[j]*exp(2*pi*i*j*k/n), 0<=k X[k] = sum_j=0^n-1 x[j]*exp(-2*pi*i*j*k/n), 0<=k ip[0] = 0; // first time only cdft(2*n, 1, a, ip, w); ip[0] = 0; // first time only cdft(2*n, -1, a, ip, w); [parameters] 2*n :data length (int) n >= 1, n = power of 2 a[0...2*n-1] :input/output data (float *) input data a[2*j] = Re(x[j]), a[2*j+1] = Im(x[j]), 0<=j= 2+sqrt(n) strictly, length of ip >= 2+(1<<(int)(log(n+0.5)/log(2))/2). ip[0],ip[1] are pointers of the cos/sin table. w[0...n/2-1] :cos/sin table (float *) w[],ip[] are initialized if ip[0] == 0. [remark] Inverse of cdft(2*n, -1, a, ip, w); is cdft(2*n, 1, a, ip, w); for (j = 0; j <= 2 * n - 1; j++) { a[j] *= 1.0 / n; } . -------- Real DFT / Inverse of Real DFT -------- [definition] RDFT R[k] = sum_j=0^n-1 a[j]*cos(2*pi*j*k/n), 0<=k<=n/2 I[k] = sum_j=0^n-1 a[j]*sin(2*pi*j*k/n), 0 IRDFT (excluding scale) a[k] = (R[0] + R[n/2]*cos(pi*k))/2 + sum_j=1^n/2-1 R[j]*cos(2*pi*j*k/n) + sum_j=1^n/2-1 I[j]*sin(2*pi*j*k/n), 0<=k ip[0] = 0; // first time only rdft(n, 1, a, ip, w); ip[0] = 0; // first time only rdft(n, -1, a, ip, w); [parameters] n :data length (size_t) n >= 2, n = power of 2 a[0...n-1] :input/output data (float *) output data a[2*k] = R[k], 0<=k input data a[2*j] = R[j], 0<=j= 2+sqrt(n/2) strictly, length of ip >= 2+(1<<(int)(log(n/2+0.5)/log(2))/2). ip[0],ip[1] are pointers of the cos/sin table. w[0...n/2-1] :cos/sin table (float *) w[],ip[] are initialized if ip[0] == 0. [remark] Inverse of rdft(n, 1, a, ip, w); is rdft(n, -1, a, ip, w); for (j = 0; j <= n - 1; j++) { a[j] *= 2.0 / n; } . -------- DCT (Discrete Cosine Transform) / Inverse of DCT -------- [definition] IDCT (excluding scale) C[k] = sum_j=0^n-1 a[j]*cos(pi*j*(k+1/2)/n), 0<=k DCT C[k] = sum_j=0^n-1 a[j]*cos(pi*(j+1/2)*k/n), 0<=k ip[0] = 0; // first time only ddct(n, 1, a, ip, w); ip[0] = 0; // first time only ddct(n, -1, a, ip, w); [parameters] n :data length (int) n >= 2, n = power of 2 a[0...n-1] :input/output data (float *) output data a[k] = C[k], 0<=k= 2+sqrt(n/2) strictly, length of ip >= 2+(1<<(int)(log(n/2+0.5)/log(2))/2). ip[0],ip[1] are pointers of the cos/sin table. w[0...n*5/4-1] :cos/sin table (float *) w[],ip[] are initialized if ip[0] == 0. [remark] Inverse of ddct(n, -1, a, ip, w); is a[0] *= 0.5; ddct(n, 1, a, ip, w); for (j = 0; j <= n - 1; j++) { a[j] *= 2.0 / n; } . -------- DST (Discrete Sine Transform) / Inverse of DST -------- [definition] IDST (excluding scale) S[k] = sum_j=1^n A[j]*sin(pi*j*(k+1/2)/n), 0<=k DST S[k] = sum_j=0^n-1 a[j]*sin(pi*(j+1/2)*k/n), 0 ip[0] = 0; // first time only ddst(n, 1, a, ip, w); ip[0] = 0; // first time only ddst(n, -1, a, ip, w); [parameters] n :data length (int) n >= 2, n = power of 2 a[0...n-1] :input/output data (float *) input data a[j] = A[j], 0 output data a[k] = S[k], 0= 2+sqrt(n/2) strictly, length of ip >= 2+(1<<(int)(log(n/2+0.5)/log(2))/2). ip[0],ip[1] are pointers of the cos/sin table. w[0...n*5/4-1] :cos/sin table (float *) w[],ip[] are initialized if ip[0] == 0. [remark] Inverse of ddst(n, -1, a, ip, w); is a[0] *= 0.5; ddst(n, 1, a, ip, w); for (j = 0; j <= n - 1; j++) { a[j] *= 2.0 / n; } . -------- Cosine Transform of RDFT (Real Symmetric DFT) -------- [definition] C[k] = sum_j=0^n a[j]*cos(pi*j*k/n), 0<=k<=n [usage] ip[0] = 0; // first time only dfct(n, a, t, ip, w); [parameters] n :data length - 1 (int) n >= 2, n = power of 2 a[0...n] :input/output data (float *) output data a[k] = C[k], 0<=k<=n t[0...n/2] :work area (float *) ip[0...*] :work area for bit reversal (int *) length of ip >= 2+sqrt(n/4) strictly, length of ip >= 2+(1<<(int)(log(n/4+0.5)/log(2))/2). ip[0],ip[1] are pointers of the cos/sin table. w[0...n*5/8-1] :cos/sin table (float *) w[],ip[] are initialized if ip[0] == 0. [remark] Inverse of a[0] *= 0.5; a[n] *= 0.5; dfct(n, a, t, ip, w); is a[0] *= 0.5; a[n] *= 0.5; dfct(n, a, t, ip, w); for (j = 0; j <= n; j++) { a[j] *= 2.0 / n; } . -------- Sine Transform of RDFT (Real Anti-symmetric DFT) -------- [definition] S[k] = sum_j=1^n-1 a[j]*sin(pi*j*k/n), 0= 2, n = power of 2 a[0...n-1] :input/output data (float *) output data a[k] = S[k], 0= 2+sqrt(n/4) strictly, length of ip >= 2+(1<<(int)(log(n/4+0.5)/log(2))/2). ip[0],ip[1] are pointers of the cos/sin table. w[0...n*5/8-1] :cos/sin table (float *) w[],ip[] are initialized if ip[0] == 0. [remark] Inverse of dfst(n, a, t, ip, w); is dfst(n, a, t, ip, w); for (j = 1; j <= n - 1; j++) { a[j] *= 2.0 / n; } . Appendix : The cos/sin table is recalculated when the larger table required. w[] and ip[] are compatible with all routines. */ #include #include #include "common_audio/third_party/ooura/fft_size_256/fft4g.h" namespace webrtc { namespace { void makewt(size_t nw, size_t* ip, float* w); void makect(size_t nc, size_t* ip, float* c); void bitrv2(size_t n, size_t* ip, float* a); void cftfsub(size_t n, float* a, float* w); void cftbsub(size_t n, float* a, float* w); void cft1st(size_t n, float* a, float* w); void cftmdl(size_t n, size_t l, float* a, float* w); void rftfsub(size_t n, float* a, size_t nc, float* c); void rftbsub(size_t n, float* a, size_t nc, float* c); /* -------- initializing routines -------- */ void makewt(size_t nw, size_t* ip, float* w) { size_t j, nwh; float delta, x, y; ip[0] = nw; ip[1] = 1; if (nw > 2) { nwh = nw >> 1; delta = atanf(1.0f) / nwh; w[0] = 1; w[1] = 0; w[nwh] = (float)cos(delta * nwh); w[nwh + 1] = w[nwh]; if (nwh > 2) { for (j = 2; j < nwh; j += 2) { x = (float)cos(delta * j); y = (float)sin(delta * j); w[j] = x; w[j + 1] = y; w[nw - j] = y; w[nw - j + 1] = x; } bitrv2(nw, ip + 2, w); } } } void makect(size_t nc, size_t* ip, float* c) { size_t j, nch; float delta; ip[1] = nc; if (nc > 1) { nch = nc >> 1; delta = atanf(1.0f) / nch; c[0] = (float)cos(delta * nch); c[nch] = 0.5f * c[0]; for (j = 1; j < nch; j++) { c[j] = 0.5f * (float)cos(delta * j); c[nc - j] = 0.5f * (float)sin(delta * j); } } } /* -------- child routines -------- */ void bitrv2(size_t n, size_t* ip, float* a) { size_t j, j1, k, k1, l, m, m2; float xr, xi, yr, yi; ip[0] = 0; l = n; m = 1; while ((m << 3) < l) { l >>= 1; for (j = 0; j < m; j++) { ip[m + j] = ip[j] + l; } m <<= 1; } m2 = 2 * m; if ((m << 3) == l) { for (k = 0; k < m; k++) { for (j = 0; j < k; j++) { j1 = 2 * j + ip[k]; k1 = 2 * k + ip[j]; xr = a[j1]; xi = a[j1 + 1]; yr = a[k1]; yi = a[k1 + 1]; a[j1] = yr; a[j1 + 1] = yi; a[k1] = xr; a[k1 + 1] = xi; j1 += m2; k1 += 2 * m2; xr = a[j1]; xi = a[j1 + 1]; yr = a[k1]; yi = a[k1 + 1]; a[j1] = yr; a[j1 + 1] = yi; a[k1] = xr; a[k1 + 1] = xi; j1 += m2; k1 -= m2; xr = a[j1]; xi = a[j1 + 1]; yr = a[k1]; yi = a[k1 + 1]; a[j1] = yr; a[j1 + 1] = yi; a[k1] = xr; a[k1 + 1] = xi; j1 += m2; k1 += 2 * m2; xr = a[j1]; xi = a[j1 + 1]; yr = a[k1]; yi = a[k1 + 1]; a[j1] = yr; a[j1 + 1] = yi; a[k1] = xr; a[k1 + 1] = xi; } j1 = 2 * k + m2 + ip[k]; k1 = j1 + m2; xr = a[j1]; xi = a[j1 + 1]; yr = a[k1]; yi = a[k1 + 1]; a[j1] = yr; a[j1 + 1] = yi; a[k1] = xr; a[k1 + 1] = xi; } } else { for (k = 1; k < m; k++) { for (j = 0; j < k; j++) { j1 = 2 * j + ip[k]; k1 = 2 * k + ip[j]; xr = a[j1]; xi = a[j1 + 1]; yr = a[k1]; yi = a[k1 + 1]; a[j1] = yr; a[j1 + 1] = yi; a[k1] = xr; a[k1 + 1] = xi; j1 += m2; k1 += m2; xr = a[j1]; xi = a[j1 + 1]; yr = a[k1]; yi = a[k1 + 1]; a[j1] = yr; a[j1 + 1] = yi; a[k1] = xr; a[k1 + 1] = xi; } } } } void cftfsub(size_t n, float* a, float* w) { size_t j, j1, j2, j3, l; float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; l = 2; if (n > 8) { cft1st(n, a, w); l = 8; while ((l << 2) < n) { cftmdl(n, l, a, w); l <<= 2; } } if ((l << 2) == n) { for (j = 0; j < l; j += 2) { j1 = j + l; j2 = j1 + l; j3 = j2 + l; x0r = a[j] + a[j1]; x0i = a[j + 1] + a[j1 + 1]; x1r = a[j] - a[j1]; x1i = a[j + 1] - a[j1 + 1]; x2r = a[j2] + a[j3]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2] - a[j3]; x3i = a[j2 + 1] - a[j3 + 1]; a[j] = x0r + x2r; a[j + 1] = x0i + x2i; a[j2] = x0r - x2r; a[j2 + 1] = x0i - x2i; a[j1] = x1r - x3i; a[j1 + 1] = x1i + x3r; a[j3] = x1r + x3i; a[j3 + 1] = x1i - x3r; } } else { for (j = 0; j < l; j += 2) { j1 = j + l; x0r = a[j] - a[j1]; x0i = a[j + 1] - a[j1 + 1]; a[j] += a[j1]; a[j + 1] += a[j1 + 1]; a[j1] = x0r; a[j1 + 1] = x0i; } } } void cftbsub(size_t n, float* a, float* w) { size_t j, j1, j2, j3, l; float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; l = 2; if (n > 8) { cft1st(n, a, w); l = 8; while ((l << 2) < n) { cftmdl(n, l, a, w); l <<= 2; } } if ((l << 2) == n) { for (j = 0; j < l; j += 2) { j1 = j + l; j2 = j1 + l; j3 = j2 + l; x0r = a[j] + a[j1]; x0i = -a[j + 1] - a[j1 + 1]; x1r = a[j] - a[j1]; x1i = -a[j + 1] + a[j1 + 1]; x2r = a[j2] + a[j3]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2] - a[j3]; x3i = a[j2 + 1] - a[j3 + 1]; a[j] = x0r + x2r; a[j + 1] = x0i - x2i; a[j2] = x0r - x2r; a[j2 + 1] = x0i + x2i; a[j1] = x1r - x3i; a[j1 + 1] = x1i - x3r; a[j3] = x1r + x3i; a[j3 + 1] = x1i + x3r; } } else { for (j = 0; j < l; j += 2) { j1 = j + l; x0r = a[j] - a[j1]; x0i = -a[j + 1] + a[j1 + 1]; a[j] += a[j1]; a[j + 1] = -a[j + 1] - a[j1 + 1]; a[j1] = x0r; a[j1 + 1] = x0i; } } } void cft1st(size_t n, float* a, float* w) { size_t j, k1, k2; float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; x0r = a[0] + a[2]; x0i = a[1] + a[3]; x1r = a[0] - a[2]; x1i = a[1] - a[3]; x2r = a[4] + a[6]; x2i = a[5] + a[7]; x3r = a[4] - a[6]; x3i = a[5] - a[7]; a[0] = x0r + x2r; a[1] = x0i + x2i; a[4] = x0r - x2r; a[5] = x0i - x2i; a[2] = x1r - x3i; a[3] = x1i + x3r; a[6] = x1r + x3i; a[7] = x1i - x3r; wk1r = w[2]; x0r = a[8] + a[10]; x0i = a[9] + a[11]; x1r = a[8] - a[10]; x1i = a[9] - a[11]; x2r = a[12] + a[14]; x2i = a[13] + a[15]; x3r = a[12] - a[14]; x3i = a[13] - a[15]; a[8] = x0r + x2r; a[9] = x0i + x2i; a[12] = x2i - x0i; a[13] = x0r - x2r; x0r = x1r - x3i; x0i = x1i + x3r; a[10] = wk1r * (x0r - x0i); a[11] = wk1r * (x0r + x0i); x0r = x3i + x1r; x0i = x3r - x1i; a[14] = wk1r * (x0i - x0r); a[15] = wk1r * (x0i + x0r); k1 = 0; for (j = 16; j < n; j += 16) { k1 += 2; k2 = 2 * k1; wk2r = w[k1]; wk2i = w[k1 + 1]; wk1r = w[k2]; wk1i = w[k2 + 1]; wk3r = wk1r - 2 * wk2i * wk1i; wk3i = 2 * wk2i * wk1r - wk1i; x0r = a[j] + a[j + 2]; x0i = a[j + 1] + a[j + 3]; x1r = a[j] - a[j + 2]; x1i = a[j + 1] - a[j + 3]; x2r = a[j + 4] + a[j + 6]; x2i = a[j + 5] + a[j + 7]; x3r = a[j + 4] - a[j + 6]; x3i = a[j + 5] - a[j + 7]; a[j] = x0r + x2r; a[j + 1] = x0i + x2i; x0r -= x2r; x0i -= x2i; a[j + 4] = wk2r * x0r - wk2i * x0i; a[j + 5] = wk2r * x0i + wk2i * x0r; x0r = x1r - x3i; x0i = x1i + x3r; a[j + 2] = wk1r * x0r - wk1i * x0i; a[j + 3] = wk1r * x0i + wk1i * x0r; x0r = x1r + x3i; x0i = x1i - x3r; a[j + 6] = wk3r * x0r - wk3i * x0i; a[j + 7] = wk3r * x0i + wk3i * x0r; wk1r = w[k2 + 2]; wk1i = w[k2 + 3]; wk3r = wk1r - 2 * wk2r * wk1i; wk3i = 2 * wk2r * wk1r - wk1i; x0r = a[j + 8] + a[j + 10]; x0i = a[j + 9] + a[j + 11]; x1r = a[j + 8] - a[j + 10]; x1i = a[j + 9] - a[j + 11]; x2r = a[j + 12] + a[j + 14]; x2i = a[j + 13] + a[j + 15]; x3r = a[j + 12] - a[j + 14]; x3i = a[j + 13] - a[j + 15]; a[j + 8] = x0r + x2r; a[j + 9] = x0i + x2i; x0r -= x2r; x0i -= x2i; a[j + 12] = -wk2i * x0r - wk2r * x0i; a[j + 13] = -wk2i * x0i + wk2r * x0r; x0r = x1r - x3i; x0i = x1i + x3r; a[j + 10] = wk1r * x0r - wk1i * x0i; a[j + 11] = wk1r * x0i + wk1i * x0r; x0r = x1r + x3i; x0i = x1i - x3r; a[j + 14] = wk3r * x0r - wk3i * x0i; a[j + 15] = wk3r * x0i + wk3i * x0r; } } void cftmdl(size_t n, size_t l, float* a, float* w) { size_t j, j1, j2, j3, k, k1, k2, m, m2; float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; m = l << 2; for (j = 0; j < l; j += 2) { j1 = j + l; j2 = j1 + l; j3 = j2 + l; x0r = a[j] + a[j1]; x0i = a[j + 1] + a[j1 + 1]; x1r = a[j] - a[j1]; x1i = a[j + 1] - a[j1 + 1]; x2r = a[j2] + a[j3]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2] - a[j3]; x3i = a[j2 + 1] - a[j3 + 1]; a[j] = x0r + x2r; a[j + 1] = x0i + x2i; a[j2] = x0r - x2r; a[j2 + 1] = x0i - x2i; a[j1] = x1r - x3i; a[j1 + 1] = x1i + x3r; a[j3] = x1r + x3i; a[j3 + 1] = x1i - x3r; } wk1r = w[2]; for (j = m; j < l + m; j += 2) { j1 = j + l; j2 = j1 + l; j3 = j2 + l; x0r = a[j] + a[j1]; x0i = a[j + 1] + a[j1 + 1]; x1r = a[j] - a[j1]; x1i = a[j + 1] - a[j1 + 1]; x2r = a[j2] + a[j3]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2] - a[j3]; x3i = a[j2 + 1] - a[j3 + 1]; a[j] = x0r + x2r; a[j + 1] = x0i + x2i; a[j2] = x2i - x0i; a[j2 + 1] = x0r - x2r; x0r = x1r - x3i; x0i = x1i + x3r; a[j1] = wk1r * (x0r - x0i); a[j1 + 1] = wk1r * (x0r + x0i); x0r = x3i + x1r; x0i = x3r - x1i; a[j3] = wk1r * (x0i - x0r); a[j3 + 1] = wk1r * (x0i + x0r); } k1 = 0; m2 = 2 * m; for (k = m2; k < n; k += m2) { k1 += 2; k2 = 2 * k1; wk2r = w[k1]; wk2i = w[k1 + 1]; wk1r = w[k2]; wk1i = w[k2 + 1]; wk3r = wk1r - 2 * wk2i * wk1i; wk3i = 2 * wk2i * wk1r - wk1i; for (j = k; j < l + k; j += 2) { j1 = j + l; j2 = j1 + l; j3 = j2 + l; x0r = a[j] + a[j1]; x0i = a[j + 1] + a[j1 + 1]; x1r = a[j] - a[j1]; x1i = a[j + 1] - a[j1 + 1]; x2r = a[j2] + a[j3]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2] - a[j3]; x3i = a[j2 + 1] - a[j3 + 1]; a[j] = x0r + x2r; a[j + 1] = x0i + x2i; x0r -= x2r; x0i -= x2i; a[j2] = wk2r * x0r - wk2i * x0i; a[j2 + 1] = wk2r * x0i + wk2i * x0r; x0r = x1r - x3i; x0i = x1i + x3r; a[j1] = wk1r * x0r - wk1i * x0i; a[j1 + 1] = wk1r * x0i + wk1i * x0r; x0r = x1r + x3i; x0i = x1i - x3r; a[j3] = wk3r * x0r - wk3i * x0i; a[j3 + 1] = wk3r * x0i + wk3i * x0r; } wk1r = w[k2 + 2]; wk1i = w[k2 + 3]; wk3r = wk1r - 2 * wk2r * wk1i; wk3i = 2 * wk2r * wk1r - wk1i; for (j = k + m; j < l + (k + m); j += 2) { j1 = j + l; j2 = j1 + l; j3 = j2 + l; x0r = a[j] + a[j1]; x0i = a[j + 1] + a[j1 + 1]; x1r = a[j] - a[j1]; x1i = a[j + 1] - a[j1 + 1]; x2r = a[j2] + a[j3]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2] - a[j3]; x3i = a[j2 + 1] - a[j3 + 1]; a[j] = x0r + x2r; a[j + 1] = x0i + x2i; x0r -= x2r; x0i -= x2i; a[j2] = -wk2i * x0r - wk2r * x0i; a[j2 + 1] = -wk2i * x0i + wk2r * x0r; x0r = x1r - x3i; x0i = x1i + x3r; a[j1] = wk1r * x0r - wk1i * x0i; a[j1 + 1] = wk1r * x0i + wk1i * x0r; x0r = x1r + x3i; x0i = x1i - x3r; a[j3] = wk3r * x0r - wk3i * x0i; a[j3 + 1] = wk3r * x0i + wk3i * x0r; } } } void rftfsub(size_t n, float* a, size_t nc, float* c) { size_t j, k, kk, ks, m; float wkr, wki, xr, xi, yr, yi; m = n >> 1; ks = 2 * nc / m; kk = 0; for (j = 2; j < m; j += 2) { k = n - j; kk += ks; wkr = 0.5f - c[nc - kk]; wki = c[kk]; xr = a[j] - a[k]; xi = a[j + 1] + a[k + 1]; yr = wkr * xr - wki * xi; yi = wkr * xi + wki * xr; a[j] -= yr; a[j + 1] -= yi; a[k] += yr; a[k + 1] -= yi; } } void rftbsub(size_t n, float* a, size_t nc, float* c) { size_t j, k, kk, ks, m; float wkr, wki, xr, xi, yr, yi; a[1] = -a[1]; m = n >> 1; ks = 2 * nc / m; kk = 0; for (j = 2; j < m; j += 2) { k = n - j; kk += ks; wkr = 0.5f - c[nc - kk]; wki = c[kk]; xr = a[j] - a[k]; xi = a[j + 1] + a[k + 1]; yr = wkr * xr + wki * xi; yi = wkr * xi - wki * xr; a[j] -= yr; a[j + 1] = yi - a[j + 1]; a[k] += yr; a[k + 1] = yi - a[k + 1]; } a[m + 1] = -a[m + 1]; } } // namespace void WebRtc_rdft(size_t n, int isgn, float* a, size_t* ip, float* w) { size_t nw, nc; float xi; nw = ip[0]; if (n > (nw << 2)) { nw = n >> 2; makewt(nw, ip, w); } nc = ip[1]; if (n > (nc << 2)) { nc = n >> 2; makect(nc, ip, w + nw); } if (isgn >= 0) { if (n > 4) { bitrv2(n, ip + 2, a); cftfsub(n, a, w); rftfsub(n, a, nc, w + nw); } else if (n == 4) { cftfsub(n, a, w); } xi = a[0] - a[1]; a[0] += a[1]; a[1] = xi; } else { a[1] = 0.5f * (a[0] - a[1]); a[0] -= a[1]; if (n > 4) { rftbsub(n, a, nc, w + nw); bitrv2(n, ip + 2, a); cftbsub(n, a, w); } else if (n == 4) { cftfsub(n, a, w); } } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/ooura/fft_size_256/fft4g.h0000664000175000017500000000137414475643423027700 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the ../../../LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_THIRD_PARTY_OOURA_FFT_SIZE_256_FFT4G_H_ #define COMMON_AUDIO_THIRD_PARTY_OOURA_FFT_SIZE_256_FFT4G_H_ namespace webrtc { // Refer to fft4g.c for documentation. void WebRtc_rdft(size_t n, int isgn, float* a, size_t* ip, float* w); } // namespace webrtc #endif // COMMON_AUDIO_THIRD_PARTY_OOURA_FFT_SIZE_256_FFT4G_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/spl_sqrt_floor/0000775000175000017500000000000014475643423026226 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/spl_sqrt_floor/BUILD.gn0000664000175000017500000000146514475643423027421 0ustar00arunarun# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the ../../../LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../../../webrtc.gni") rtc_library("spl_sqrt_floor") { visibility = [ "../..:common_audio_c" ] sources = [ "spl_sqrt_floor.h" ] deps = [] if (current_cpu == "arm") { sources += [ "spl_sqrt_floor_arm.S" ] deps += [ "../../../rtc_base/system:asm_defines" ] } else if (current_cpu == "mipsel") { sources += [ "spl_sqrt_floor_mips.c" ] } else { sources += [ "spl_sqrt_floor.c" ] } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/spl_sqrt_floor/LICENSE0000664000175000017500000000162314475643423027235 0ustar00arunarun/* * Written by Wilco Dijkstra, 1996. The following email exchange establishes the * license. * * From: Wilco Dijkstra * Date: Fri, Jun 24, 2011 at 3:20 AM * Subject: Re: sqrt routine * To: Kevin Ma * Hi Kevin, * Thanks for asking. Those routines are public domain (originally posted to * comp.sys.arm a long time ago), so you can use them freely for any purpose. * Cheers, * Wilco * * ----- Original Message ----- * From: "Kevin Ma" * To: * Sent: Thursday, June 23, 2011 11:44 PM * Subject: Fwd: sqrt routine * Hi Wilco, * I saw your sqrt routine from several web sites, including * http://www.finesse.demon.co.uk/steven/sqrt.html. * Just wonder if there's any copyright information with your Successive * approximation routines, or if I can freely use it for any purpose. * Thanks. * Kevin */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c0000664000175000017500000000455614475643423031454 0ustar00arunarun/* * Written by Wilco Dijkstra, 1996. The following email exchange establishes the * license. * * From: Wilco Dijkstra * Date: Fri, Jun 24, 2011 at 3:20 AM * Subject: Re: sqrt routine * To: Kevin Ma * Hi Kevin, * Thanks for asking. Those routines are public domain (originally posted to * comp.sys.arm a long time ago), so you can use them freely for any purpose. * Cheers, * Wilco * * ----- Original Message ----- * From: "Kevin Ma" * To: * Sent: Thursday, June 23, 2011 11:44 PM * Subject: Fwd: sqrt routine * Hi Wilco, * I saw your sqrt routine from several web sites, including * http://www.finesse.demon.co.uk/steven/sqrt.html. * Just wonder if there's any copyright information with your Successive * approximation routines, or if I can freely use it for any purpose. * Thanks. * Kevin */ // Minor modifications in code style for WebRTC, 2012. #include "common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h" /* * Algorithm: * Successive approximation of the equation (root + delta) ^ 2 = N * until delta < 1. If delta < 1 we have the integer part of SQRT (N). * Use delta = 2^i for i = 15 .. 0. * * Output precision is 16 bits. Note for large input values (close to * 0x7FFFFFFF), bit 15 (the highest bit of the low 16-bit half word) * contains the MSB information (a non-sign value). Do with caution * if you need to cast the output to int16_t type. * * If the input value is negative, it returns 0. */ #define WEBRTC_SPL_SQRT_ITER(N) \ try1 = root + (1 << (N)); \ if (value >= try1 << (N)) \ { \ value -= try1 << (N); \ root |= 2 << (N); \ } int32_t WebRtcSpl_SqrtFloor(int32_t value) { int32_t root = 0, try1; WEBRTC_SPL_SQRT_ITER (15); WEBRTC_SPL_SQRT_ITER (14); WEBRTC_SPL_SQRT_ITER (13); WEBRTC_SPL_SQRT_ITER (12); WEBRTC_SPL_SQRT_ITER (11); WEBRTC_SPL_SQRT_ITER (10); WEBRTC_SPL_SQRT_ITER ( 9); WEBRTC_SPL_SQRT_ITER ( 8); WEBRTC_SPL_SQRT_ITER ( 7); WEBRTC_SPL_SQRT_ITER ( 6); WEBRTC_SPL_SQRT_ITER ( 5); WEBRTC_SPL_SQRT_ITER ( 4); WEBRTC_SPL_SQRT_ITER ( 3); WEBRTC_SPL_SQRT_ITER ( 2); WEBRTC_SPL_SQRT_ITER ( 1); WEBRTC_SPL_SQRT_ITER ( 0); return root >> 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h0000664000175000017500000000160714475643423031453 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include // // WebRtcSpl_SqrtFloor(...) // // Returns the square root of the input value |value|. The precision of this // function is rounding down integer precision, i.e., sqrt(8) gives 2 as answer. // If |value| is a negative number then 0 is returned. // // Algorithm: // // An iterative 4 cylce/bit routine // // Input: // - value : Value to calculate sqrt of // // Return value : Result of the sqrt calculation // int32_t WebRtcSpl_SqrtFloor(int32_t value); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_arm.S0000664000175000017500000000546114475643423032267 0ustar00arunarun@ @ Written by Wilco Dijkstra, 1996. The following email exchange establishes the @ license. @ @ From: Wilco Dijkstra @ Date: Fri, Jun 24, 2011 at 3:20 AM @ Subject: Re: sqrt routine @ To: Kevin Ma @ Hi Kevin, @ Thanks for asking. Those routines are public domain (originally posted to @ comp.sys.arm a long time ago), so you can use them freely for any purpose. @ Cheers, @ Wilco @ @ ----- Original Message ----- @ From: "Kevin Ma" @ To: @ Sent: Thursday, June 23, 2011 11:44 PM @ Subject: Fwd: sqrt routine @ Hi Wilco, @ I saw your sqrt routine from several web sites, including @ http://www.finesse.demon.co.uk/steven/sqrt.html. @ Just wonder if there's any copyright information with your Successive @ approximation routines, or if I can freely use it for any purpose. @ Thanks. @ Kevin @ Minor modifications in code style for WebRTC, 2012. @ Output is bit-exact with the reference C code in spl_sqrt_floor.c. @ Input : r0 32 bit unsigned integer @ Output: r0 = INT (SQRT (r0)), precision is 16 bits @ Registers touched: r1, r2 #include "rtc_base/system/asm_defines.h" GLOBAL_FUNCTION WebRtcSpl_SqrtFloor .align 2 DEFINE_FUNCTION WebRtcSpl_SqrtFloor mov r1, #3 << 30 mov r2, #1 << 30 @ unroll for i = 0 .. 15 cmp r0, r2, ror #2 * 0 subhs r0, r0, r2, ror #2 * 0 adc r2, r1, r2, lsl #1 cmp r0, r2, ror #2 * 1 subhs r0, r0, r2, ror #2 * 1 adc r2, r1, r2, lsl #1 cmp r0, r2, ror #2 * 2 subhs r0, r0, r2, ror #2 * 2 adc r2, r1, r2, lsl #1 cmp r0, r2, ror #2 * 3 subhs r0, r0, r2, ror #2 * 3 adc r2, r1, r2, lsl #1 cmp r0, r2, ror #2 * 4 subhs r0, r0, r2, ror #2 * 4 adc r2, r1, r2, lsl #1 cmp r0, r2, ror #2 * 5 subhs r0, r0, r2, ror #2 * 5 adc r2, r1, r2, lsl #1 cmp r0, r2, ror #2 * 6 subhs r0, r0, r2, ror #2 * 6 adc r2, r1, r2, lsl #1 cmp r0, r2, ror #2 * 7 subhs r0, r0, r2, ror #2 * 7 adc r2, r1, r2, lsl #1 cmp r0, r2, ror #2 * 8 subhs r0, r0, r2, ror #2 * 8 adc r2, r1, r2, lsl #1 cmp r0, r2, ror #2 * 9 subhs r0, r0, r2, ror #2 * 9 adc r2, r1, r2, lsl #1 cmp r0, r2, ror #2 * 10 subhs r0, r0, r2, ror #2 * 10 adc r2, r1, r2, lsl #1 cmp r0, r2, ror #2 * 11 subhs r0, r0, r2, ror #2 * 11 adc r2, r1, r2, lsl #1 cmp r0, r2, ror #2 * 12 subhs r0, r0, r2, ror #2 * 12 adc r2, r1, r2, lsl #1 cmp r0, r2, ror #2 * 13 subhs r0, r0, r2, ror #2 * 13 adc r2, r1, r2, lsl #1 cmp r0, r2, ror #2 * 14 subhs r0, r0, r2, ror #2 * 14 adc r2, r1, r2, lsl #1 cmp r0, r2, ror #2 * 15 subhs r0, r0, r2, ror #2 * 15 adc r2, r1, r2, lsl #1 bic r0, r2, #3 << 30 @ for rounding add: cmp r0, r2 adc r2, #1 bx lr ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_mips.c0000664000175000017500000002265214475643423032501 0ustar00arunarun/* * Written by Wilco Dijkstra, 1996. The following email exchange establishes the * license. * * From: Wilco Dijkstra * Date: Fri, Jun 24, 2011 at 3:20 AM * Subject: Re: sqrt routine * To: Kevin Ma * Hi Kevin, * Thanks for asking. Those routines are public domain (originally posted to * comp.sys.arm a long time ago), so you can use them freely for any purpose. * Cheers, * Wilco * * ----- Original Message ----- * From: "Kevin Ma" * To: * Sent: Thursday, June 23, 2011 11:44 PM * Subject: Fwd: sqrt routine * Hi Wilco, * I saw your sqrt routine from several web sites, including * http://www.finesse.demon.co.uk/steven/sqrt.html. * Just wonder if there's any copyright information with your Successive * approximation routines, or if I can freely use it for any purpose. * Thanks. * Kevin */ // Minor modifications in code style for WebRTC, 2012. // Code optimizations for MIPS, 2013. #include "common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h" /* * Algorithm: * Successive approximation of the equation (root + delta) ^ 2 = N * until delta < 1. If delta < 1 we have the integer part of SQRT (N). * Use delta = 2^i for i = 15 .. 0. * * Output precision is 16 bits. Note for large input values (close to * 0x7FFFFFFF), bit 15 (the highest bit of the low 16-bit half word) * contains the MSB information (a non-sign value). Do with caution * if you need to cast the output to int16_t type. * * If the input value is negative, it returns 0. */ int32_t WebRtcSpl_SqrtFloor(int32_t value) { int32_t root = 0, tmp1, tmp2, tmp3, tmp4; __asm __volatile( ".set push \n\t" ".set noreorder \n\t" "lui %[tmp1], 0x4000 \n\t" "slt %[tmp2], %[value], %[tmp1] \n\t" "sub %[tmp3], %[value], %[tmp1] \n\t" "lui %[tmp1], 0x1 \n\t" "or %[tmp4], %[root], %[tmp1] \n\t" "movz %[value], %[tmp3], %[tmp2] \n\t" "movz %[root], %[tmp4], %[tmp2] \n\t" "addiu %[tmp1], $0, 0x4000 \n\t" "addu %[tmp1], %[tmp1], %[root] \n\t" "sll %[tmp1], 14 \n\t" "slt %[tmp2], %[value], %[tmp1] \n\t" "subu %[tmp3], %[value], %[tmp1] \n\t" "ori %[tmp4], %[root], 0x8000 \n\t" "movz %[value], %[tmp3], %[tmp2] \n\t" "movz %[root], %[tmp4], %[tmp2] \n\t" "addiu %[tmp1], $0, 0x2000 \n\t" "addu %[tmp1], %[tmp1], %[root] \n\t" "sll %[tmp1], 13 \n\t" "slt %[tmp2], %[value], %[tmp1] \n\t" "subu %[tmp3], %[value], %[tmp1] \n\t" "ori %[tmp4], %[root], 0x4000 \n\t" "movz %[value], %[tmp3], %[tmp2] \n\t" "movz %[root], %[tmp4], %[tmp2] \n\t" "addiu %[tmp1], $0, 0x1000 \n\t" "addu %[tmp1], %[tmp1], %[root] \n\t" "sll %[tmp1], 12 \n\t" "slt %[tmp2], %[value], %[tmp1] \n\t" "subu %[tmp3], %[value], %[tmp1] \n\t" "ori %[tmp4], %[root], 0x2000 \n\t" "movz %[value], %[tmp3], %[tmp2] \n\t" "movz %[root], %[tmp4], %[tmp2] \n\t" "addiu %[tmp1], $0, 0x800 \n\t" "addu %[tmp1], %[tmp1], %[root] \n\t" "sll %[tmp1], 11 \n\t" "slt %[tmp2], %[value], %[tmp1] \n\t" "subu %[tmp3], %[value], %[tmp1] \n\t" "ori %[tmp4], %[root], 0x1000 \n\t" "movz %[value], %[tmp3], %[tmp2] \n\t" "movz %[root], %[tmp4], %[tmp2] \n\t" "addiu %[tmp1], $0, 0x400 \n\t" "addu %[tmp1], %[tmp1], %[root] \n\t" "sll %[tmp1], 10 \n\t" "slt %[tmp2], %[value], %[tmp1] \n\t" "subu %[tmp3], %[value], %[tmp1] \n\t" "ori %[tmp4], %[root], 0x800 \n\t" "movz %[value], %[tmp3], %[tmp2] \n\t" "movz %[root], %[tmp4], %[tmp2] \n\t" "addiu %[tmp1], $0, 0x200 \n\t" "addu %[tmp1], %[tmp1], %[root] \n\t" "sll %[tmp1], 9 \n\t" "slt %[tmp2], %[value], %[tmp1] \n\t" "subu %[tmp3], %[value], %[tmp1] \n\t" "ori %[tmp4], %[root], 0x400 \n\t" "movz %[value], %[tmp3], %[tmp2] \n\t" "movz %[root], %[tmp4], %[tmp2] \n\t" "addiu %[tmp1], $0, 0x100 \n\t" "addu %[tmp1], %[tmp1], %[root] \n\t" "sll %[tmp1], 8 \n\t" "slt %[tmp2], %[value], %[tmp1] \n\t" "subu %[tmp3], %[value], %[tmp1] \n\t" "ori %[tmp4], %[root], 0x200 \n\t" "movz %[value], %[tmp3], %[tmp2] \n\t" "movz %[root], %[tmp4], %[tmp2] \n\t" "addiu %[tmp1], $0, 0x80 \n\t" "addu %[tmp1], %[tmp1], %[root] \n\t" "sll %[tmp1], 7 \n\t" "slt %[tmp2], %[value], %[tmp1] \n\t" "subu %[tmp3], %[value], %[tmp1] \n\t" "ori %[tmp4], %[root], 0x100 \n\t" "movz %[value], %[tmp3], %[tmp2] \n\t" "movz %[root], %[tmp4], %[tmp2] \n\t" "addiu %[tmp1], $0, 0x40 \n\t" "addu %[tmp1], %[tmp1], %[root] \n\t" "sll %[tmp1], 6 \n\t" "slt %[tmp2], %[value], %[tmp1] \n\t" "subu %[tmp3], %[value], %[tmp1] \n\t" "ori %[tmp4], %[root], 0x80 \n\t" "movz %[value], %[tmp3], %[tmp2] \n\t" "movz %[root], %[tmp4], %[tmp2] \n\t" "addiu %[tmp1], $0, 0x20 \n\t" "addu %[tmp1], %[tmp1], %[root] \n\t" "sll %[tmp1], 5 \n\t" "slt %[tmp2], %[value], %[tmp1] \n\t" "subu %[tmp3], %[value], %[tmp1] \n\t" "ori %[tmp4], %[root], 0x40 \n\t" "movz %[value], %[tmp3], %[tmp2] \n\t" "movz %[root], %[tmp4], %[tmp2] \n\t" "addiu %[tmp1], $0, 0x10 \n\t" "addu %[tmp1], %[tmp1], %[root] \n\t" "sll %[tmp1], 4 \n\t" "slt %[tmp2], %[value], %[tmp1] \n\t" "subu %[tmp3], %[value], %[tmp1] \n\t" "ori %[tmp4], %[root], 0x20 \n\t" "movz %[value], %[tmp3], %[tmp2] \n\t" "movz %[root], %[tmp4], %[tmp2] \n\t" "addiu %[tmp1], $0, 0x8 \n\t" "addu %[tmp1], %[tmp1], %[root] \n\t" "sll %[tmp1], 3 \n\t" "slt %[tmp2], %[value], %[tmp1] \n\t" "subu %[tmp3], %[value], %[tmp1] \n\t" "ori %[tmp4], %[root], 0x10 \n\t" "movz %[value], %[tmp3], %[tmp2] \n\t" "movz %[root], %[tmp4], %[tmp2] \n\t" "addiu %[tmp1], $0, 0x4 \n\t" "addu %[tmp1], %[tmp1], %[root] \n\t" "sll %[tmp1], 2 \n\t" "slt %[tmp2], %[value], %[tmp1] \n\t" "subu %[tmp3], %[value], %[tmp1] \n\t" "ori %[tmp4], %[root], 0x8 \n\t" "movz %[value], %[tmp3], %[tmp2] \n\t" "movz %[root], %[tmp4], %[tmp2] \n\t" "addiu %[tmp1], $0, 0x2 \n\t" "addu %[tmp1], %[tmp1], %[root] \n\t" "sll %[tmp1], 1 \n\t" "slt %[tmp2], %[value], %[tmp1] \n\t" "subu %[tmp3], %[value], %[tmp1] \n\t" "ori %[tmp4], %[root], 0x4 \n\t" "movz %[value], %[tmp3], %[tmp2] \n\t" "movz %[root], %[tmp4], %[tmp2] \n\t" "addiu %[tmp1], $0, 0x1 \n\t" "addu %[tmp1], %[tmp1], %[root] \n\t" "slt %[tmp2], %[value], %[tmp1] \n\t" "ori %[tmp4], %[root], 0x2 \n\t" "movz %[root], %[tmp4], %[tmp2] \n\t" ".set pop \n\t" : [root] "+r" (root), [value] "+r" (value), [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3), [tmp4] "=&r" (tmp4) : ); return root >> 1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/vad/0000775000175000017500000000000014475643423021377 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/vad/include/0000775000175000017500000000000014475643423023022 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/vad/include/vad.h0000664000175000017500000000267314475643423023755 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_VAD_INCLUDE_VAD_H_ #define COMMON_AUDIO_VAD_INCLUDE_VAD_H_ #include #include "common_audio/vad/include/webrtc_vad.h" #include "rtc_base/checks.h" namespace webrtc { class Vad { public: enum Aggressiveness { kVadNormal = 0, kVadLowBitrate = 1, kVadAggressive = 2, kVadVeryAggressive = 3 }; enum Activity { kPassive = 0, kActive = 1, kError = -1 }; virtual ~Vad() = default; // Calculates a VAD decision for the given audio frame. Valid sample rates // are 8000, 16000, and 32000 Hz; the number of samples must be such that the // frame is 10, 20, or 30 ms long. virtual Activity VoiceActivity(const int16_t* audio, size_t num_samples, int sample_rate_hz) = 0; // Resets VAD state. virtual void Reset() = 0; }; // Returns a Vad instance that's implemented on top of WebRtcVad. std::unique_ptr CreateVad(Vad::Aggressiveness aggressiveness); } // namespace webrtc #endif // COMMON_AUDIO_VAD_INCLUDE_VAD_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/vad/include/webrtc_vad.h0000664000175000017500000000603314475643423025315 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This header file includes the VAD API calls. Specific function calls are * given below. */ #ifndef COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ // NOLINT #define COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ #include #include typedef struct WebRtcVadInst VadInst; #ifdef __cplusplus extern "C" { #endif // Creates an instance to the VAD structure. VadInst* WebRtcVad_Create(void); // Frees the dynamic memory of a specified VAD instance. // // - handle [i] : Pointer to VAD instance that should be freed. void WebRtcVad_Free(VadInst* handle); // Initializes a VAD instance. // // - handle [i/o] : Instance that should be initialized. // // returns : 0 - (OK), // -1 - (null pointer or Default mode could not be set). int WebRtcVad_Init(VadInst* handle); // Sets the VAD operating mode. A more aggressive (higher mode) VAD is more // restrictive in reporting speech. Put in other words the probability of being // speech when the VAD returns 1 is increased with increasing mode. As a // consequence also the missed detection rate goes up. // // - handle [i/o] : VAD instance. // - mode [i] : Aggressiveness mode (0, 1, 2, or 3). // // returns : 0 - (OK), // -1 - (null pointer, mode could not be set or the VAD instance // has not been initialized). int WebRtcVad_set_mode(VadInst* handle, int mode); // Calculates a VAD decision for the |audio_frame|. For valid sampling rates // frame lengths, see the description of WebRtcVad_ValidRatesAndFrameLengths(). // // - handle [i/o] : VAD Instance. Needs to be initialized by // WebRtcVad_Init() before call. // - fs [i] : Sampling frequency (Hz): 8000, 16000, or 32000 // - audio_frame [i] : Audio frame buffer. // - frame_length [i] : Length of audio frame buffer in number of samples. // // returns : 1 - (Active Voice), // 0 - (Non-active Voice), // -1 - (Error) int WebRtcVad_Process(VadInst* handle, int fs, const int16_t* audio_frame, size_t frame_length); // Checks for valid combinations of |rate| and |frame_length|. We support 10, // 20 and 30 ms frames and the rates 8000, 16000 and 32000 Hz. // // - rate [i] : Sampling frequency (Hz). // - frame_length [i] : Speech frame buffer length in number of samples. // // returns : 0 - (valid combination), -1 - (invalid combination) int WebRtcVad_ValidRateAndFrameLength(int rate, size_t frame_length); #ifdef __cplusplus } #endif #endif // COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ // NOLINT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/vad/vad.cc0000664000175000017500000000331514475643423022462 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/vad/include/vad.h" #include #include "common_audio/vad/include/webrtc_vad.h" #include "rtc_base/checks.h" namespace webrtc { namespace { class VadImpl final : public Vad { public: explicit VadImpl(Aggressiveness aggressiveness) : handle_(nullptr), aggressiveness_(aggressiveness) { Reset(); } ~VadImpl() override { WebRtcVad_Free(handle_); } Activity VoiceActivity(const int16_t* audio, size_t num_samples, int sample_rate_hz) override { int ret = WebRtcVad_Process(handle_, sample_rate_hz, audio, num_samples); switch (ret) { case 0: return kPassive; case 1: return kActive; default: RTC_NOTREACHED() << "WebRtcVad_Process returned an error."; return kError; } } void Reset() override { if (handle_) WebRtcVad_Free(handle_); handle_ = WebRtcVad_Create(); RTC_CHECK(handle_); RTC_CHECK_EQ(WebRtcVad_Init(handle_), 0); RTC_CHECK_EQ(WebRtcVad_set_mode(handle_, aggressiveness_), 0); } private: VadInst* handle_; Aggressiveness aggressiveness_; }; } // namespace std::unique_ptr CreateVad(Vad::Aggressiveness aggressiveness) { return std::unique_ptr(new VadImpl(aggressiveness)); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/vad/vad_core.c0000664000175000017500000006311114475643423023327 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/vad/vad_core.h" #include "rtc_base/sanitizer.h" #include "common_audio/signal_processing/include/signal_processing_library.h" #include "common_audio/vad/vad_filterbank.h" #include "common_audio/vad/vad_gmm.h" #include "common_audio/vad/vad_sp.h" // Spectrum Weighting static const int16_t kSpectrumWeight[kNumChannels] = { 6, 8, 10, 12, 14, 16 }; static const int16_t kNoiseUpdateConst = 655; // Q15 static const int16_t kSpeechUpdateConst = 6554; // Q15 static const int16_t kBackEta = 154; // Q8 // Minimum difference between the two models, Q5 static const int16_t kMinimumDifference[kNumChannels] = { 544, 544, 576, 576, 576, 576 }; // Upper limit of mean value for speech model, Q7 static const int16_t kMaximumSpeech[kNumChannels] = { 11392, 11392, 11520, 11520, 11520, 11520 }; // Minimum value for mean value static const int16_t kMinimumMean[kNumGaussians] = { 640, 768 }; // Upper limit of mean value for noise model, Q7 static const int16_t kMaximumNoise[kNumChannels] = { 9216, 9088, 8960, 8832, 8704, 8576 }; // Start values for the Gaussian models, Q7 // Weights for the two Gaussians for the six channels (noise) static const int16_t kNoiseDataWeights[kTableSize] = { 34, 62, 72, 66, 53, 25, 94, 66, 56, 62, 75, 103 }; // Weights for the two Gaussians for the six channels (speech) static const int16_t kSpeechDataWeights[kTableSize] = { 48, 82, 45, 87, 50, 47, 80, 46, 83, 41, 78, 81 }; // Means for the two Gaussians for the six channels (noise) static const int16_t kNoiseDataMeans[kTableSize] = { 6738, 4892, 7065, 6715, 6771, 3369, 7646, 3863, 7820, 7266, 5020, 4362 }; // Means for the two Gaussians for the six channels (speech) static const int16_t kSpeechDataMeans[kTableSize] = { 8306, 10085, 10078, 11823, 11843, 6309, 9473, 9571, 10879, 7581, 8180, 7483 }; // Stds for the two Gaussians for the six channels (noise) static const int16_t kNoiseDataStds[kTableSize] = { 378, 1064, 493, 582, 688, 593, 474, 697, 475, 688, 421, 455 }; // Stds for the two Gaussians for the six channels (speech) static const int16_t kSpeechDataStds[kTableSize] = { 555, 505, 567, 524, 585, 1231, 509, 828, 492, 1540, 1079, 850 }; // Constants used in GmmProbability(). // // Maximum number of counted speech (VAD = 1) frames in a row. static const int16_t kMaxSpeechFrames = 6; // Minimum standard deviation for both speech and noise. static const int16_t kMinStd = 384; // Constants in WebRtcVad_InitCore(). // Default aggressiveness mode. static const short kDefaultMode = 0; static const int kInitCheck = 42; // Constants used in WebRtcVad_set_mode_core(). // // Thresholds for different frame lengths (10 ms, 20 ms and 30 ms). // // Mode 0, Quality. static const int16_t kOverHangMax1Q[3] = { 8, 4, 3 }; static const int16_t kOverHangMax2Q[3] = { 14, 7, 5 }; static const int16_t kLocalThresholdQ[3] = { 24, 21, 24 }; static const int16_t kGlobalThresholdQ[3] = { 57, 48, 57 }; // Mode 1, Low bitrate. static const int16_t kOverHangMax1LBR[3] = { 8, 4, 3 }; static const int16_t kOverHangMax2LBR[3] = { 14, 7, 5 }; static const int16_t kLocalThresholdLBR[3] = { 37, 32, 37 }; static const int16_t kGlobalThresholdLBR[3] = { 100, 80, 100 }; // Mode 2, Aggressive. static const int16_t kOverHangMax1AGG[3] = { 6, 3, 2 }; static const int16_t kOverHangMax2AGG[3] = { 9, 5, 3 }; static const int16_t kLocalThresholdAGG[3] = { 82, 78, 82 }; static const int16_t kGlobalThresholdAGG[3] = { 285, 260, 285 }; // Mode 3, Very aggressive. static const int16_t kOverHangMax1VAG[3] = { 6, 3, 2 }; static const int16_t kOverHangMax2VAG[3] = { 9, 5, 3 }; static const int16_t kLocalThresholdVAG[3] = { 94, 94, 94 }; static const int16_t kGlobalThresholdVAG[3] = { 1100, 1050, 1100 }; // Calculates the weighted average w.r.t. number of Gaussians. The |data| are // updated with an |offset| before averaging. // // - data [i/o] : Data to average. // - offset [i] : An offset added to |data|. // - weights [i] : Weights used for averaging. // // returns : The weighted average. static int32_t WeightedAverage(int16_t* data, int16_t offset, const int16_t* weights) { int k; int32_t weighted_average = 0; for (k = 0; k < kNumGaussians; k++) { data[k * kNumChannels] += offset; weighted_average += data[k * kNumChannels] * weights[k * kNumChannels]; } return weighted_average; } // An s16 x s32 -> s32 multiplication that's allowed to overflow. (It's still // undefined behavior, so not a good idea; this just makes UBSan ignore the // violation, so that our old code can continue to do what it's always been // doing.) static inline int32_t RTC_NO_SANITIZE("signed-integer-overflow") OverflowingMulS16ByS32ToS32(int16_t a, int32_t b) { return a * b; } // Calculates the probabilities for both speech and background noise using // Gaussian Mixture Models (GMM). A hypothesis-test is performed to decide which // type of signal is most probable. // // - self [i/o] : Pointer to VAD instance // - features [i] : Feature vector of length |kNumChannels| // = log10(energy in frequency band) // - total_power [i] : Total power in audio frame. // - frame_length [i] : Number of input samples // // - returns : the VAD decision (0 - noise, 1 - speech). static int16_t GmmProbability(VadInstT* self, int16_t* features, int16_t total_power, size_t frame_length) { int channel, k; int16_t feature_minimum; int16_t h0, h1; int16_t log_likelihood_ratio; int16_t vadflag = 0; int16_t shifts_h0, shifts_h1; int16_t tmp_s16, tmp1_s16, tmp2_s16; int16_t diff; int gaussian; int16_t nmk, nmk2, nmk3, smk, smk2, nsk, ssk; int16_t delt, ndelt; int16_t maxspe, maxmu; int16_t deltaN[kTableSize], deltaS[kTableSize]; int16_t ngprvec[kTableSize] = { 0 }; // Conditional probability = 0. int16_t sgprvec[kTableSize] = { 0 }; // Conditional probability = 0. int32_t h0_test, h1_test; int32_t tmp1_s32, tmp2_s32; int32_t sum_log_likelihood_ratios = 0; int32_t noise_global_mean, speech_global_mean; int32_t noise_probability[kNumGaussians], speech_probability[kNumGaussians]; int16_t overhead1, overhead2, individualTest, totalTest; // Set various thresholds based on frame lengths (80, 160 or 240 samples). if (frame_length == 80) { overhead1 = self->over_hang_max_1[0]; overhead2 = self->over_hang_max_2[0]; individualTest = self->individual[0]; totalTest = self->total[0]; } else if (frame_length == 160) { overhead1 = self->over_hang_max_1[1]; overhead2 = self->over_hang_max_2[1]; individualTest = self->individual[1]; totalTest = self->total[1]; } else { overhead1 = self->over_hang_max_1[2]; overhead2 = self->over_hang_max_2[2]; individualTest = self->individual[2]; totalTest = self->total[2]; } if (total_power > kMinEnergy) { // The signal power of current frame is large enough for processing. The // processing consists of two parts: // 1) Calculating the likelihood of speech and thereby a VAD decision. // 2) Updating the underlying model, w.r.t., the decision made. // The detection scheme is an LRT with hypothesis // H0: Noise // H1: Speech // // We combine a global LRT with local tests, for each frequency sub-band, // here defined as |channel|. for (channel = 0; channel < kNumChannels; channel++) { // For each channel we model the probability with a GMM consisting of // |kNumGaussians|, with different means and standard deviations depending // on H0 or H1. h0_test = 0; h1_test = 0; for (k = 0; k < kNumGaussians; k++) { gaussian = channel + k * kNumChannels; // Probability under H0, that is, probability of frame being noise. // Value given in Q27 = Q7 * Q20. tmp1_s32 = WebRtcVad_GaussianProbability(features[channel], self->noise_means[gaussian], self->noise_stds[gaussian], &deltaN[gaussian]); noise_probability[k] = kNoiseDataWeights[gaussian] * tmp1_s32; h0_test += noise_probability[k]; // Q27 // Probability under H1, that is, probability of frame being speech. // Value given in Q27 = Q7 * Q20. tmp1_s32 = WebRtcVad_GaussianProbability(features[channel], self->speech_means[gaussian], self->speech_stds[gaussian], &deltaS[gaussian]); speech_probability[k] = kSpeechDataWeights[gaussian] * tmp1_s32; h1_test += speech_probability[k]; // Q27 } // Calculate the log likelihood ratio: log2(Pr{X|H1} / Pr{X|H1}). // Approximation: // log2(Pr{X|H1} / Pr{X|H1}) = log2(Pr{X|H1}*2^Q) - log2(Pr{X|H1}*2^Q) // = log2(h1_test) - log2(h0_test) // = log2(2^(31-shifts_h1)*(1+b1)) // - log2(2^(31-shifts_h0)*(1+b0)) // = shifts_h0 - shifts_h1 // + log2(1+b1) - log2(1+b0) // ~= shifts_h0 - shifts_h1 // // Note that b0 and b1 are values less than 1, hence, 0 <= log2(1+b0) < 1. // Further, b0 and b1 are independent and on the average the two terms // cancel. shifts_h0 = WebRtcSpl_NormW32(h0_test); shifts_h1 = WebRtcSpl_NormW32(h1_test); if (h0_test == 0) { shifts_h0 = 31; } if (h1_test == 0) { shifts_h1 = 31; } log_likelihood_ratio = shifts_h0 - shifts_h1; // Update |sum_log_likelihood_ratios| with spectrum weighting. This is // used for the global VAD decision. sum_log_likelihood_ratios += (int32_t) (log_likelihood_ratio * kSpectrumWeight[channel]); // Local VAD decision. if ((log_likelihood_ratio * 4) > individualTest) { vadflag = 1; } // TODO(bjornv): The conditional probabilities below are applied on the // hard coded number of Gaussians set to two. Find a way to generalize. // Calculate local noise probabilities used later when updating the GMM. h0 = (int16_t) (h0_test >> 12); // Q15 if (h0 > 0) { // High probability of noise. Assign conditional probabilities for each // Gaussian in the GMM. tmp1_s32 = (noise_probability[0] & 0xFFFFF000) << 2; // Q29 ngprvec[channel] = (int16_t) WebRtcSpl_DivW32W16(tmp1_s32, h0); // Q14 ngprvec[channel + kNumChannels] = 16384 - ngprvec[channel]; } else { // Low noise probability. Assign conditional probability 1 to the first // Gaussian and 0 to the rest (which is already set at initialization). ngprvec[channel] = 16384; } // Calculate local speech probabilities used later when updating the GMM. h1 = (int16_t) (h1_test >> 12); // Q15 if (h1 > 0) { // High probability of speech. Assign conditional probabilities for each // Gaussian in the GMM. Otherwise use the initialized values, i.e., 0. tmp1_s32 = (speech_probability[0] & 0xFFFFF000) << 2; // Q29 sgprvec[channel] = (int16_t) WebRtcSpl_DivW32W16(tmp1_s32, h1); // Q14 sgprvec[channel + kNumChannels] = 16384 - sgprvec[channel]; } } // Make a global VAD decision. vadflag |= (sum_log_likelihood_ratios >= totalTest); // Update the model parameters. maxspe = 12800; for (channel = 0; channel < kNumChannels; channel++) { // Get minimum value in past which is used for long term correction in Q4. feature_minimum = WebRtcVad_FindMinimum(self, features[channel], channel); // Compute the "global" mean, that is the sum of the two means weighted. noise_global_mean = WeightedAverage(&self->noise_means[channel], 0, &kNoiseDataWeights[channel]); tmp1_s16 = (int16_t) (noise_global_mean >> 6); // Q8 for (k = 0; k < kNumGaussians; k++) { gaussian = channel + k * kNumChannels; nmk = self->noise_means[gaussian]; smk = self->speech_means[gaussian]; nsk = self->noise_stds[gaussian]; ssk = self->speech_stds[gaussian]; // Update noise mean vector if the frame consists of noise only. nmk2 = nmk; if (!vadflag) { // deltaN = (x-mu)/sigma^2 // ngprvec[k] = |noise_probability[k]| / // (|noise_probability[0]| + |noise_probability[1]|) // (Q14 * Q11 >> 11) = Q14. delt = (int16_t)((ngprvec[gaussian] * deltaN[gaussian]) >> 11); // Q7 + (Q14 * Q15 >> 22) = Q7. nmk2 = nmk + (int16_t)((delt * kNoiseUpdateConst) >> 22); } // Long term correction of the noise mean. // Q8 - Q8 = Q8. ndelt = (feature_minimum << 4) - tmp1_s16; // Q7 + (Q8 * Q8) >> 9 = Q7. nmk3 = nmk2 + (int16_t)((ndelt * kBackEta) >> 9); // Control that the noise mean does not drift to much. tmp_s16 = (int16_t) ((k + 5) << 7); if (nmk3 < tmp_s16) { nmk3 = tmp_s16; } tmp_s16 = (int16_t) ((72 + k - channel) << 7); if (nmk3 > tmp_s16) { nmk3 = tmp_s16; } self->noise_means[gaussian] = nmk3; if (vadflag) { // Update speech mean vector: // |deltaS| = (x-mu)/sigma^2 // sgprvec[k] = |speech_probability[k]| / // (|speech_probability[0]| + |speech_probability[1]|) // (Q14 * Q11) >> 11 = Q14. delt = (int16_t)((sgprvec[gaussian] * deltaS[gaussian]) >> 11); // Q14 * Q15 >> 21 = Q8. tmp_s16 = (int16_t)((delt * kSpeechUpdateConst) >> 21); // Q7 + (Q8 >> 1) = Q7. With rounding. smk2 = smk + ((tmp_s16 + 1) >> 1); // Control that the speech mean does not drift to much. maxmu = maxspe + 640; if (smk2 < kMinimumMean[k]) { smk2 = kMinimumMean[k]; } if (smk2 > maxmu) { smk2 = maxmu; } self->speech_means[gaussian] = smk2; // Q7. // (Q7 >> 3) = Q4. With rounding. tmp_s16 = ((smk + 4) >> 3); tmp_s16 = features[channel] - tmp_s16; // Q4 // (Q11 * Q4 >> 3) = Q12. tmp1_s32 = (deltaS[gaussian] * tmp_s16) >> 3; tmp2_s32 = tmp1_s32 - 4096; tmp_s16 = sgprvec[gaussian] >> 2; // (Q14 >> 2) * Q12 = Q24. tmp1_s32 = tmp_s16 * tmp2_s32; tmp2_s32 = tmp1_s32 >> 4; // Q20 // 0.1 * Q20 / Q7 = Q13. if (tmp2_s32 > 0) { tmp_s16 = (int16_t) WebRtcSpl_DivW32W16(tmp2_s32, ssk * 10); } else { tmp_s16 = (int16_t) WebRtcSpl_DivW32W16(-tmp2_s32, ssk * 10); tmp_s16 = -tmp_s16; } // Divide by 4 giving an update factor of 0.025 (= 0.1 / 4). // Note that division by 4 equals shift by 2, hence, // (Q13 >> 8) = (Q13 >> 6) / 4 = Q7. tmp_s16 += 128; // Rounding. ssk += (tmp_s16 >> 8); if (ssk < kMinStd) { ssk = kMinStd; } self->speech_stds[gaussian] = ssk; } else { // Update GMM variance vectors. // deltaN * (features[channel] - nmk) - 1 // Q4 - (Q7 >> 3) = Q4. tmp_s16 = features[channel] - (nmk >> 3); // (Q11 * Q4 >> 3) = Q12. tmp1_s32 = (deltaN[gaussian] * tmp_s16) >> 3; tmp1_s32 -= 4096; // (Q14 >> 2) * Q12 = Q24. tmp_s16 = (ngprvec[gaussian] + 2) >> 2; tmp2_s32 = OverflowingMulS16ByS32ToS32(tmp_s16, tmp1_s32); // Q20 * approx 0.001 (2^-10=0.0009766), hence, // (Q24 >> 14) = (Q24 >> 4) / 2^10 = Q20. tmp1_s32 = tmp2_s32 >> 14; // Q20 / Q7 = Q13. if (tmp1_s32 > 0) { tmp_s16 = (int16_t) WebRtcSpl_DivW32W16(tmp1_s32, nsk); } else { tmp_s16 = (int16_t) WebRtcSpl_DivW32W16(-tmp1_s32, nsk); tmp_s16 = -tmp_s16; } tmp_s16 += 32; // Rounding nsk += tmp_s16 >> 6; // Q13 >> 6 = Q7. if (nsk < kMinStd) { nsk = kMinStd; } self->noise_stds[gaussian] = nsk; } } // Separate models if they are too close. // |noise_global_mean| in Q14 (= Q7 * Q7). noise_global_mean = WeightedAverage(&self->noise_means[channel], 0, &kNoiseDataWeights[channel]); // |speech_global_mean| in Q14 (= Q7 * Q7). speech_global_mean = WeightedAverage(&self->speech_means[channel], 0, &kSpeechDataWeights[channel]); // |diff| = "global" speech mean - "global" noise mean. // (Q14 >> 9) - (Q14 >> 9) = Q5. diff = (int16_t) (speech_global_mean >> 9) - (int16_t) (noise_global_mean >> 9); if (diff < kMinimumDifference[channel]) { tmp_s16 = kMinimumDifference[channel] - diff; // |tmp1_s16| = ~0.8 * (kMinimumDifference - diff) in Q7. // |tmp2_s16| = ~0.2 * (kMinimumDifference - diff) in Q7. tmp1_s16 = (int16_t)((13 * tmp_s16) >> 2); tmp2_s16 = (int16_t)((3 * tmp_s16) >> 2); // Move Gaussian means for speech model by |tmp1_s16| and update // |speech_global_mean|. Note that |self->speech_means[channel]| is // changed after the call. speech_global_mean = WeightedAverage(&self->speech_means[channel], tmp1_s16, &kSpeechDataWeights[channel]); // Move Gaussian means for noise model by -|tmp2_s16| and update // |noise_global_mean|. Note that |self->noise_means[channel]| is // changed after the call. noise_global_mean = WeightedAverage(&self->noise_means[channel], -tmp2_s16, &kNoiseDataWeights[channel]); } // Control that the speech & noise means do not drift to much. maxspe = kMaximumSpeech[channel]; tmp2_s16 = (int16_t) (speech_global_mean >> 7); if (tmp2_s16 > maxspe) { // Upper limit of speech model. tmp2_s16 -= maxspe; for (k = 0; k < kNumGaussians; k++) { self->speech_means[channel + k * kNumChannels] -= tmp2_s16; } } tmp2_s16 = (int16_t) (noise_global_mean >> 7); if (tmp2_s16 > kMaximumNoise[channel]) { tmp2_s16 -= kMaximumNoise[channel]; for (k = 0; k < kNumGaussians; k++) { self->noise_means[channel + k * kNumChannels] -= tmp2_s16; } } } self->frame_counter++; } // Smooth with respect to transition hysteresis. if (!vadflag) { if (self->over_hang > 0) { vadflag = 2 + self->over_hang; self->over_hang--; } self->num_of_speech = 0; } else { self->num_of_speech++; if (self->num_of_speech > kMaxSpeechFrames) { self->num_of_speech = kMaxSpeechFrames; self->over_hang = overhead2; } else { self->over_hang = overhead1; } } return vadflag; } // Initialize the VAD. Set aggressiveness mode to default value. int WebRtcVad_InitCore(VadInstT* self) { int i; if (self == NULL) { return -1; } // Initialization of general struct variables. self->vad = 1; // Speech active (=1). self->frame_counter = 0; self->over_hang = 0; self->num_of_speech = 0; // Initialization of downsampling filter state. memset(self->downsampling_filter_states, 0, sizeof(self->downsampling_filter_states)); // Initialization of 48 to 8 kHz downsampling. WebRtcSpl_ResetResample48khzTo8khz(&self->state_48_to_8); // Read initial PDF parameters. for (i = 0; i < kTableSize; i++) { self->noise_means[i] = kNoiseDataMeans[i]; self->speech_means[i] = kSpeechDataMeans[i]; self->noise_stds[i] = kNoiseDataStds[i]; self->speech_stds[i] = kSpeechDataStds[i]; } // Initialize Index and Minimum value vectors. for (i = 0; i < 16 * kNumChannels; i++) { self->low_value_vector[i] = 10000; self->index_vector[i] = 0; } // Initialize splitting filter states. memset(self->upper_state, 0, sizeof(self->upper_state)); memset(self->lower_state, 0, sizeof(self->lower_state)); // Initialize high pass filter states. memset(self->hp_filter_state, 0, sizeof(self->hp_filter_state)); // Initialize mean value memory, for WebRtcVad_FindMinimum(). for (i = 0; i < kNumChannels; i++) { self->mean_value[i] = 1600; } // Set aggressiveness mode to default (=|kDefaultMode|). if (WebRtcVad_set_mode_core(self, kDefaultMode) != 0) { return -1; } self->init_flag = kInitCheck; return 0; } // Set aggressiveness mode int WebRtcVad_set_mode_core(VadInstT* self, int mode) { int return_value = 0; switch (mode) { case 0: // Quality mode. memcpy(self->over_hang_max_1, kOverHangMax1Q, sizeof(self->over_hang_max_1)); memcpy(self->over_hang_max_2, kOverHangMax2Q, sizeof(self->over_hang_max_2)); memcpy(self->individual, kLocalThresholdQ, sizeof(self->individual)); memcpy(self->total, kGlobalThresholdQ, sizeof(self->total)); break; case 1: // Low bitrate mode. memcpy(self->over_hang_max_1, kOverHangMax1LBR, sizeof(self->over_hang_max_1)); memcpy(self->over_hang_max_2, kOverHangMax2LBR, sizeof(self->over_hang_max_2)); memcpy(self->individual, kLocalThresholdLBR, sizeof(self->individual)); memcpy(self->total, kGlobalThresholdLBR, sizeof(self->total)); break; case 2: // Aggressive mode. memcpy(self->over_hang_max_1, kOverHangMax1AGG, sizeof(self->over_hang_max_1)); memcpy(self->over_hang_max_2, kOverHangMax2AGG, sizeof(self->over_hang_max_2)); memcpy(self->individual, kLocalThresholdAGG, sizeof(self->individual)); memcpy(self->total, kGlobalThresholdAGG, sizeof(self->total)); break; case 3: // Very aggressive mode. memcpy(self->over_hang_max_1, kOverHangMax1VAG, sizeof(self->over_hang_max_1)); memcpy(self->over_hang_max_2, kOverHangMax2VAG, sizeof(self->over_hang_max_2)); memcpy(self->individual, kLocalThresholdVAG, sizeof(self->individual)); memcpy(self->total, kGlobalThresholdVAG, sizeof(self->total)); break; default: return_value = -1; break; } return return_value; } // Calculate VAD decision by first extracting feature values and then calculate // probability for both speech and background noise. int WebRtcVad_CalcVad48khz(VadInstT* inst, const int16_t* speech_frame, size_t frame_length) { int vad; size_t i; int16_t speech_nb[240]; // 30 ms in 8 kHz. // |tmp_mem| is a temporary memory used by resample function, length is // frame length in 10 ms (480 samples) + 256 extra. int32_t tmp_mem[480 + 256] = { 0 }; const size_t kFrameLen10ms48khz = 480; const size_t kFrameLen10ms8khz = 80; size_t num_10ms_frames = frame_length / kFrameLen10ms48khz; for (i = 0; i < num_10ms_frames; i++) { WebRtcSpl_Resample48khzTo8khz(speech_frame, &speech_nb[i * kFrameLen10ms8khz], &inst->state_48_to_8, tmp_mem); } // Do VAD on an 8 kHz signal vad = WebRtcVad_CalcVad8khz(inst, speech_nb, frame_length / 6); return vad; } int WebRtcVad_CalcVad32khz(VadInstT* inst, const int16_t* speech_frame, size_t frame_length) { size_t len; int vad; int16_t speechWB[480]; // Downsampled speech frame: 960 samples (30ms in SWB) int16_t speechNB[240]; // Downsampled speech frame: 480 samples (30ms in WB) // Downsample signal 32->16->8 before doing VAD WebRtcVad_Downsampling(speech_frame, speechWB, &(inst->downsampling_filter_states[2]), frame_length); len = frame_length / 2; WebRtcVad_Downsampling(speechWB, speechNB, inst->downsampling_filter_states, len); len /= 2; // Do VAD on an 8 kHz signal vad = WebRtcVad_CalcVad8khz(inst, speechNB, len); return vad; } int WebRtcVad_CalcVad16khz(VadInstT* inst, const int16_t* speech_frame, size_t frame_length) { size_t len; int vad; int16_t speechNB[240]; // Downsampled speech frame: 480 samples (30ms in WB) // Wideband: Downsample signal before doing VAD WebRtcVad_Downsampling(speech_frame, speechNB, inst->downsampling_filter_states, frame_length); len = frame_length / 2; vad = WebRtcVad_CalcVad8khz(inst, speechNB, len); return vad; } int WebRtcVad_CalcVad8khz(VadInstT* inst, const int16_t* speech_frame, size_t frame_length) { int16_t feature_vector[kNumChannels], total_power; // Get power in the bands total_power = WebRtcVad_CalculateFeatures(inst, speech_frame, frame_length, feature_vector); // Make a VAD inst->vad = GmmProbability(inst, feature_vector, total_power, frame_length); return inst->vad; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/vad/vad_core.h0000664000175000017500000000737514475643423023346 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This header file includes the descriptions of the core VAD calls. */ #ifndef COMMON_AUDIO_VAD_VAD_CORE_H_ #define COMMON_AUDIO_VAD_VAD_CORE_H_ #include "common_audio/signal_processing/include/signal_processing_library.h" enum { kNumChannels = 6 }; // Number of frequency bands (named channels). enum { kNumGaussians = 2 }; // Number of Gaussians per channel in the GMM. enum { kTableSize = kNumChannels * kNumGaussians }; enum { kMinEnergy = 10 }; // Minimum energy required to trigger audio signal. typedef struct VadInstT_ { int vad; int32_t downsampling_filter_states[4]; WebRtcSpl_State48khzTo8khz state_48_to_8; int16_t noise_means[kTableSize]; int16_t speech_means[kTableSize]; int16_t noise_stds[kTableSize]; int16_t speech_stds[kTableSize]; // TODO(bjornv): Change to |frame_count|. int32_t frame_counter; int16_t over_hang; // Over Hang int16_t num_of_speech; // TODO(bjornv): Change to |age_vector|. int16_t index_vector[16 * kNumChannels]; int16_t low_value_vector[16 * kNumChannels]; // TODO(bjornv): Change to |median|. int16_t mean_value[kNumChannels]; int16_t upper_state[5]; int16_t lower_state[5]; int16_t hp_filter_state[4]; int16_t over_hang_max_1[3]; int16_t over_hang_max_2[3]; int16_t individual[3]; int16_t total[3]; int init_flag; } VadInstT; // Initializes the core VAD component. The default aggressiveness mode is // controlled by |kDefaultMode| in vad_core.c. // // - self [i/o] : Instance that should be initialized // // returns : 0 (OK), -1 (null pointer in or if the default mode can't be // set) int WebRtcVad_InitCore(VadInstT* self); /**************************************************************************** * WebRtcVad_set_mode_core(...) * * This function changes the VAD settings * * Input: * - inst : VAD instance * - mode : Aggressiveness degree * 0 (High quality) - 3 (Highly aggressive) * * Output: * - inst : Changed instance * * Return value : 0 - Ok * -1 - Error */ int WebRtcVad_set_mode_core(VadInstT* self, int mode); /**************************************************************************** * WebRtcVad_CalcVad48khz(...) * WebRtcVad_CalcVad32khz(...) * WebRtcVad_CalcVad16khz(...) * WebRtcVad_CalcVad8khz(...) * * Calculate probability for active speech and make VAD decision. * * Input: * - inst : Instance that should be initialized * - speech_frame : Input speech frame * - frame_length : Number of input samples * * Output: * - inst : Updated filter states etc. * * Return value : VAD decision * 0 - No active speech * 1-6 - Active speech */ int WebRtcVad_CalcVad48khz(VadInstT* inst, const int16_t* speech_frame, size_t frame_length); int WebRtcVad_CalcVad32khz(VadInstT* inst, const int16_t* speech_frame, size_t frame_length); int WebRtcVad_CalcVad16khz(VadInstT* inst, const int16_t* speech_frame, size_t frame_length); int WebRtcVad_CalcVad8khz(VadInstT* inst, const int16_t* speech_frame, size_t frame_length); #endif // COMMON_AUDIO_VAD_VAD_CORE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/vad/vad_filterbank.c0000664000175000017500000003332714475643423024526 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/vad/vad_filterbank.h" #include "rtc_base/checks.h" #include "common_audio/signal_processing/include/signal_processing_library.h" // Constants used in LogOfEnergy(). static const int16_t kLogConst = 24660; // 160*log10(2) in Q9. static const int16_t kLogEnergyIntPart = 14336; // 14 in Q10 // Coefficients used by HighPassFilter, Q14. static const int16_t kHpZeroCoefs[3] = { 6631, -13262, 6631 }; static const int16_t kHpPoleCoefs[3] = { 16384, -7756, 5620 }; // Allpass filter coefficients, upper and lower, in Q15. // Upper: 0.64, Lower: 0.17 static const int16_t kAllPassCoefsQ15[2] = { 20972, 5571 }; // Adjustment for division with two in SplitFilter. static const int16_t kOffsetVector[6] = { 368, 368, 272, 176, 176, 176 }; // High pass filtering, with a cut-off frequency at 80 Hz, if the |data_in| is // sampled at 500 Hz. // // - data_in [i] : Input audio data sampled at 500 Hz. // - data_length [i] : Length of input and output data. // - filter_state [i/o] : State of the filter. // - data_out [o] : Output audio data in the frequency interval // 80 - 250 Hz. static void HighPassFilter(const int16_t* data_in, size_t data_length, int16_t* filter_state, int16_t* data_out) { size_t i; const int16_t* in_ptr = data_in; int16_t* out_ptr = data_out; int32_t tmp32 = 0; // The sum of the absolute values of the impulse response: // The zero/pole-filter has a max amplification of a single sample of: 1.4546 // Impulse response: 0.4047 -0.6179 -0.0266 0.1993 0.1035 -0.0194 // The all-zero section has a max amplification of a single sample of: 1.6189 // Impulse response: 0.4047 -0.8094 0.4047 0 0 0 // The all-pole section has a max amplification of a single sample of: 1.9931 // Impulse response: 1.0000 0.4734 -0.1189 -0.2187 -0.0627 0.04532 for (i = 0; i < data_length; i++) { // All-zero section (filter coefficients in Q14). tmp32 = kHpZeroCoefs[0] * *in_ptr; tmp32 += kHpZeroCoefs[1] * filter_state[0]; tmp32 += kHpZeroCoefs[2] * filter_state[1]; filter_state[1] = filter_state[0]; filter_state[0] = *in_ptr++; // All-pole section (filter coefficients in Q14). tmp32 -= kHpPoleCoefs[1] * filter_state[2]; tmp32 -= kHpPoleCoefs[2] * filter_state[3]; filter_state[3] = filter_state[2]; filter_state[2] = (int16_t) (tmp32 >> 14); *out_ptr++ = filter_state[2]; } } // All pass filtering of |data_in|, used before splitting the signal into two // frequency bands (low pass vs high pass). // Note that |data_in| and |data_out| can NOT correspond to the same address. // // - data_in [i] : Input audio signal given in Q0. // - data_length [i] : Length of input and output data. // - filter_coefficient [i] : Given in Q15. // - filter_state [i/o] : State of the filter given in Q(-1). // - data_out [o] : Output audio signal given in Q(-1). static void AllPassFilter(const int16_t* data_in, size_t data_length, int16_t filter_coefficient, int16_t* filter_state, int16_t* data_out) { // The filter can only cause overflow (in the w16 output variable) // if more than 4 consecutive input numbers are of maximum value and // has the the same sign as the impulse responses first taps. // First 6 taps of the impulse response: // 0.6399 0.5905 -0.3779 0.2418 -0.1547 0.0990 size_t i; int16_t tmp16 = 0; int32_t tmp32 = 0; int32_t state32 = ((int32_t) (*filter_state) * (1 << 16)); // Q15 for (i = 0; i < data_length; i++) { tmp32 = state32 + filter_coefficient * *data_in; tmp16 = (int16_t) (tmp32 >> 16); // Q(-1) *data_out++ = tmp16; state32 = (*data_in * (1 << 14)) - filter_coefficient * tmp16; // Q14 state32 *= 2; // Q15. data_in += 2; } *filter_state = (int16_t) (state32 >> 16); // Q(-1) } // Splits |data_in| into |hp_data_out| and |lp_data_out| corresponding to // an upper (high pass) part and a lower (low pass) part respectively. // // - data_in [i] : Input audio data to be split into two frequency bands. // - data_length [i] : Length of |data_in|. // - upper_state [i/o] : State of the upper filter, given in Q(-1). // - lower_state [i/o] : State of the lower filter, given in Q(-1). // - hp_data_out [o] : Output audio data of the upper half of the spectrum. // The length is |data_length| / 2. // - lp_data_out [o] : Output audio data of the lower half of the spectrum. // The length is |data_length| / 2. static void SplitFilter(const int16_t* data_in, size_t data_length, int16_t* upper_state, int16_t* lower_state, int16_t* hp_data_out, int16_t* lp_data_out) { size_t i; size_t half_length = data_length >> 1; // Downsampling by 2. int16_t tmp_out; // All-pass filtering upper branch. AllPassFilter(&data_in[0], half_length, kAllPassCoefsQ15[0], upper_state, hp_data_out); // All-pass filtering lower branch. AllPassFilter(&data_in[1], half_length, kAllPassCoefsQ15[1], lower_state, lp_data_out); // Make LP and HP signals. for (i = 0; i < half_length; i++) { tmp_out = *hp_data_out; *hp_data_out++ -= *lp_data_out; *lp_data_out++ += tmp_out; } } // Calculates the energy of |data_in| in dB, and also updates an overall // |total_energy| if necessary. // // - data_in [i] : Input audio data for energy calculation. // - data_length [i] : Length of input data. // - offset [i] : Offset value added to |log_energy|. // - total_energy [i/o] : An external energy updated with the energy of // |data_in|. // NOTE: |total_energy| is only updated if // |total_energy| <= |kMinEnergy|. // - log_energy [o] : 10 * log10("energy of |data_in|") given in Q4. static void LogOfEnergy(const int16_t* data_in, size_t data_length, int16_t offset, int16_t* total_energy, int16_t* log_energy) { // |tot_rshifts| accumulates the number of right shifts performed on |energy|. int tot_rshifts = 0; // The |energy| will be normalized to 15 bits. We use unsigned integer because // we eventually will mask out the fractional part. uint32_t energy = 0; RTC_DCHECK(data_in); RTC_DCHECK_GT(data_length, 0); energy = (uint32_t) WebRtcSpl_Energy((int16_t*) data_in, data_length, &tot_rshifts); if (energy != 0) { // By construction, normalizing to 15 bits is equivalent with 17 leading // zeros of an unsigned 32 bit value. int normalizing_rshifts = 17 - WebRtcSpl_NormU32(energy); // In a 15 bit representation the leading bit is 2^14. log2(2^14) in Q10 is // (14 << 10), which is what we initialize |log2_energy| with. For a more // detailed derivations, see below. int16_t log2_energy = kLogEnergyIntPart; tot_rshifts += normalizing_rshifts; // Normalize |energy| to 15 bits. // |tot_rshifts| is now the total number of right shifts performed on // |energy| after normalization. This means that |energy| is in // Q(-tot_rshifts). if (normalizing_rshifts < 0) { energy <<= -normalizing_rshifts; } else { energy >>= normalizing_rshifts; } // Calculate the energy of |data_in| in dB, in Q4. // // 10 * log10("true energy") in Q4 = 2^4 * 10 * log10("true energy") = // 160 * log10(|energy| * 2^|tot_rshifts|) = // 160 * log10(2) * log2(|energy| * 2^|tot_rshifts|) = // 160 * log10(2) * (log2(|energy|) + log2(2^|tot_rshifts|)) = // (160 * log10(2)) * (log2(|energy|) + |tot_rshifts|) = // |kLogConst| * (|log2_energy| + |tot_rshifts|) // // We know by construction that |energy| is normalized to 15 bits. Hence, // |energy| = 2^14 + frac_Q15, where frac_Q15 is a fractional part in Q15. // Further, we'd like |log2_energy| in Q10 // log2(|energy|) in Q10 = 2^10 * log2(2^14 + frac_Q15) = // 2^10 * log2(2^14 * (1 + frac_Q15 * 2^-14)) = // 2^10 * (14 + log2(1 + frac_Q15 * 2^-14)) ~= // (14 << 10) + 2^10 * (frac_Q15 * 2^-14) = // (14 << 10) + (frac_Q15 * 2^-4) = (14 << 10) + (frac_Q15 >> 4) // // Note that frac_Q15 = (|energy| & 0x00003FFF) // Calculate and add the fractional part to |log2_energy|. log2_energy += (int16_t) ((energy & 0x00003FFF) >> 4); // |kLogConst| is in Q9, |log2_energy| in Q10 and |tot_rshifts| in Q0. // Note that we in our derivation above have accounted for an output in Q4. *log_energy = (int16_t)(((kLogConst * log2_energy) >> 19) + ((tot_rshifts * kLogConst) >> 9)); if (*log_energy < 0) { *log_energy = 0; } } else { *log_energy = offset; return; } *log_energy += offset; // Update the approximate |total_energy| with the energy of |data_in|, if // |total_energy| has not exceeded |kMinEnergy|. |total_energy| is used as an // energy indicator in WebRtcVad_GmmProbability() in vad_core.c. if (*total_energy <= kMinEnergy) { if (tot_rshifts >= 0) { // We know by construction that the |energy| > |kMinEnergy| in Q0, so add // an arbitrary value such that |total_energy| exceeds |kMinEnergy|. *total_energy += kMinEnergy + 1; } else { // By construction |energy| is represented by 15 bits, hence any number of // right shifted |energy| will fit in an int16_t. In addition, adding the // value to |total_energy| is wrap around safe as long as // |kMinEnergy| < 8192. *total_energy += (int16_t) (energy >> -tot_rshifts); // Q0. } } } int16_t WebRtcVad_CalculateFeatures(VadInstT* self, const int16_t* data_in, size_t data_length, int16_t* features) { int16_t total_energy = 0; // We expect |data_length| to be 80, 160 or 240 samples, which corresponds to // 10, 20 or 30 ms in 8 kHz. Therefore, the intermediate downsampled data will // have at most 120 samples after the first split and at most 60 samples after // the second split. int16_t hp_120[120], lp_120[120]; int16_t hp_60[60], lp_60[60]; const size_t half_data_length = data_length >> 1; size_t length = half_data_length; // |data_length| / 2, corresponds to // bandwidth = 2000 Hz after downsampling. // Initialize variables for the first SplitFilter(). int frequency_band = 0; const int16_t* in_ptr = data_in; // [0 - 4000] Hz. int16_t* hp_out_ptr = hp_120; // [2000 - 4000] Hz. int16_t* lp_out_ptr = lp_120; // [0 - 2000] Hz. RTC_DCHECK_LE(data_length, 240); RTC_DCHECK_LT(4, kNumChannels - 1); // Checking maximum |frequency_band|. // Split at 2000 Hz and downsample. SplitFilter(in_ptr, data_length, &self->upper_state[frequency_band], &self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr); // For the upper band (2000 Hz - 4000 Hz) split at 3000 Hz and downsample. frequency_band = 1; in_ptr = hp_120; // [2000 - 4000] Hz. hp_out_ptr = hp_60; // [3000 - 4000] Hz. lp_out_ptr = lp_60; // [2000 - 3000] Hz. SplitFilter(in_ptr, length, &self->upper_state[frequency_band], &self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr); // Energy in 3000 Hz - 4000 Hz. length >>= 1; // |data_length| / 4 <=> bandwidth = 1000 Hz. LogOfEnergy(hp_60, length, kOffsetVector[5], &total_energy, &features[5]); // Energy in 2000 Hz - 3000 Hz. LogOfEnergy(lp_60, length, kOffsetVector[4], &total_energy, &features[4]); // For the lower band (0 Hz - 2000 Hz) split at 1000 Hz and downsample. frequency_band = 2; in_ptr = lp_120; // [0 - 2000] Hz. hp_out_ptr = hp_60; // [1000 - 2000] Hz. lp_out_ptr = lp_60; // [0 - 1000] Hz. length = half_data_length; // |data_length| / 2 <=> bandwidth = 2000 Hz. SplitFilter(in_ptr, length, &self->upper_state[frequency_band], &self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr); // Energy in 1000 Hz - 2000 Hz. length >>= 1; // |data_length| / 4 <=> bandwidth = 1000 Hz. LogOfEnergy(hp_60, length, kOffsetVector[3], &total_energy, &features[3]); // For the lower band (0 Hz - 1000 Hz) split at 500 Hz and downsample. frequency_band = 3; in_ptr = lp_60; // [0 - 1000] Hz. hp_out_ptr = hp_120; // [500 - 1000] Hz. lp_out_ptr = lp_120; // [0 - 500] Hz. SplitFilter(in_ptr, length, &self->upper_state[frequency_band], &self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr); // Energy in 500 Hz - 1000 Hz. length >>= 1; // |data_length| / 8 <=> bandwidth = 500 Hz. LogOfEnergy(hp_120, length, kOffsetVector[2], &total_energy, &features[2]); // For the lower band (0 Hz - 500 Hz) split at 250 Hz and downsample. frequency_band = 4; in_ptr = lp_120; // [0 - 500] Hz. hp_out_ptr = hp_60; // [250 - 500] Hz. lp_out_ptr = lp_60; // [0 - 250] Hz. SplitFilter(in_ptr, length, &self->upper_state[frequency_band], &self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr); // Energy in 250 Hz - 500 Hz. length >>= 1; // |data_length| / 16 <=> bandwidth = 250 Hz. LogOfEnergy(hp_60, length, kOffsetVector[1], &total_energy, &features[1]); // Remove 0 Hz - 80 Hz, by high pass filtering the lower band. HighPassFilter(lp_60, length, self->hp_filter_state, hp_120); // Energy in 80 Hz - 250 Hz. LogOfEnergy(hp_120, length, kOffsetVector[0], &total_energy, &features[0]); return total_energy; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/vad/vad_filterbank.h0000664000175000017500000000353014475643423024524 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This file includes feature calculating functionality used in vad_core.c. */ #ifndef COMMON_AUDIO_VAD_VAD_FILTERBANK_H_ #define COMMON_AUDIO_VAD_VAD_FILTERBANK_H_ #include "common_audio/vad/vad_core.h" // Takes |data_length| samples of |data_in| and calculates the logarithm of the // energy of each of the |kNumChannels| = 6 frequency bands used by the VAD: // 80 Hz - 250 Hz // 250 Hz - 500 Hz // 500 Hz - 1000 Hz // 1000 Hz - 2000 Hz // 2000 Hz - 3000 Hz // 3000 Hz - 4000 Hz // // The values are given in Q4 and written to |features|. Further, an approximate // overall energy is returned. The return value is used in // WebRtcVad_GmmProbability() as a signal indicator, hence it is arbitrary above // the threshold |kMinEnergy|. // // - self [i/o] : State information of the VAD. // - data_in [i] : Input audio data, for feature extraction. // - data_length [i] : Audio data size, in number of samples. // - features [o] : 10 * log10(energy in each frequency band), Q4. // - returns : Total energy of the signal (NOTE! This value is not // exact. It is only used in a comparison.) int16_t WebRtcVad_CalculateFeatures(VadInstT* self, const int16_t* data_in, size_t data_length, int16_t* features); #endif // COMMON_AUDIO_VAD_VAD_FILTERBANK_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/vad/vad_gmm.c0000664000175000017500000000572714475643423023170 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/vad/vad_gmm.h" #include "common_audio/signal_processing/include/signal_processing_library.h" static const int32_t kCompVar = 22005; static const int16_t kLog2Exp = 5909; // log2(exp(1)) in Q12. // For a normal distribution, the probability of |input| is calculated and // returned (in Q20). The formula for normal distributed probability is // // 1 / s * exp(-(x - m)^2 / (2 * s^2)) // // where the parameters are given in the following Q domains: // m = |mean| (Q7) // s = |std| (Q7) // x = |input| (Q4) // in addition to the probability we output |delta| (in Q11) used when updating // the noise/speech model. int32_t WebRtcVad_GaussianProbability(int16_t input, int16_t mean, int16_t std, int16_t* delta) { int16_t tmp16, inv_std, inv_std2, exp_value = 0; int32_t tmp32; // Calculate |inv_std| = 1 / s, in Q10. // 131072 = 1 in Q17, and (|std| >> 1) is for rounding instead of truncation. // Q-domain: Q17 / Q7 = Q10. tmp32 = (int32_t) 131072 + (int32_t) (std >> 1); inv_std = (int16_t) WebRtcSpl_DivW32W16(tmp32, std); // Calculate |inv_std2| = 1 / s^2, in Q14. tmp16 = (inv_std >> 2); // Q10 -> Q8. // Q-domain: (Q8 * Q8) >> 2 = Q14. inv_std2 = (int16_t)((tmp16 * tmp16) >> 2); // TODO(bjornv): Investigate if changing to // inv_std2 = (int16_t)((inv_std * inv_std) >> 6); // gives better accuracy. tmp16 = (input << 3); // Q4 -> Q7 tmp16 = tmp16 - mean; // Q7 - Q7 = Q7 // To be used later, when updating noise/speech model. // |delta| = (x - m) / s^2, in Q11. // Q-domain: (Q14 * Q7) >> 10 = Q11. *delta = (int16_t)((inv_std2 * tmp16) >> 10); // Calculate the exponent |tmp32| = (x - m)^2 / (2 * s^2), in Q10. Replacing // division by two with one shift. // Q-domain: (Q11 * Q7) >> 8 = Q10. tmp32 = (*delta * tmp16) >> 9; // If the exponent is small enough to give a non-zero probability we calculate // |exp_value| ~= exp(-(x - m)^2 / (2 * s^2)) // ~= exp2(-log2(exp(1)) * |tmp32|). if (tmp32 < kCompVar) { // Calculate |tmp16| = log2(exp(1)) * |tmp32|, in Q10. // Q-domain: (Q12 * Q10) >> 12 = Q10. tmp16 = (int16_t)((kLog2Exp * tmp32) >> 12); tmp16 = -tmp16; exp_value = (0x0400 | (tmp16 & 0x03FF)); tmp16 ^= 0xFFFF; tmp16 >>= 10; tmp16 += 1; // Get |exp_value| = exp(-|tmp32|) in Q10. exp_value >>= tmp16; } // Calculate and return (1 / s) * exp(-(x - m)^2 / (2 * s^2)), in Q20. // Q-domain: Q10 * Q10 = Q20. return inv_std * exp_value; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/vad/vad_gmm.h0000664000175000017500000000260414475643423023164 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Gaussian probability calculations internally used in vad_core.c. #ifndef COMMON_AUDIO_VAD_VAD_GMM_H_ #define COMMON_AUDIO_VAD_VAD_GMM_H_ #include // Calculates the probability for |input|, given that |input| comes from a // normal distribution with mean and standard deviation (|mean|, |std|). // // Inputs: // - input : input sample in Q4. // - mean : mean input in the statistical model, Q7. // - std : standard deviation, Q7. // // Output: // // - delta : input used when updating the model, Q11. // |delta| = (|input| - |mean|) / |std|^2. // // Return: // (probability for |input|) = // 1 / |std| * exp(-(|input| - |mean|)^2 / (2 * |std|^2)); int32_t WebRtcVad_GaussianProbability(int16_t input, int16_t mean, int16_t std, int16_t* delta); #endif // COMMON_AUDIO_VAD_VAD_GMM_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/vad/vad_sp.c0000664000175000017500000001331514475643423023022 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/vad/vad_sp.h" #include "rtc_base/checks.h" #include "common_audio/signal_processing/include/signal_processing_library.h" #include "common_audio/vad/vad_core.h" // Allpass filter coefficients, upper and lower, in Q13. // Upper: 0.64, Lower: 0.17. static const int16_t kAllPassCoefsQ13[2] = { 5243, 1392 }; // Q13. static const int16_t kSmoothingDown = 6553; // 0.2 in Q15. static const int16_t kSmoothingUp = 32439; // 0.99 in Q15. // TODO(bjornv): Move this function to vad_filterbank.c. // Downsampling filter based on splitting filter and allpass functions. void WebRtcVad_Downsampling(const int16_t* signal_in, int16_t* signal_out, int32_t* filter_state, size_t in_length) { int16_t tmp16_1 = 0, tmp16_2 = 0; int32_t tmp32_1 = filter_state[0]; int32_t tmp32_2 = filter_state[1]; size_t n = 0; // Downsampling by 2 gives half length. size_t half_length = (in_length >> 1); // Filter coefficients in Q13, filter state in Q0. for (n = 0; n < half_length; n++) { // All-pass filtering upper branch. tmp16_1 = (int16_t) ((tmp32_1 >> 1) + ((kAllPassCoefsQ13[0] * *signal_in) >> 14)); *signal_out = tmp16_1; tmp32_1 = (int32_t)(*signal_in++) - ((kAllPassCoefsQ13[0] * tmp16_1) >> 12); // All-pass filtering lower branch. tmp16_2 = (int16_t) ((tmp32_2 >> 1) + ((kAllPassCoefsQ13[1] * *signal_in) >> 14)); *signal_out++ += tmp16_2; tmp32_2 = (int32_t)(*signal_in++) - ((kAllPassCoefsQ13[1] * tmp16_2) >> 12); } // Store the filter states. filter_state[0] = tmp32_1; filter_state[1] = tmp32_2; } // Inserts |feature_value| into |low_value_vector|, if it is one of the 16 // smallest values the last 100 frames. Then calculates and returns the median // of the five smallest values. int16_t WebRtcVad_FindMinimum(VadInstT* self, int16_t feature_value, int channel) { int i = 0, j = 0; int position = -1; // Offset to beginning of the 16 minimum values in memory. const int offset = (channel << 4); int16_t current_median = 1600; int16_t alpha = 0; int32_t tmp32 = 0; // Pointer to memory for the 16 minimum values and the age of each value of // the |channel|. int16_t* age = &self->index_vector[offset]; int16_t* smallest_values = &self->low_value_vector[offset]; RTC_DCHECK_LT(channel, kNumChannels); // Each value in |smallest_values| is getting 1 loop older. Update |age|, and // remove old values. for (i = 0; i < 16; i++) { if (age[i] != 100) { age[i]++; } else { // Too old value. Remove from memory and shift larger values downwards. for (j = i; j < 15; j++) { smallest_values[j] = smallest_values[j + 1]; age[j] = age[j + 1]; } age[15] = 101; smallest_values[15] = 10000; } } // Check if |feature_value| is smaller than any of the values in // |smallest_values|. If so, find the |position| where to insert the new value // (|feature_value|). if (feature_value < smallest_values[7]) { if (feature_value < smallest_values[3]) { if (feature_value < smallest_values[1]) { if (feature_value < smallest_values[0]) { position = 0; } else { position = 1; } } else if (feature_value < smallest_values[2]) { position = 2; } else { position = 3; } } else if (feature_value < smallest_values[5]) { if (feature_value < smallest_values[4]) { position = 4; } else { position = 5; } } else if (feature_value < smallest_values[6]) { position = 6; } else { position = 7; } } else if (feature_value < smallest_values[15]) { if (feature_value < smallest_values[11]) { if (feature_value < smallest_values[9]) { if (feature_value < smallest_values[8]) { position = 8; } else { position = 9; } } else if (feature_value < smallest_values[10]) { position = 10; } else { position = 11; } } else if (feature_value < smallest_values[13]) { if (feature_value < smallest_values[12]) { position = 12; } else { position = 13; } } else if (feature_value < smallest_values[14]) { position = 14; } else { position = 15; } } // If we have detected a new small value, insert it at the correct position // and shift larger values up. if (position > -1) { for (i = 15; i > position; i--) { smallest_values[i] = smallest_values[i - 1]; age[i] = age[i - 1]; } smallest_values[position] = feature_value; age[position] = 1; } // Get |current_median|. if (self->frame_counter > 2) { current_median = smallest_values[2]; } else if (self->frame_counter > 0) { current_median = smallest_values[0]; } // Smooth the median value. if (self->frame_counter > 0) { if (current_median < self->mean_value[channel]) { alpha = kSmoothingDown; // 0.2 in Q15. } else { alpha = kSmoothingUp; // 0.99 in Q15. } } tmp32 = (alpha + 1) * self->mean_value[channel]; tmp32 += (WEBRTC_SPL_WORD16_MAX - alpha) * current_median; tmp32 += 16384; self->mean_value[channel] = (int16_t) (tmp32 >> 15); return self->mean_value[channel]; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/vad/vad_sp.h0000664000175000017500000000377714475643423023042 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // This file includes specific signal processing tools used in vad_core.c. #ifndef COMMON_AUDIO_VAD_VAD_SP_H_ #define COMMON_AUDIO_VAD_VAD_SP_H_ #include "common_audio/vad/vad_core.h" // Downsamples the signal by a factor 2, eg. 32->16 or 16->8. // // Inputs: // - signal_in : Input signal. // - in_length : Length of input signal in samples. // // Input & Output: // - filter_state : Current filter states of the two all-pass filters. The // |filter_state| is updated after all samples have been // processed. // // Output: // - signal_out : Downsampled signal (of length |in_length| / 2). void WebRtcVad_Downsampling(const int16_t* signal_in, int16_t* signal_out, int32_t* filter_state, size_t in_length); // Updates and returns the smoothed feature minimum. As minimum we use the // median of the five smallest feature values in a 100 frames long window. // As long as |handle->frame_counter| is zero, that is, we haven't received any // "valid" data, FindMinimum() outputs the default value of 1600. // // Inputs: // - feature_value : New feature value to update with. // - channel : Channel number. // // Input & Output: // - handle : State information of the VAD. // // Returns: // : Smoothed minimum value for a moving window. int16_t WebRtcVad_FindMinimum(VadInstT* handle, int16_t feature_value, int channel); #endif // COMMON_AUDIO_VAD_VAD_SP_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/vad/webrtc_vad.c0000664000175000017500000000574114475643423023672 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/vad/include/webrtc_vad.h" #include #include #include "common_audio/signal_processing/include/signal_processing_library.h" #include "common_audio/vad/vad_core.h" static const int kInitCheck = 42; static const int kValidRates[] = { 8000, 16000, 32000, 48000 }; static const size_t kRatesSize = sizeof(kValidRates) / sizeof(*kValidRates); static const int kMaxFrameLengthMs = 30; VadInst* WebRtcVad_Create() { VadInstT* self = (VadInstT*)malloc(sizeof(VadInstT)); self->init_flag = 0; return (VadInst*)self; } void WebRtcVad_Free(VadInst* handle) { free(handle); } // TODO(bjornv): Move WebRtcVad_InitCore() code here. int WebRtcVad_Init(VadInst* handle) { // Initialize the core VAD component. return WebRtcVad_InitCore((VadInstT*) handle); } // TODO(bjornv): Move WebRtcVad_set_mode_core() code here. int WebRtcVad_set_mode(VadInst* handle, int mode) { VadInstT* self = (VadInstT*) handle; if (handle == NULL) { return -1; } if (self->init_flag != kInitCheck) { return -1; } return WebRtcVad_set_mode_core(self, mode); } int WebRtcVad_Process(VadInst* handle, int fs, const int16_t* audio_frame, size_t frame_length) { int vad = -1; VadInstT* self = (VadInstT*) handle; if (handle == NULL) { return -1; } if (self->init_flag != kInitCheck) { return -1; } if (audio_frame == NULL) { return -1; } if (WebRtcVad_ValidRateAndFrameLength(fs, frame_length) != 0) { return -1; } if (fs == 48000) { vad = WebRtcVad_CalcVad48khz(self, audio_frame, frame_length); } else if (fs == 32000) { vad = WebRtcVad_CalcVad32khz(self, audio_frame, frame_length); } else if (fs == 16000) { vad = WebRtcVad_CalcVad16khz(self, audio_frame, frame_length); } else if (fs == 8000) { vad = WebRtcVad_CalcVad8khz(self, audio_frame, frame_length); } if (vad > 0) { vad = 1; } return vad; } int WebRtcVad_ValidRateAndFrameLength(int rate, size_t frame_length) { int return_value = -1; size_t i; int valid_length_ms; size_t valid_length; // We only allow 10, 20 or 30 ms frames. Loop through valid frame rates and // see if we have a matching pair. for (i = 0; i < kRatesSize; i++) { if (kValidRates[i] == rate) { for (valid_length_ms = 10; valid_length_ms <= kMaxFrameLengthMs; valid_length_ms += 10) { valid_length = (size_t)(kValidRates[i] / 1000 * valid_length_ms); if (frame_length == valid_length) { return_value = 0; break; } } break; } } return return_value; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/wav_file.cc0000664000175000017500000002460314475643423022735 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "common_audio/wav_file.h" #include #include #include #include #include #include #include "common_audio/include/audio_util.h" #include "rtc_base/checks.h" #include "rtc_base/system/arch.h" namespace webrtc { namespace { static_assert(std::is_trivially_destructible::value, ""); // Checks whether the format is supported or not. bool FormatSupported(WavFormat format) { // Only PCM and IEEE Float formats are supported. return format == WavFormat::kWavFormatPcm || format == WavFormat::kWavFormatIeeeFloat; } // Doesn't take ownership of the file handle and won't close it. class WavHeaderFileReader : public WavHeaderReader { public: explicit WavHeaderFileReader(FileWrapper* file) : file_(file) {} WavHeaderFileReader(const WavHeaderFileReader&) = delete; WavHeaderFileReader& operator=(const WavHeaderFileReader&) = delete; size_t Read(void* buf, size_t num_bytes) override { size_t count = file_->Read(buf, num_bytes); pos_ += count; return count; } bool SeekForward(uint32_t num_bytes) override { bool success = file_->SeekRelative(num_bytes); if (success) { pos_ += num_bytes; } return success; } int64_t GetPosition() override { return pos_; } private: FileWrapper* file_; int64_t pos_ = 0; }; constexpr size_t kMaxChunksize = 4096; } // namespace WavReader::WavReader(const std::string& filename) : WavReader(FileWrapper::OpenReadOnly(filename)) {} WavReader::WavReader(FileWrapper file) : file_(std::move(file)) { RTC_CHECK(file_.is_open()) << "Invalid file. Could not create file handle for wav file."; WavHeaderFileReader readable(&file_); size_t bytes_per_sample; RTC_CHECK(ReadWavHeader(&readable, &num_channels_, &sample_rate_, &format_, &bytes_per_sample, &num_samples_in_file_, &data_start_pos_)); num_unread_samples_ = num_samples_in_file_; RTC_CHECK(FormatSupported(format_)) << "Non-implemented wav-format"; } void WavReader::Reset() { RTC_CHECK(file_.SeekTo(data_start_pos_)) << "Failed to set position in the file to WAV data start position"; num_unread_samples_ = num_samples_in_file_; } size_t WavReader::ReadSamples(const size_t num_samples, int16_t* const samples) { #ifndef WEBRTC_ARCH_LITTLE_ENDIAN #error "Need to convert samples to big-endian when reading from WAV file" #endif size_t num_samples_left_to_read = num_samples; size_t next_chunk_start = 0; while (num_samples_left_to_read > 0 && num_unread_samples_ > 0) { const size_t chunk_size = std::min( std::min(kMaxChunksize, num_samples_left_to_read), num_unread_samples_); size_t num_bytes_read; size_t num_samples_read; if (format_ == WavFormat::kWavFormatIeeeFloat) { std::array samples_to_convert; num_bytes_read = file_.Read(samples_to_convert.data(), chunk_size * sizeof(samples_to_convert[0])); num_samples_read = num_bytes_read / sizeof(samples_to_convert[0]); for (size_t j = 0; j < num_samples_read; ++j) { samples[next_chunk_start + j] = FloatToS16(samples_to_convert[j]); } } else { RTC_CHECK_EQ(format_, WavFormat::kWavFormatPcm); num_bytes_read = file_.Read(&samples[next_chunk_start], chunk_size * sizeof(samples[0])); num_samples_read = num_bytes_read / sizeof(samples[0]); } RTC_CHECK(num_samples_read == 0 || (num_bytes_read % num_samples_read) == 0) << "Corrupt file: file ended in the middle of a sample."; RTC_CHECK(num_samples_read == chunk_size || file_.ReadEof()) << "Corrupt file: payload size does not match header."; next_chunk_start += num_samples_read; num_unread_samples_ -= num_samples_read; num_samples_left_to_read -= num_samples_read; } return num_samples - num_samples_left_to_read; } size_t WavReader::ReadSamples(const size_t num_samples, float* const samples) { #ifndef WEBRTC_ARCH_LITTLE_ENDIAN #error "Need to convert samples to big-endian when reading from WAV file" #endif size_t num_samples_left_to_read = num_samples; size_t next_chunk_start = 0; while (num_samples_left_to_read > 0 && num_unread_samples_ > 0) { const size_t chunk_size = std::min( std::min(kMaxChunksize, num_samples_left_to_read), num_unread_samples_); size_t num_bytes_read; size_t num_samples_read; if (format_ == WavFormat::kWavFormatPcm) { std::array samples_to_convert; num_bytes_read = file_.Read(samples_to_convert.data(), chunk_size * sizeof(samples_to_convert[0])); num_samples_read = num_bytes_read / sizeof(samples_to_convert[0]); for (size_t j = 0; j < num_samples_read; ++j) { samples[next_chunk_start + j] = static_cast(samples_to_convert[j]); } } else { RTC_CHECK_EQ(format_, WavFormat::kWavFormatIeeeFloat); num_bytes_read = file_.Read(&samples[next_chunk_start], chunk_size * sizeof(samples[0])); num_samples_read = num_bytes_read / sizeof(samples[0]); for (size_t j = 0; j < num_samples_read; ++j) { samples[next_chunk_start + j] = FloatToFloatS16(samples[next_chunk_start + j]); } } RTC_CHECK(num_samples_read == 0 || (num_bytes_read % num_samples_read) == 0) << "Corrupt file: file ended in the middle of a sample."; RTC_CHECK(num_samples_read == chunk_size || file_.ReadEof()) << "Corrupt file: payload size does not match header."; next_chunk_start += num_samples_read; num_unread_samples_ -= num_samples_read; num_samples_left_to_read -= num_samples_read; } return num_samples - num_samples_left_to_read; } void WavReader::Close() { file_.Close(); } WavWriter::WavWriter(const std::string& filename, int sample_rate, size_t num_channels, SampleFormat sample_format) // Unlike plain fopen, OpenWriteOnly takes care of filename utf8 -> // wchar conversion on windows. : WavWriter(FileWrapper::OpenWriteOnly(filename), sample_rate, num_channels, sample_format) {} WavWriter::WavWriter(FileWrapper file, int sample_rate, size_t num_channels, SampleFormat sample_format) : sample_rate_(sample_rate), num_channels_(num_channels), num_samples_written_(0), format_(sample_format == SampleFormat::kInt16 ? WavFormat::kWavFormatPcm : WavFormat::kWavFormatIeeeFloat), file_(std::move(file)) { // Handle errors from the OpenWriteOnly call in above constructor. RTC_CHECK(file_.is_open()) << "Invalid file. Could not create wav file."; RTC_CHECK(CheckWavParameters(num_channels_, sample_rate_, format_, num_samples_written_)); // Write a blank placeholder header, since we need to know the total number // of samples before we can fill in the real data. static const uint8_t blank_header[MaxWavHeaderSize()] = {0}; RTC_CHECK(file_.Write(blank_header, WavHeaderSize(format_))); } void WavWriter::WriteSamples(const int16_t* samples, size_t num_samples) { #ifndef WEBRTC_ARCH_LITTLE_ENDIAN #error "Need to convert samples to little-endian when writing to WAV file" #endif for (size_t i = 0; i < num_samples; i += kMaxChunksize) { const size_t num_remaining_samples = num_samples - i; const size_t num_samples_to_write = std::min(kMaxChunksize, num_remaining_samples); if (format_ == WavFormat::kWavFormatPcm) { RTC_CHECK( file_.Write(&samples[i], num_samples_to_write * sizeof(samples[0]))); } else { RTC_CHECK_EQ(format_, WavFormat::kWavFormatIeeeFloat); std::array converted_samples; for (size_t j = 0; j < num_samples_to_write; ++j) { converted_samples[j] = S16ToFloat(samples[i + j]); } RTC_CHECK( file_.Write(converted_samples.data(), num_samples_to_write * sizeof(converted_samples[0]))); } num_samples_written_ += num_samples_to_write; RTC_CHECK_GE(num_samples_written_, num_samples_to_write); // detect size_t overflow } } void WavWriter::WriteSamples(const float* samples, size_t num_samples) { #ifndef WEBRTC_ARCH_LITTLE_ENDIAN #error "Need to convert samples to little-endian when writing to WAV file" #endif for (size_t i = 0; i < num_samples; i += kMaxChunksize) { const size_t num_remaining_samples = num_samples - i; const size_t num_samples_to_write = std::min(kMaxChunksize, num_remaining_samples); if (format_ == WavFormat::kWavFormatPcm) { std::array converted_samples; for (size_t j = 0; j < num_samples_to_write; ++j) { converted_samples[j] = FloatS16ToS16(samples[i + j]); } RTC_CHECK( file_.Write(converted_samples.data(), num_samples_to_write * sizeof(converted_samples[0]))); } else { RTC_CHECK_EQ(format_, WavFormat::kWavFormatIeeeFloat); std::array converted_samples; for (size_t j = 0; j < num_samples_to_write; ++j) { converted_samples[j] = FloatS16ToFloat(samples[i + j]); } RTC_CHECK( file_.Write(converted_samples.data(), num_samples_to_write * sizeof(converted_samples[0]))); } num_samples_written_ += num_samples_to_write; RTC_CHECK(num_samples_written_ >= num_samples_to_write); // detect size_t overflow } } void WavWriter::Close() { RTC_CHECK(file_.Rewind()); std::array header; size_t header_size; WriteWavHeader(num_channels_, sample_rate_, format_, num_samples_written_, header.data(), &header_size); RTC_CHECK(file_.Write(header.data(), header_size)); RTC_CHECK(file_.Close()); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/wav_file.h0000664000175000017500000000675314475643423022605 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_WAV_FILE_H_ #define COMMON_AUDIO_WAV_FILE_H_ #include #include #include #include "common_audio/wav_header.h" #include "rtc_base/system/file_wrapper.h" namespace webrtc { // Interface to provide access WAV file parameters. class WavFile { public: enum class SampleFormat { kInt16, kFloat }; virtual ~WavFile() {} virtual int sample_rate() const = 0; virtual size_t num_channels() const = 0; virtual size_t num_samples() const = 0; }; // Simple C++ class for writing 16-bit integer and 32 bit floating point PCM WAV // files. All error handling is by calls to RTC_CHECK(), making it unsuitable // for anything but debug code. class WavWriter final : public WavFile { public: // Opens a new WAV file for writing. WavWriter(const std::string& filename, int sample_rate, size_t num_channels, SampleFormat sample_format = SampleFormat::kInt16); WavWriter(FileWrapper file, int sample_rate, size_t num_channels, SampleFormat sample_format = SampleFormat::kInt16); // Closes the WAV file, after writing its header. ~WavWriter() { Close(); } WavWriter(const WavWriter&) = delete; WavWriter& operator=(const WavWriter&) = delete; // Write additional samples to the file. Each sample is in the range // [-32768.0,32767.0], and there must be the previously specified number of // interleaved channels. void WriteSamples(const float* samples, size_t num_samples); void WriteSamples(const int16_t* samples, size_t num_samples); int sample_rate() const override { return sample_rate_; } size_t num_channels() const override { return num_channels_; } size_t num_samples() const override { return num_samples_written_; } private: void Close(); const int sample_rate_; const size_t num_channels_; size_t num_samples_written_; WavFormat format_; FileWrapper file_; }; // Follows the conventions of WavWriter. class WavReader final : public WavFile { public: // Opens an existing WAV file for reading. explicit WavReader(const std::string& filename); explicit WavReader(FileWrapper file); // Close the WAV file. ~WavReader() { Close(); } WavReader(const WavReader&) = delete; WavReader& operator=(const WavReader&) = delete; // Resets position to the beginning of the file. void Reset(); // Returns the number of samples read. If this is less than requested, // verifies that the end of the file was reached. size_t ReadSamples(size_t num_samples, float* samples); size_t ReadSamples(size_t num_samples, int16_t* samples); int sample_rate() const override { return sample_rate_; } size_t num_channels() const override { return num_channels_; } size_t num_samples() const override { return num_samples_in_file_; } private: void Close(); int sample_rate_; size_t num_channels_; WavFormat format_; size_t num_samples_in_file_; size_t num_unread_samples_; FileWrapper file_; int64_t data_start_pos_; // Position in the file immediately after WAV header. }; } // namespace webrtc #endif // COMMON_AUDIO_WAV_FILE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/wav_header.cc0000664000175000017500000003574414475643423023256 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Based on the WAV file format documentation at // https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ and // http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html #include "common_audio/wav_header.h" #include #include #include #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/sanitizer.h" #include "rtc_base/system/arch.h" namespace webrtc { namespace { #ifndef WEBRTC_ARCH_LITTLE_ENDIAN #error "Code not working properly for big endian platforms." #endif #pragma pack(2) struct ChunkHeader { uint32_t ID; uint32_t Size; }; static_assert(sizeof(ChunkHeader) == 8, "ChunkHeader size"); #pragma pack(2) struct RiffHeader { ChunkHeader header; uint32_t Format; }; static_assert(sizeof(RiffHeader) == sizeof(ChunkHeader) + 4, "RiffHeader size"); // We can't nest this definition in WavHeader, because VS2013 gives an error // on sizeof(WavHeader::fmt): "error C2070: 'unknown': illegal sizeof operand". #pragma pack(2) struct FmtPcmSubchunk { ChunkHeader header; uint16_t AudioFormat; uint16_t NumChannels; uint32_t SampleRate; uint32_t ByteRate; uint16_t BlockAlign; uint16_t BitsPerSample; }; static_assert(sizeof(FmtPcmSubchunk) == 24, "FmtPcmSubchunk size"); const uint32_t kFmtPcmSubchunkSize = sizeof(FmtPcmSubchunk) - sizeof(ChunkHeader); // Pack struct to avoid additional padding bytes. #pragma pack(2) struct FmtIeeeFloatSubchunk { ChunkHeader header; uint16_t AudioFormat; uint16_t NumChannels; uint32_t SampleRate; uint32_t ByteRate; uint16_t BlockAlign; uint16_t BitsPerSample; uint16_t ExtensionSize; }; static_assert(sizeof(FmtIeeeFloatSubchunk) == 26, "FmtIeeeFloatSubchunk size"); const uint32_t kFmtIeeeFloatSubchunkSize = sizeof(FmtIeeeFloatSubchunk) - sizeof(ChunkHeader); // Simple PCM wav header. It does not include chunks that are not essential to // read audio samples. #pragma pack(2) struct WavHeaderPcm { WavHeaderPcm(const WavHeaderPcm&) = default; WavHeaderPcm& operator=(const WavHeaderPcm&) = default; RiffHeader riff; FmtPcmSubchunk fmt; struct { ChunkHeader header; } data; }; static_assert(sizeof(WavHeaderPcm) == kPcmWavHeaderSize, "no padding in header"); // IEEE Float Wav header, includes extra chunks necessary for proper non-PCM // WAV implementation. #pragma pack(2) struct WavHeaderIeeeFloat { WavHeaderIeeeFloat(const WavHeaderIeeeFloat&) = default; WavHeaderIeeeFloat& operator=(const WavHeaderIeeeFloat&) = default; RiffHeader riff; FmtIeeeFloatSubchunk fmt; struct { ChunkHeader header; uint32_t SampleLength; } fact; struct { ChunkHeader header; } data; }; static_assert(sizeof(WavHeaderIeeeFloat) == kIeeeFloatWavHeaderSize, "no padding in header"); uint32_t PackFourCC(char a, char b, char c, char d) { uint32_t packed_value = static_cast(a) | static_cast(b) << 8 | static_cast(c) << 16 | static_cast(d) << 24; return packed_value; } std::string ReadFourCC(uint32_t x) { return std::string(reinterpret_cast(&x), 4); } uint16_t MapWavFormatToHeaderField(WavFormat format) { switch (format) { case WavFormat::kWavFormatPcm: return 1; case WavFormat::kWavFormatIeeeFloat: return 3; case WavFormat::kWavFormatALaw: return 6; case WavFormat::kWavFormatMuLaw: return 7; } RTC_CHECK(false); } WavFormat MapHeaderFieldToWavFormat(uint16_t format_header_value) { if (format_header_value == 1) { return WavFormat::kWavFormatPcm; } if (format_header_value == 3) { return WavFormat::kWavFormatIeeeFloat; } RTC_CHECK(false) << "Unsupported WAV format"; } uint32_t RiffChunkSize(size_t bytes_in_payload, size_t header_size) { return static_cast(bytes_in_payload + header_size - sizeof(ChunkHeader)); } uint32_t ByteRate(size_t num_channels, int sample_rate, size_t bytes_per_sample) { return static_cast(num_channels * sample_rate * bytes_per_sample); } uint16_t BlockAlign(size_t num_channels, size_t bytes_per_sample) { return static_cast(num_channels * bytes_per_sample); } // Finds a chunk having the sought ID. If found, then |readable| points to the // first byte of the sought chunk data. If not found, the end of the file is // reached. bool FindWaveChunk(ChunkHeader* chunk_header, WavHeaderReader* readable, const std::string sought_chunk_id) { RTC_DCHECK_EQ(sought_chunk_id.size(), 4); while (true) { if (readable->Read(chunk_header, sizeof(*chunk_header)) != sizeof(*chunk_header)) return false; // EOF. if (ReadFourCC(chunk_header->ID) == sought_chunk_id) return true; // Sought chunk found. // Ignore current chunk by skipping its payload. if (!readable->SeekForward(chunk_header->Size)) return false; // EOF or error. } } bool ReadFmtChunkData(FmtPcmSubchunk* fmt_subchunk, WavHeaderReader* readable) { // Reads "fmt " chunk payload. if (readable->Read(&(fmt_subchunk->AudioFormat), kFmtPcmSubchunkSize) != kFmtPcmSubchunkSize) return false; const uint32_t fmt_size = fmt_subchunk->header.Size; if (fmt_size != kFmtPcmSubchunkSize) { // There is an optional two-byte extension field permitted to be present // with PCM, but which must be zero. int16_t ext_size; if (kFmtPcmSubchunkSize + sizeof(ext_size) != fmt_size) return false; if (readable->Read(&ext_size, sizeof(ext_size)) != sizeof(ext_size)) return false; if (ext_size != 0) return false; } return true; } void WritePcmWavHeader(size_t num_channels, int sample_rate, size_t bytes_per_sample, size_t num_samples, uint8_t* buf, size_t* header_size) { RTC_CHECK(buf); RTC_CHECK(header_size); *header_size = kPcmWavHeaderSize; auto header = rtc::MsanUninitialized({}); const size_t bytes_in_payload = bytes_per_sample * num_samples; header.riff.header.ID = PackFourCC('R', 'I', 'F', 'F'); header.riff.header.Size = RiffChunkSize(bytes_in_payload, *header_size); header.riff.Format = PackFourCC('W', 'A', 'V', 'E'); header.fmt.header.ID = PackFourCC('f', 'm', 't', ' '); header.fmt.header.Size = kFmtPcmSubchunkSize; header.fmt.AudioFormat = MapWavFormatToHeaderField(WavFormat::kWavFormatPcm); header.fmt.NumChannels = static_cast(num_channels); header.fmt.SampleRate = sample_rate; header.fmt.ByteRate = ByteRate(num_channels, sample_rate, bytes_per_sample); header.fmt.BlockAlign = BlockAlign(num_channels, bytes_per_sample); header.fmt.BitsPerSample = static_cast(8 * bytes_per_sample); header.data.header.ID = PackFourCC('d', 'a', 't', 'a'); header.data.header.Size = static_cast(bytes_in_payload); // Do an extra copy rather than writing everything to buf directly, since buf // might not be correctly aligned. memcpy(buf, &header, *header_size); } void WriteIeeeFloatWavHeader(size_t num_channels, int sample_rate, size_t bytes_per_sample, size_t num_samples, uint8_t* buf, size_t* header_size) { RTC_CHECK(buf); RTC_CHECK(header_size); *header_size = kIeeeFloatWavHeaderSize; auto header = rtc::MsanUninitialized({}); const size_t bytes_in_payload = bytes_per_sample * num_samples; header.riff.header.ID = PackFourCC('R', 'I', 'F', 'F'); header.riff.header.Size = RiffChunkSize(bytes_in_payload, *header_size); header.riff.Format = PackFourCC('W', 'A', 'V', 'E'); header.fmt.header.ID = PackFourCC('f', 'm', 't', ' '); header.fmt.header.Size = kFmtIeeeFloatSubchunkSize; header.fmt.AudioFormat = MapWavFormatToHeaderField(WavFormat::kWavFormatIeeeFloat); header.fmt.NumChannels = static_cast(num_channels); header.fmt.SampleRate = sample_rate; header.fmt.ByteRate = ByteRate(num_channels, sample_rate, bytes_per_sample); header.fmt.BlockAlign = BlockAlign(num_channels, bytes_per_sample); header.fmt.BitsPerSample = static_cast(8 * bytes_per_sample); header.fmt.ExtensionSize = 0; header.fact.header.ID = PackFourCC('f', 'a', 'c', 't'); header.fact.header.Size = 4; header.fact.SampleLength = static_cast(num_channels * num_samples); header.data.header.ID = PackFourCC('d', 'a', 't', 'a'); header.data.header.Size = static_cast(bytes_in_payload); // Do an extra copy rather than writing everything to buf directly, since buf // might not be correctly aligned. memcpy(buf, &header, *header_size); } // Returns the number of bytes per sample for the format. size_t GetFormatBytesPerSample(WavFormat format) { switch (format) { case WavFormat::kWavFormatPcm: // Other values may be OK, but for now we're conservative. return 2; case WavFormat::kWavFormatALaw: case WavFormat::kWavFormatMuLaw: return 1; case WavFormat::kWavFormatIeeeFloat: return 4; default: RTC_CHECK(false); return 2; } } bool CheckWavParameters(size_t num_channels, int sample_rate, WavFormat format, size_t bytes_per_sample, size_t num_samples) { // num_channels, sample_rate, and bytes_per_sample must be positive, must fit // in their respective fields, and their product must fit in the 32-bit // ByteRate field. if (num_channels == 0 || sample_rate <= 0 || bytes_per_sample == 0) return false; if (static_cast(sample_rate) > std::numeric_limits::max()) return false; if (num_channels > std::numeric_limits::max()) return false; if (static_cast(bytes_per_sample) * 8 > std::numeric_limits::max()) return false; if (static_cast(sample_rate) * num_channels * bytes_per_sample > std::numeric_limits::max()) return false; // format and bytes_per_sample must agree. switch (format) { case WavFormat::kWavFormatPcm: // Other values may be OK, but for now we're conservative: if (bytes_per_sample != 1 && bytes_per_sample != 2) return false; break; case WavFormat::kWavFormatALaw: case WavFormat::kWavFormatMuLaw: if (bytes_per_sample != 1) return false; break; case WavFormat::kWavFormatIeeeFloat: if (bytes_per_sample != 4) return false; break; default: return false; } // The number of bytes in the file, not counting the first ChunkHeader, must // be less than 2^32; otherwise, the ChunkSize field overflows. const size_t header_size = kPcmWavHeaderSize - sizeof(ChunkHeader); const size_t max_samples = (std::numeric_limits::max() - header_size) / bytes_per_sample; if (num_samples > max_samples) return false; // Each channel must have the same number of samples. if (num_samples % num_channels != 0) return false; return true; } } // namespace bool CheckWavParameters(size_t num_channels, int sample_rate, WavFormat format, size_t num_samples) { return CheckWavParameters(num_channels, sample_rate, format, GetFormatBytesPerSample(format), num_samples); } void WriteWavHeader(size_t num_channels, int sample_rate, WavFormat format, size_t num_samples, uint8_t* buf, size_t* header_size) { RTC_CHECK(buf); RTC_CHECK(header_size); const size_t bytes_per_sample = GetFormatBytesPerSample(format); RTC_CHECK(CheckWavParameters(num_channels, sample_rate, format, bytes_per_sample, num_samples)); if (format == WavFormat::kWavFormatPcm) { WritePcmWavHeader(num_channels, sample_rate, bytes_per_sample, num_samples, buf, header_size); } else { RTC_CHECK_EQ(format, WavFormat::kWavFormatIeeeFloat); WriteIeeeFloatWavHeader(num_channels, sample_rate, bytes_per_sample, num_samples, buf, header_size); } } bool ReadWavHeader(WavHeaderReader* readable, size_t* num_channels, int* sample_rate, WavFormat* format, size_t* bytes_per_sample, size_t* num_samples, int64_t* data_start_pos) { // Read using the PCM header, even though it might be float Wav file auto header = rtc::MsanUninitialized({}); // Read RIFF chunk. if (readable->Read(&header.riff, sizeof(header.riff)) != sizeof(header.riff)) return false; if (ReadFourCC(header.riff.header.ID) != "RIFF") return false; if (ReadFourCC(header.riff.Format) != "WAVE") return false; // Find "fmt " and "data" chunks. While the official Wave file specification // does not put requirements on the chunks order, it is uncommon to find the // "data" chunk before the "fmt " one. The code below fails if this is not the // case. if (!FindWaveChunk(&header.fmt.header, readable, "fmt ")) { RTC_LOG(LS_ERROR) << "Cannot find 'fmt ' chunk."; return false; } if (!ReadFmtChunkData(&header.fmt, readable)) { RTC_LOG(LS_ERROR) << "Cannot read 'fmt ' chunk."; return false; } if (!FindWaveChunk(&header.data.header, readable, "data")) { RTC_LOG(LS_ERROR) << "Cannot find 'data' chunk."; return false; } // Parse needed fields. *format = MapHeaderFieldToWavFormat(header.fmt.AudioFormat); *num_channels = header.fmt.NumChannels; *sample_rate = header.fmt.SampleRate; *bytes_per_sample = header.fmt.BitsPerSample / 8; const size_t bytes_in_payload = header.data.header.Size; if (*bytes_per_sample == 0) return false; *num_samples = bytes_in_payload / *bytes_per_sample; const size_t header_size = *format == WavFormat::kWavFormatPcm ? kPcmWavHeaderSize : kIeeeFloatWavHeaderSize; if (header.riff.header.Size < RiffChunkSize(bytes_in_payload, header_size)) return false; if (header.fmt.ByteRate != ByteRate(*num_channels, *sample_rate, *bytes_per_sample)) return false; if (header.fmt.BlockAlign != BlockAlign(*num_channels, *bytes_per_sample)) return false; if (!CheckWavParameters(*num_channels, *sample_rate, *format, *bytes_per_sample, *num_samples)) { return false; } *data_start_pos = readable->GetPosition(); return true; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/wav_header.h0000664000175000017500000000624214475643423023107 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_WAV_HEADER_H_ #define COMMON_AUDIO_WAV_HEADER_H_ #include #include #include #include "rtc_base/checks.h" namespace webrtc { // Interface providing header reading functionality. class WavHeaderReader { public: // Returns the number of bytes read. virtual size_t Read(void* buf, size_t num_bytes) = 0; virtual bool SeekForward(uint32_t num_bytes) = 0; virtual ~WavHeaderReader() = default; virtual int64_t GetPosition() = 0; }; // Possible WAV formats. enum class WavFormat { kWavFormatPcm = 1, // PCM, each sample of size bytes_per_sample. kWavFormatIeeeFloat = 3, // IEEE float. kWavFormatALaw = 6, // 8-bit ITU-T G.711 A-law. kWavFormatMuLaw = 7, // 8-bit ITU-T G.711 mu-law. }; // Header sizes for supported WAV formats. constexpr size_t kPcmWavHeaderSize = 44; constexpr size_t kIeeeFloatWavHeaderSize = 58; // Returns the size of the WAV header for the specified format. constexpr size_t WavHeaderSize(WavFormat format) { if (format == WavFormat::kWavFormatPcm) { return kPcmWavHeaderSize; } RTC_CHECK_EQ(format, WavFormat::kWavFormatIeeeFloat); return kIeeeFloatWavHeaderSize; } // Returns the maximum size of the supported WAV formats. constexpr size_t MaxWavHeaderSize() { return std::max(WavHeaderSize(WavFormat::kWavFormatPcm), WavHeaderSize(WavFormat::kWavFormatIeeeFloat)); } // Return true if the given parameters will make a well-formed WAV header. bool CheckWavParameters(size_t num_channels, int sample_rate, WavFormat format, size_t num_samples); // Write a kWavHeaderSize bytes long WAV header to buf. The payload that // follows the header is supposed to have the specified number of interleaved // channels and contain the specified total number of samples of the specified // type. The size of the header is returned in header_size. CHECKs the input // parameters for validity. void WriteWavHeader(size_t num_channels, int sample_rate, WavFormat format, size_t num_samples, uint8_t* buf, size_t* header_size); // Read a WAV header from an implemented WavHeaderReader and parse the values // into the provided output parameters. WavHeaderReader is used because the // header can be variably sized. Returns false if the header is invalid. bool ReadWavHeader(WavHeaderReader* readable, size_t* num_channels, int* sample_rate, WavFormat* format, size_t* bytes_per_sample, size_t* num_samples, int64_t* data_start_pos); } // namespace webrtc #endif // COMMON_AUDIO_WAV_HEADER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/window_generator.cc0000664000175000017500000000373714475643423024523 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #define _USE_MATH_DEFINES #include "common_audio/window_generator.h" #include #include #include "rtc_base/checks.h" using std::complex; namespace { // Modified Bessel function of order 0 for complex inputs. complex I0(complex x) { complex y = x / 3.75f; y *= y; return 1.0f + y * (3.5156229f + y * (3.0899424f + y * (1.2067492f + y * (0.2659732f + y * (0.360768e-1f + y * 0.45813e-2f))))); } } // namespace namespace webrtc { void WindowGenerator::Hanning(int length, float* window) { RTC_CHECK_GT(length, 1); RTC_CHECK(window != nullptr); for (int i = 0; i < length; ++i) { window[i] = 0.5f * (1 - cosf(2 * static_cast(M_PI) * i / (length - 1))); } } void WindowGenerator::KaiserBesselDerived(float alpha, size_t length, float* window) { RTC_CHECK_GT(length, 1U); RTC_CHECK(window != nullptr); const size_t half = (length + 1) / 2; float sum = 0.0f; for (size_t i = 0; i <= half; ++i) { complex r = (4.0f * i) / length - 1.0f; sum += I0(static_cast(M_PI) * alpha * sqrt(1.0f - r * r)).real(); window[i] = sum; } for (size_t i = length - 1; i >= half; --i) { window[length - i - 1] = sqrtf(window[length - i - 1] / sum); window[i] = window[length - i - 1]; } if (length % 2 == 1) { window[half - 1] = sqrtf(window[half - 1] / sum); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/common_audio/window_generator.h0000664000175000017500000000173314475643423024357 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef COMMON_AUDIO_WINDOW_GENERATOR_H_ #define COMMON_AUDIO_WINDOW_GENERATOR_H_ #include namespace webrtc { // Helper class with generators for various signal transform windows. class WindowGenerator { public: WindowGenerator() = delete; WindowGenerator(const WindowGenerator&) = delete; WindowGenerator& operator=(const WindowGenerator&) = delete; static void Hanning(int length, float* window); static void KaiserBesselDerived(float alpha, size_t length, float* window); }; } // namespace webrtc #endif // COMMON_AUDIO_WINDOW_GENERATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/meson.build0000664000175000017500000000030714475643423020316 0ustar00arunarunwebrtc_inc = include_directories('.') subdir('rtc_base') subdir('api') subdir('system_wrappers') subdir('common_audio') subdir('third_party/pffft') subdir('third_party/rnnoise') subdir('modules') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/0000775000175000017500000000000014475643423017624 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/BUILD.gn0000664000175000017500000002367214475643423021023 0ustar00arunarun# Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../webrtc.gni") import("audio_coding/audio_coding.gni") group("modules") { deps = [ "audio_coding", "audio_device", "audio_mixer", "audio_processing", "congestion_controller", "pacing", "remote_bitrate_estimator", "rtp_rtcp", "utility", "video_coding", "video_processing", ] if (rtc_desktop_capture_supported) { deps += [ "desktop_capture" ] } } rtc_source_set("module_api_public") { sources = [ "include/module_common_types_public.h" ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_source_set("module_api") { visibility = [ "*" ] sources = [ "include/module.h", "include/module_common_types.h", ] } rtc_source_set("module_fec_api") { visibility = [ "*" ] sources = [ "include/module_fec_types.h" ] } if (rtc_include_tests) { modules_tests_resources = [ "../resources/audio_coding/testfile16kHz.pcm", "../resources/audio_coding/testfile32kHz.pcm", "../resources/audio_coding/teststereo32kHz.pcm", "../resources/foreman_cif.yuv", ] if (is_ios) { bundle_data("modules_tests_bundle_data") { testonly = true sources = modules_tests_resources outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ] } } rtc_test("modules_tests") { testonly = true deps = [ "../test:test_main", "../test:video_test_common", "audio_coding:audio_coding_modules_tests", "rtp_rtcp:rtp_rtcp_modules_tests", "video_coding:video_coding_modules_tests", "//testing/gtest", ] if (rtc_desktop_capture_supported) { deps += [ "desktop_capture:desktop_capture_modules_tests" ] } data = modules_tests_resources if (is_android) { deps += [ # NOTE(brandtr): Including Java classes seems only to be possible from # rtc_test targets. Therefore we include this target here, instead of # in video_coding_modules_tests, where it is actually used. "../sdk/android:libjingle_peerconnection_java", "//testing/android/native_test:native_test_native_code", ] shard_timeout = 900 } if (is_ios) { deps += [ ":modules_tests_bundle_data" ] } } modules_unittests_resources = [ "../resources/audio_coding/neteq_opus.rtp", "../resources/audio_coding/neteq_opus_dtx.rtp", "../resources/audio_coding/neteq_universal_new.rtp", "../resources/audio_coding/speech_4_channels_48k_one_second.wav", "../resources/audio_coding/speech_mono_16kHz.pcm", "../resources/audio_coding/speech_mono_32_48kHz.pcm", "../resources/audio_coding/testfile16kHz.pcm", "../resources/audio_coding/testfile32kHz.pcm", "../resources/audio_coding/testfile_fake_stereo_32kHz.pcm", "../resources/audio_coding/teststereo32kHz.pcm", "../resources/audio_device/audio_short16.pcm", "../resources/audio_device/audio_short44.pcm", "../resources/audio_device/audio_short48.pcm", "../resources/audio_processing/agc/agc_audio.pcm", "../resources/audio_processing/agc/agc_no_circular_buffer.dat", "../resources/audio_processing/agc/agc_pitch_gain.dat", "../resources/audio_processing/agc/agc_pitch_lag.dat", "../resources/audio_processing/agc/agc_spectral_peak.dat", "../resources/audio_processing/agc/agc_vad.dat", "../resources/audio_processing/agc/agc_voicing_prob.dat", "../resources/audio_processing/agc/agc_with_circular_buffer.dat", "../resources/audio_processing/output_data_fixed.pb", "../resources/audio_processing/output_data_float.pb", "../resources/audio_processing/output_data_float_avx2.pb", "../resources/audio_processing/output_data_mac.pb", "../resources/audio_processing/transient/ajm-macbook-1-spke16m.pcm", "../resources/audio_processing/transient/audio16kHz.pcm", "../resources/audio_processing/transient/audio32kHz.pcm", "../resources/audio_processing/transient/audio48kHz.pcm", "../resources/audio_processing/transient/audio8kHz.pcm", "../resources/audio_processing/transient/detect16kHz.dat", "../resources/audio_processing/transient/detect32kHz.dat", "../resources/audio_processing/transient/detect48kHz.dat", "../resources/audio_processing/transient/detect8kHz.dat", "../resources/audio_processing/transient/double-utils.dat", "../resources/audio_processing/transient/float-utils.dat", "../resources/audio_processing/transient/suppressed16kHz.pcm", "../resources/audio_processing/transient/suppressed32kHz.pcm", "../resources/audio_processing/transient/suppressed8kHz.pcm", "../resources/audio_processing/transient/wpd0.dat", "../resources/audio_processing/transient/wpd1.dat", "../resources/audio_processing/transient/wpd2.dat", "../resources/audio_processing/transient/wpd3.dat", "../resources/audio_processing/transient/wpd4.dat", "../resources/audio_processing/transient/wpd5.dat", "../resources/audio_processing/transient/wpd6.dat", "../resources/audio_processing/transient/wpd7.dat", "../resources/deflicker_before_cif_short.yuv", "../resources/far16_stereo.pcm", "../resources/far32_stereo.pcm", "../resources/far44_stereo.pcm", "../resources/far48_stereo.pcm", "../resources/far8_stereo.pcm", "../resources/foremanColorEnhanced_cif_short.yuv", "../resources/foreman_cif.yuv", "../resources/foreman_cif_short.yuv", "../resources/near16_stereo.pcm", "../resources/near32_stereo.pcm", "../resources/near44_stereo.pcm", "../resources/near48_stereo.pcm", "../resources/near8_stereo.pcm", "../resources/ref03.aecdump", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke1_0_AST.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke1_0_TOF.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke1_1_AST.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke1_1_TOF.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke2_0_AST.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke2_0_TOF.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke2_1_AST.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke2_1_TOF.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingDelay1_0_AST.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingDelay1_0_TOF.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingLoss1_0_AST.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingLoss1_0_TOF.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_Multi1_1_AST.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_Multi1_1_TOF.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyChoke_0_AST.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyChoke_0_TOF.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyChoke_1_AST.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyChoke_1_TOF.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyDelay_0_AST.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyDelay_0_TOF.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyLoss_0_AST.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyLoss_0_TOF.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_UnlimitedSpeed_0_AST.bin", "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_UnlimitedSpeed_0_TOF.bin", "../resources/short_mixed_mono_48.dat", "../resources/short_mixed_mono_48.pcm", "../resources/short_mixed_mono_48_arm.dat", "../resources/short_mixed_stereo_48.dat", "../resources/short_mixed_stereo_48.pcm", "../resources/voice_engine/audio_tiny48.wav", ] if (is_ios) { bundle_data("modules_unittests_bundle_data") { testonly = true sources = modules_unittests_resources outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ] } } rtc_test("modules_unittests") { testonly = true defines = [] sources = [ "module_common_types_unittest.cc" ] deps = [ ":module_api", ":module_api_public", "../test:test_main", "../test:test_support", "audio_coding:audio_coding_unittests", "audio_device:audio_device_unittests", "audio_mixer:audio_mixer_unittests", "audio_processing:audio_processing_unittests", "audio_processing/aec3:aec3_unittests", "audio_processing/ns:ns_unittests", "congestion_controller:congestion_controller_unittests", "pacing:pacing_unittests", "remote_bitrate_estimator:remote_bitrate_estimator_unittests", "rtp_rtcp:rtp_rtcp_unittests", "utility:utility_unittests", "video_coding:video_coding_unittests", "video_processing:video_processing_unittests", ] if (rtc_desktop_capture_supported) { deps += [ "desktop_capture:desktop_capture_unittests" ] } data = modules_unittests_resources if (is_android) { deps += [ "../sdk/android:libjingle_peerconnection_java", "//testing/android/native_test:native_test_support", ] shard_timeout = 900 } if (is_ios) { info_plist = "../test/ios/Info.plist" deps += [ ":modules_unittests_bundle_data" ] configs += [ "..:common_objc" ] ldflags = [ "-ObjC" ] } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/0000775000175000017500000000000014475643423022250 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/BUILD.gn0000664000175000017500000017213514475643423023446 0ustar00arunarun# Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../../webrtc.gni") import("audio_coding.gni") if (rtc_enable_protobuf) { import("//third_party/protobuf/proto_library.gni") } visibility = [ ":*" ] rtc_source_set("audio_coding_module_typedefs") { visibility += [ "*" ] sources = [ "include/audio_coding_module_typedefs.h" ] deps = [ "../../rtc_base:deprecation" ] } rtc_library("audio_coding") { visibility += [ "*" ] sources = [ "acm2/acm_receiver.cc", "acm2/acm_receiver.h", "acm2/acm_remixing.cc", "acm2/acm_remixing.h", "acm2/acm_resampler.cc", "acm2/acm_resampler.h", "acm2/audio_coding_module.cc", "acm2/call_statistics.cc", "acm2/call_statistics.h", "include/audio_coding_module.h", ] defines = [] deps = [ ":audio_coding_module_typedefs", ":default_neteq_factory", ":neteq", "..:module_api", "..:module_api_public", "../../api:array_view", "../../api:function_view", "../../api/audio:audio_frame_api", "../../api/audio_codecs:audio_codecs_api", "../../api/neteq:neteq_api", "../../common_audio", "../../common_audio:common_audio_c", "../../rtc_base:audio_format_to_string", "../../rtc_base:checks", "../../rtc_base:deprecation", "../../rtc_base:rtc_base_approved", "../../rtc_base/synchronization:mutex", "../../system_wrappers", "../../system_wrappers:metrics", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] } rtc_library("legacy_encoded_audio_frame") { sources = [ "codecs/legacy_encoded_audio_frame.cc", "codecs/legacy_encoded_audio_frame.h", ] deps = [ "../../api:array_view", "../../api/audio_codecs:audio_codecs_api", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("webrtc_cng") { visibility += webrtc_default_visibility sources = [ "codecs/cng/webrtc_cng.cc", "codecs/cng/webrtc_cng.h", ] deps = [ "../../api:array_view", "../../common_audio:common_audio_c", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../../rtc_base:safe_conversions", ] } rtc_library("audio_encoder_cng") { visibility += [ "*" ] sources = [ "codecs/cng/audio_encoder_cng.cc", "codecs/cng/audio_encoder_cng.h", ] deps = [ ":webrtc_cng", "../../api/audio_codecs:audio_codecs_api", "../../api/units:time_delta", "../../common_audio", "../../rtc_base:checks", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("red") { visibility += [ "*" ] sources = [ "codecs/red/audio_encoder_copy_red.cc", "codecs/red/audio_encoder_copy_red.h", ] deps = [ "../../api:array_view", "../../api/audio_codecs:audio_codecs_api", "../../api/units:time_delta", "../../common_audio", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("g711") { visibility += [ "*" ] poisonous = [ "audio_codecs" ] sources = [ "codecs/g711/audio_decoder_pcm.cc", "codecs/g711/audio_decoder_pcm.h", "codecs/g711/audio_encoder_pcm.cc", "codecs/g711/audio_encoder_pcm.h", ] deps = [ ":legacy_encoded_audio_frame", "../../api:array_view", "../../api/audio_codecs:audio_codecs_api", "../../api/units:time_delta", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] public_deps = [ ":g711_c" ] # no-presubmit-check TODO(webrtc:8603) } rtc_library("g711_c") { poisonous = [ "audio_codecs" ] sources = [ "codecs/g711/g711_interface.c", "codecs/g711/g711_interface.h", ] deps = [ "../third_party/g711:g711_3p" ] } rtc_library("g722") { visibility += [ "*" ] poisonous = [ "audio_codecs" ] sources = [ "codecs/g722/audio_decoder_g722.cc", "codecs/g722/audio_decoder_g722.h", "codecs/g722/audio_encoder_g722.cc", "codecs/g722/audio_encoder_g722.h", ] deps = [ ":legacy_encoded_audio_frame", "../../api:array_view", "../../api/audio_codecs:audio_codecs_api", "../../api/audio_codecs/g722:audio_encoder_g722_config", "../../api/units:time_delta", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] public_deps = [ ":g722_c" ] # no-presubmit-check TODO(webrtc:8603) } rtc_library("g722_c") { poisonous = [ "audio_codecs" ] sources = [ "codecs/g722/g722_interface.c", "codecs/g722/g722_interface.h", ] deps = [ "../third_party/g722:g722_3p" ] } rtc_library("ilbc") { visibility += webrtc_default_visibility poisonous = [ "audio_codecs" ] sources = [ "codecs/ilbc/audio_decoder_ilbc.cc", "codecs/ilbc/audio_decoder_ilbc.h", "codecs/ilbc/audio_encoder_ilbc.cc", "codecs/ilbc/audio_encoder_ilbc.h", ] deps = [ ":legacy_encoded_audio_frame", "../../api:array_view", "../../api/audio_codecs:audio_codecs_api", "../../api/audio_codecs/ilbc:audio_encoder_ilbc_config", "../../api/units:time_delta", "../../common_audio", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] public_deps = [ ":ilbc_c" ] # no-presubmit-check TODO(webrtc:8603) } rtc_library("ilbc_c") { poisonous = [ "audio_codecs" ] sources = [ "codecs/ilbc/abs_quant.c", "codecs/ilbc/abs_quant.h", "codecs/ilbc/abs_quant_loop.c", "codecs/ilbc/abs_quant_loop.h", "codecs/ilbc/augmented_cb_corr.c", "codecs/ilbc/augmented_cb_corr.h", "codecs/ilbc/bw_expand.c", "codecs/ilbc/bw_expand.h", "codecs/ilbc/cb_construct.c", "codecs/ilbc/cb_construct.h", "codecs/ilbc/cb_mem_energy.c", "codecs/ilbc/cb_mem_energy.h", "codecs/ilbc/cb_mem_energy_augmentation.c", "codecs/ilbc/cb_mem_energy_augmentation.h", "codecs/ilbc/cb_mem_energy_calc.c", "codecs/ilbc/cb_mem_energy_calc.h", "codecs/ilbc/cb_search.c", "codecs/ilbc/cb_search.h", "codecs/ilbc/cb_search_core.c", "codecs/ilbc/cb_search_core.h", "codecs/ilbc/cb_update_best_index.c", "codecs/ilbc/cb_update_best_index.h", "codecs/ilbc/chebyshev.c", "codecs/ilbc/chebyshev.h", "codecs/ilbc/comp_corr.c", "codecs/ilbc/comp_corr.h", "codecs/ilbc/constants.c", "codecs/ilbc/constants.h", "codecs/ilbc/create_augmented_vec.c", "codecs/ilbc/create_augmented_vec.h", "codecs/ilbc/decode.c", "codecs/ilbc/decode.h", "codecs/ilbc/decode_residual.c", "codecs/ilbc/decode_residual.h", "codecs/ilbc/decoder_interpolate_lsf.c", "codecs/ilbc/decoder_interpolate_lsf.h", "codecs/ilbc/defines.h", "codecs/ilbc/do_plc.c", "codecs/ilbc/do_plc.h", "codecs/ilbc/encode.c", "codecs/ilbc/encode.h", "codecs/ilbc/energy_inverse.c", "codecs/ilbc/energy_inverse.h", "codecs/ilbc/enh_upsample.c", "codecs/ilbc/enh_upsample.h", "codecs/ilbc/enhancer.c", "codecs/ilbc/enhancer.h", "codecs/ilbc/enhancer_interface.c", "codecs/ilbc/enhancer_interface.h", "codecs/ilbc/filtered_cb_vecs.c", "codecs/ilbc/filtered_cb_vecs.h", "codecs/ilbc/frame_classify.c", "codecs/ilbc/frame_classify.h", "codecs/ilbc/gain_dequant.c", "codecs/ilbc/gain_dequant.h", "codecs/ilbc/gain_quant.c", "codecs/ilbc/gain_quant.h", "codecs/ilbc/get_cd_vec.c", "codecs/ilbc/get_cd_vec.h", "codecs/ilbc/get_lsp_poly.c", "codecs/ilbc/get_lsp_poly.h", "codecs/ilbc/get_sync_seq.c", "codecs/ilbc/get_sync_seq.h", "codecs/ilbc/hp_input.c", "codecs/ilbc/hp_input.h", "codecs/ilbc/hp_output.c", "codecs/ilbc/hp_output.h", "codecs/ilbc/ilbc.c", "codecs/ilbc/ilbc.h", "codecs/ilbc/index_conv_dec.c", "codecs/ilbc/index_conv_dec.h", "codecs/ilbc/index_conv_enc.c", "codecs/ilbc/index_conv_enc.h", "codecs/ilbc/init_decode.c", "codecs/ilbc/init_decode.h", "codecs/ilbc/init_encode.c", "codecs/ilbc/init_encode.h", "codecs/ilbc/interpolate.c", "codecs/ilbc/interpolate.h", "codecs/ilbc/interpolate_samples.c", "codecs/ilbc/interpolate_samples.h", "codecs/ilbc/lpc_encode.c", "codecs/ilbc/lpc_encode.h", "codecs/ilbc/lsf_check.c", "codecs/ilbc/lsf_check.h", "codecs/ilbc/lsf_interpolate_to_poly_dec.c", "codecs/ilbc/lsf_interpolate_to_poly_dec.h", "codecs/ilbc/lsf_interpolate_to_poly_enc.c", "codecs/ilbc/lsf_interpolate_to_poly_enc.h", "codecs/ilbc/lsf_to_lsp.c", "codecs/ilbc/lsf_to_lsp.h", "codecs/ilbc/lsf_to_poly.c", "codecs/ilbc/lsf_to_poly.h", "codecs/ilbc/lsp_to_lsf.c", "codecs/ilbc/lsp_to_lsf.h", "codecs/ilbc/my_corr.c", "codecs/ilbc/my_corr.h", "codecs/ilbc/nearest_neighbor.c", "codecs/ilbc/nearest_neighbor.h", "codecs/ilbc/pack_bits.c", "codecs/ilbc/pack_bits.h", "codecs/ilbc/poly_to_lsf.c", "codecs/ilbc/poly_to_lsf.h", "codecs/ilbc/poly_to_lsp.c", "codecs/ilbc/poly_to_lsp.h", "codecs/ilbc/refiner.c", "codecs/ilbc/refiner.h", "codecs/ilbc/simple_interpolate_lsf.c", "codecs/ilbc/simple_interpolate_lsf.h", "codecs/ilbc/simple_lpc_analysis.c", "codecs/ilbc/simple_lpc_analysis.h", "codecs/ilbc/simple_lsf_dequant.c", "codecs/ilbc/simple_lsf_dequant.h", "codecs/ilbc/simple_lsf_quant.c", "codecs/ilbc/simple_lsf_quant.h", "codecs/ilbc/smooth.c", "codecs/ilbc/smooth.h", "codecs/ilbc/smooth_out_data.c", "codecs/ilbc/smooth_out_data.h", "codecs/ilbc/sort_sq.c", "codecs/ilbc/sort_sq.h", "codecs/ilbc/split_vq.c", "codecs/ilbc/split_vq.h", "codecs/ilbc/state_construct.c", "codecs/ilbc/state_construct.h", "codecs/ilbc/state_search.c", "codecs/ilbc/state_search.h", "codecs/ilbc/swap_bytes.c", "codecs/ilbc/swap_bytes.h", "codecs/ilbc/unpack_bits.c", "codecs/ilbc/unpack_bits.h", "codecs/ilbc/vq3.c", "codecs/ilbc/vq3.h", "codecs/ilbc/vq4.c", "codecs/ilbc/vq4.h", "codecs/ilbc/window32_w32.c", "codecs/ilbc/window32_w32.h", "codecs/ilbc/xcorr_coef.c", "codecs/ilbc/xcorr_coef.h", ] deps = [ "../../api/audio_codecs:audio_codecs_api", "../../common_audio", "../../common_audio:common_audio_c", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../../rtc_base:sanitizer", "../../rtc_base/system:arch", "../../rtc_base/system:unused", ] } rtc_source_set("isac_common") { poisonous = [ "audio_codecs" ] sources = [ "codecs/isac/audio_decoder_isac_t.h", "codecs/isac/audio_decoder_isac_t_impl.h", "codecs/isac/audio_encoder_isac_t.h", "codecs/isac/audio_encoder_isac_t_impl.h", ] deps = [ ":isac_bwinfo", "../../api:scoped_refptr", "../../api/audio_codecs:audio_codecs_api", "../../api/units:time_delta", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../../rtc_base:safe_minmax", "../../system_wrappers:field_trial", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("isac") { visibility += [ "*" ] poisonous = [ "audio_codecs" ] sources = [ "codecs/isac/main/include/audio_decoder_isac.h", "codecs/isac/main/include/audio_encoder_isac.h", "codecs/isac/main/source/audio_decoder_isac.cc", "codecs/isac/main/source/audio_encoder_isac.cc", ] deps = [ ":isac_common", "../../api/audio_codecs:audio_codecs_api", ] public_deps = [ ":isac_c" ] # no-presubmit-check TODO(webrtc:8603) } rtc_source_set("isac_bwinfo") { sources = [ "codecs/isac/bandwidth_info.h" ] deps = [] } rtc_library("isac_vad") { visibility += webrtc_default_visibility sources = [ "codecs/isac/main/source/filter_functions.c", "codecs/isac/main/source/filter_functions.h", "codecs/isac/main/source/isac_vad.c", "codecs/isac/main/source/isac_vad.h", "codecs/isac/main/source/os_specific_inline.h", "codecs/isac/main/source/pitch_estimator.c", "codecs/isac/main/source/pitch_estimator.h", "codecs/isac/main/source/pitch_filter.c", "codecs/isac/main/source/pitch_filter.h", "codecs/isac/main/source/settings.h", "codecs/isac/main/source/structs.h", ] deps = [ ":isac_bwinfo", "../../rtc_base:compile_assert_c", "../../rtc_base/system:arch", "../../rtc_base/system:ignore_warnings", "../third_party/fft", ] } rtc_library("isac_c") { poisonous = [ "audio_codecs" ] sources = [ "codecs/isac/main/include/isac.h", "codecs/isac/main/source/arith_routines.c", "codecs/isac/main/source/arith_routines.h", "codecs/isac/main/source/arith_routines_hist.c", "codecs/isac/main/source/arith_routines_logist.c", "codecs/isac/main/source/bandwidth_estimator.c", "codecs/isac/main/source/bandwidth_estimator.h", "codecs/isac/main/source/codec.h", "codecs/isac/main/source/crc.c", "codecs/isac/main/source/crc.h", "codecs/isac/main/source/decode.c", "codecs/isac/main/source/decode_bwe.c", "codecs/isac/main/source/encode.c", "codecs/isac/main/source/encode_lpc_swb.c", "codecs/isac/main/source/encode_lpc_swb.h", "codecs/isac/main/source/entropy_coding.c", "codecs/isac/main/source/entropy_coding.h", "codecs/isac/main/source/filterbanks.c", "codecs/isac/main/source/intialize.c", "codecs/isac/main/source/isac.c", "codecs/isac/main/source/isac_float_type.h", "codecs/isac/main/source/lattice.c", "codecs/isac/main/source/lpc_analysis.c", "codecs/isac/main/source/lpc_analysis.h", "codecs/isac/main/source/lpc_gain_swb_tables.c", "codecs/isac/main/source/lpc_gain_swb_tables.h", "codecs/isac/main/source/lpc_shape_swb12_tables.c", "codecs/isac/main/source/lpc_shape_swb12_tables.h", "codecs/isac/main/source/lpc_shape_swb16_tables.c", "codecs/isac/main/source/lpc_shape_swb16_tables.h", "codecs/isac/main/source/lpc_tables.c", "codecs/isac/main/source/lpc_tables.h", "codecs/isac/main/source/pitch_gain_tables.c", "codecs/isac/main/source/pitch_gain_tables.h", "codecs/isac/main/source/pitch_lag_tables.c", "codecs/isac/main/source/pitch_lag_tables.h", "codecs/isac/main/source/spectrum_ar_model_tables.c", "codecs/isac/main/source/spectrum_ar_model_tables.h", "codecs/isac/main/source/transform.c", ] if (is_linux || is_chromeos) { libs = [ "m" ] } deps = [ ":isac_bwinfo", ":isac_vad", "../../common_audio", "../../common_audio:common_audio_c", "../../rtc_base:checks", "../../rtc_base:compile_assert_c", "../../rtc_base:rtc_base_approved", "../../rtc_base/system:arch", "../third_party/fft", ] } rtc_library("isac_fix") { visibility += [ "*" ] poisonous = [ "audio_codecs" ] sources = [ "codecs/isac/fix/source/audio_decoder_isacfix.cc", "codecs/isac/fix/source/audio_encoder_isacfix.cc", ] deps = [ ":isac_common", "../../api/audio_codecs:audio_codecs_api", "../../common_audio", "../../system_wrappers", ] public_deps = [ ":isac_fix_c" ] # no-presubmit-check TODO(webrtc:8603) if (rtc_build_with_neon) { deps += [ ":isac_neon" ] } } rtc_library("isac_fix_common") { poisonous = [ "audio_codecs" ] sources = [ "codecs/isac/fix/source/codec.h", "codecs/isac/fix/source/entropy_coding.h", "codecs/isac/fix/source/fft.c", "codecs/isac/fix/source/fft.h", "codecs/isac/fix/source/filterbank_internal.h", "codecs/isac/fix/source/settings.h", "codecs/isac/fix/source/structs.h", "codecs/isac/fix/source/transform_tables.c", ] deps = [ ":isac_bwinfo", "../../common_audio", "../../common_audio:common_audio_c", ] } rtc_source_set("isac_fix_c_arm_asm") { poisonous = [ "audio_codecs" ] sources = [] if (current_cpu == "arm" && arm_version >= 7) { sources += [ "codecs/isac/fix/source/lattice_armv7.S", "codecs/isac/fix/source/pitch_filter_armv6.S", ] deps = [ ":isac_fix_common", "../../rtc_base/system:asm_defines", ] } } rtc_library("isac_fix_c") { poisonous = [ "audio_codecs" ] sources = [ "codecs/isac/fix/include/audio_decoder_isacfix.h", "codecs/isac/fix/include/audio_encoder_isacfix.h", "codecs/isac/fix/include/isacfix.h", "codecs/isac/fix/source/arith_routines.c", "codecs/isac/fix/source/arith_routines_hist.c", "codecs/isac/fix/source/arith_routines_logist.c", "codecs/isac/fix/source/arith_routins.h", "codecs/isac/fix/source/bandwidth_estimator.c", "codecs/isac/fix/source/bandwidth_estimator.h", "codecs/isac/fix/source/decode.c", "codecs/isac/fix/source/decode_bwe.c", "codecs/isac/fix/source/decode_plc.c", "codecs/isac/fix/source/encode.c", "codecs/isac/fix/source/entropy_coding.c", "codecs/isac/fix/source/filterbank_tables.c", "codecs/isac/fix/source/filterbank_tables.h", "codecs/isac/fix/source/filterbanks.c", "codecs/isac/fix/source/filters.c", "codecs/isac/fix/source/initialize.c", "codecs/isac/fix/source/isac_fix_type.h", "codecs/isac/fix/source/isacfix.c", "codecs/isac/fix/source/lattice.c", "codecs/isac/fix/source/lattice_c.c", "codecs/isac/fix/source/lpc_masking_model.c", "codecs/isac/fix/source/lpc_masking_model.h", "codecs/isac/fix/source/lpc_tables.c", "codecs/isac/fix/source/lpc_tables.h", "codecs/isac/fix/source/pitch_estimator.c", "codecs/isac/fix/source/pitch_estimator.h", "codecs/isac/fix/source/pitch_estimator_c.c", "codecs/isac/fix/source/pitch_filter.c", "codecs/isac/fix/source/pitch_filter_c.c", "codecs/isac/fix/source/pitch_gain_tables.c", "codecs/isac/fix/source/pitch_gain_tables.h", "codecs/isac/fix/source/pitch_lag_tables.c", "codecs/isac/fix/source/pitch_lag_tables.h", "codecs/isac/fix/source/spectrum_ar_model_tables.c", "codecs/isac/fix/source/spectrum_ar_model_tables.h", "codecs/isac/fix/source/transform.c", ] deps = [ ":isac_bwinfo", ":isac_common", "../../api/audio_codecs:audio_codecs_api", "../../common_audio", "../../common_audio:common_audio_c", "../../rtc_base:checks", "../../rtc_base:compile_assert_c", "../../rtc_base:rtc_base_approved", "../../rtc_base:sanitizer", "../../system_wrappers", "../third_party/fft", ] public_deps = [ ":isac_fix_common" ] # no-presubmit-check TODO(webrtc:8603) if (rtc_build_with_neon) { deps += [ ":isac_neon" ] # TODO(bugs.webrtc.org/9579): Consider moving the usage of NEON from # pitch_estimator_c.c into the "isac_neon" target and delete this flag: if (current_cpu != "arm64") { suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ] cflags = [ "-mfpu=neon" ] } } if (current_cpu == "arm" && arm_version >= 7) { sources -= [ "codecs/isac/fix/source/lattice_c.c", "codecs/isac/fix/source/pitch_filter_c.c", ] deps += [ ":isac_fix_c_arm_asm" ] } if (current_cpu == "mipsel") { sources += [ "codecs/isac/fix/source/entropy_coding_mips.c", "codecs/isac/fix/source/filters_mips.c", "codecs/isac/fix/source/lattice_mips.c", "codecs/isac/fix/source/pitch_estimator_mips.c", "codecs/isac/fix/source/transform_mips.c", ] sources -= [ "codecs/isac/fix/source/lattice_c.c", "codecs/isac/fix/source/pitch_estimator_c.c", ] if (mips_dsp_rev > 0) { sources += [ "codecs/isac/fix/source/filterbanks_mips.c" ] } if (mips_dsp_rev > 1) { sources += [ "codecs/isac/fix/source/lpc_masking_model_mips.c", "codecs/isac/fix/source/pitch_filter_mips.c", ] sources -= [ "codecs/isac/fix/source/pitch_filter_c.c" ] } } } if (rtc_build_with_neon) { rtc_library("isac_neon") { poisonous = [ "audio_codecs" ] sources = [ "codecs/isac/fix/source/entropy_coding_neon.c", "codecs/isac/fix/source/filterbanks_neon.c", "codecs/isac/fix/source/filters_neon.c", "codecs/isac/fix/source/lattice_neon.c", "codecs/isac/fix/source/transform_neon.c", ] if (current_cpu != "arm64") { # Enable compilation for the NEON instruction set. suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ] cflags = [ "-mfpu=neon" ] } deps = [ ":isac_fix_common", "../../common_audio", "../../common_audio:common_audio_c", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", ] } } rtc_library("pcm16b") { visibility += [ "*" ] poisonous = [ "audio_codecs" ] sources = [ "codecs/pcm16b/audio_decoder_pcm16b.cc", "codecs/pcm16b/audio_decoder_pcm16b.h", "codecs/pcm16b/audio_encoder_pcm16b.cc", "codecs/pcm16b/audio_encoder_pcm16b.h", "codecs/pcm16b/pcm16b_common.cc", "codecs/pcm16b/pcm16b_common.h", ] deps = [ ":g711", ":legacy_encoded_audio_frame", "../../api:array_view", "../../api/audio_codecs:audio_codecs_api", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", ] public_deps = [ ":pcm16b_c" ] # no-presubmit-check TODO(webrtc:8603) } rtc_library("pcm16b_c") { poisonous = [ "audio_codecs" ] sources = [ "codecs/pcm16b/pcm16b.c", "codecs/pcm16b/pcm16b.h", ] } rtc_library("audio_coding_opus_common") { sources = [ "codecs/opus/audio_coder_opus_common.cc", "codecs/opus/audio_coder_opus_common.h", ] deps = [ "../../api:array_view", "../../api/audio_codecs:audio_codecs_api", "../../rtc_base:checks", "../../rtc_base:stringutils", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] } rtc_library("webrtc_opus") { visibility += webrtc_default_visibility poisonous = [ "audio_codecs" ] sources = [ "codecs/opus/audio_decoder_opus.cc", "codecs/opus/audio_decoder_opus.h", "codecs/opus/audio_encoder_opus.cc", "codecs/opus/audio_encoder_opus.h", ] deps = [ ":audio_coding_opus_common", ":audio_network_adaptor", "../../api:array_view", "../../api/audio_codecs:audio_codecs_api", "../../api/audio_codecs/opus:audio_encoder_opus_config", "../../common_audio", "../../rtc_base:checks", "../../rtc_base:protobuf_utils", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_numerics", "../../rtc_base:safe_minmax", "../../system_wrappers:field_trial", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] public_deps = # no-presubmit-check TODO(webrtc:8603) [ ":webrtc_opus_wrapper" ] defines = audio_codec_defines if (rtc_build_opus) { public_deps += [ rtc_opus_dir ] # no-presubmit-check TODO(webrtc:8603) } else if (build_with_mozilla) { include_dirs = [ "/media/libopus/include" ] } } rtc_library("webrtc_multiopus") { visibility += webrtc_default_visibility poisonous = [ "audio_codecs" ] sources = [ "codecs/opus/audio_decoder_multi_channel_opus_impl.cc", "codecs/opus/audio_decoder_multi_channel_opus_impl.h", "codecs/opus/audio_encoder_multi_channel_opus_impl.cc", "codecs/opus/audio_encoder_multi_channel_opus_impl.h", ] deps = [ ":audio_coding_opus_common", "../../api/audio_codecs:audio_codecs_api", "../../api/audio_codecs/opus:audio_decoder_opus_config", "../../api/audio_codecs/opus:audio_encoder_opus_config", "../../api/units:time_delta", "../../rtc_base:checks", "../../rtc_base:logging", "../../rtc_base:rtc_base_approved", "../../rtc_base:safe_minmax", "../../rtc_base:stringutils", ] absl_deps = [ "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] public_deps = # no-presubmit-check TODO(webrtc:8603) [ ":webrtc_opus_wrapper" ] defines = audio_codec_defines if (rtc_build_opus) { public_deps += [ rtc_opus_dir ] } else if (build_with_mozilla) { include_dirs = [ "/media/libopus/include" ] } } rtc_library("webrtc_opus_wrapper") { poisonous = [ "audio_codecs" ] sources = [ "codecs/opus/opus_inst.h", "codecs/opus/opus_interface.cc", "codecs/opus/opus_interface.h", ] defines = audio_coding_defines if (rtc_build_opus) { public_deps = [ rtc_opus_dir ] # no-presubmit-check TODO(webrtc:8603) } else if (build_with_mozilla) { include_dirs = [ getenv("DIST") + "/include/opus" ] } deps = [ "../../rtc_base:checks", "../../rtc_base:ignore_wundef", "../../rtc_base:rtc_base_approved", "../../system_wrappers:field_trial", ] } if (rtc_enable_protobuf) { proto_library("ana_debug_dump_proto") { visibility += webrtc_default_visibility sources = [ "audio_network_adaptor/debug_dump.proto" ] link_deps = [ ":ana_config_proto" ] proto_out_dir = "modules/audio_coding/audio_network_adaptor" } proto_library("ana_config_proto") { visibility += [ "*" ] sources = [ "audio_network_adaptor/config.proto" ] proto_out_dir = "modules/audio_coding/audio_network_adaptor" } } rtc_library("audio_network_adaptor_config") { visibility += webrtc_default_visibility sources = [ "audio_network_adaptor/audio_network_adaptor_config.cc", "audio_network_adaptor/include/audio_network_adaptor_config.h", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("audio_network_adaptor") { visibility += webrtc_default_visibility sources = [ "audio_network_adaptor/audio_network_adaptor_impl.cc", "audio_network_adaptor/audio_network_adaptor_impl.h", "audio_network_adaptor/bitrate_controller.cc", "audio_network_adaptor/bitrate_controller.h", "audio_network_adaptor/channel_controller.cc", "audio_network_adaptor/channel_controller.h", "audio_network_adaptor/controller.cc", "audio_network_adaptor/controller.h", "audio_network_adaptor/controller_manager.cc", "audio_network_adaptor/controller_manager.h", "audio_network_adaptor/debug_dump_writer.cc", "audio_network_adaptor/debug_dump_writer.h", "audio_network_adaptor/dtx_controller.cc", "audio_network_adaptor/dtx_controller.h", "audio_network_adaptor/event_log_writer.cc", "audio_network_adaptor/event_log_writer.h", "audio_network_adaptor/fec_controller_plr_based.cc", "audio_network_adaptor/fec_controller_plr_based.h", "audio_network_adaptor/frame_length_controller.cc", "audio_network_adaptor/frame_length_controller.h", "audio_network_adaptor/frame_length_controller_v2.cc", "audio_network_adaptor/frame_length_controller_v2.h", "audio_network_adaptor/include/audio_network_adaptor.h", "audio_network_adaptor/util/threshold_curve.h", ] public_deps = # no-presubmit-check TODO(webrtc:8603) [ ":audio_network_adaptor_config" ] deps = [ "../../api/audio_codecs:audio_codecs_api", "../../api/rtc_event_log", "../../common_audio", "../../logging:rtc_event_audio", "../../rtc_base:checks", "../../rtc_base:ignore_wundef", "../../rtc_base:protobuf_utils", "../../rtc_base:rtc_base_approved", "../../rtc_base/system:file_wrapper", "../../system_wrappers", "../../system_wrappers:field_trial", ] absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container", "//third_party/abseil-cpp/absl/types:optional", ] if (rtc_enable_protobuf) { deps += [ ":ana_config_proto", ":ana_debug_dump_proto", ] } } rtc_library("neteq") { visibility += webrtc_default_visibility sources = [ "neteq/accelerate.cc", "neteq/accelerate.h", "neteq/audio_multi_vector.cc", "neteq/audio_multi_vector.h", "neteq/audio_vector.cc", "neteq/audio_vector.h", "neteq/background_noise.cc", "neteq/background_noise.h", "neteq/buffer_level_filter.cc", "neteq/buffer_level_filter.h", "neteq/comfort_noise.cc", "neteq/comfort_noise.h", "neteq/cross_correlation.cc", "neteq/cross_correlation.h", "neteq/decision_logic.cc", "neteq/decision_logic.h", "neteq/decoder_database.cc", "neteq/decoder_database.h", "neteq/delay_manager.cc", "neteq/delay_manager.h", "neteq/dsp_helper.cc", "neteq/dsp_helper.h", "neteq/dtmf_buffer.cc", "neteq/dtmf_buffer.h", "neteq/dtmf_tone_generator.cc", "neteq/dtmf_tone_generator.h", "neteq/expand.cc", "neteq/expand.h", "neteq/expand_uma_logger.cc", "neteq/expand_uma_logger.h", "neteq/histogram.cc", "neteq/histogram.h", "neteq/merge.cc", "neteq/merge.h", "neteq/nack_tracker.cc", "neteq/nack_tracker.h", "neteq/neteq_impl.cc", "neteq/neteq_impl.h", "neteq/normal.cc", "neteq/normal.h", "neteq/packet.cc", "neteq/packet.h", "neteq/packet_buffer.cc", "neteq/packet_buffer.h", "neteq/post_decode_vad.cc", "neteq/post_decode_vad.h", "neteq/preemptive_expand.cc", "neteq/preemptive_expand.h", "neteq/random_vector.cc", "neteq/random_vector.h", "neteq/red_payload_splitter.cc", "neteq/red_payload_splitter.h", "neteq/statistics_calculator.cc", "neteq/statistics_calculator.h", "neteq/sync_buffer.cc", "neteq/sync_buffer.h", "neteq/time_stretch.cc", "neteq/time_stretch.h", "neteq/timestamp_scaler.cc", "neteq/timestamp_scaler.h", ] deps = [ ":audio_coding_module_typedefs", ":webrtc_cng", "..:module_api", "..:module_api_public", "../../api:array_view", "../../api:rtp_headers", "../../api:rtp_packet_info", "../../api:scoped_refptr", "../../api/audio:audio_frame_api", "../../api/audio_codecs:audio_codecs_api", "../../api/neteq:neteq_api", "../../api/neteq:neteq_controller_api", "../../api/neteq:tick_timer", "../../common_audio", "../../common_audio:common_audio_c", "../../rtc_base:audio_format_to_string", "../../rtc_base:checks", "../../rtc_base:gtest_prod", "../../rtc_base:rtc_base_approved", "../../rtc_base:safe_minmax", "../../rtc_base:sanitizer", "../../rtc_base/experiments:field_trial_parser", "../../rtc_base/synchronization:mutex", "../../system_wrappers", "../../system_wrappers:field_trial", "../../system_wrappers:metrics", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] } rtc_source_set("default_neteq_factory") { visibility += webrtc_default_visibility sources = [ "neteq/default_neteq_factory.cc", "neteq/default_neteq_factory.h", ] deps = [ ":neteq", "../../api:scoped_refptr", "../../api/audio_codecs:audio_codecs_api", "../../api/neteq:default_neteq_controller_factory", "../../api/neteq:neteq_api", "../../system_wrappers:system_wrappers", ] } # Although providing only test support, this target must be outside of the # rtc_include_tests conditional. The reason is that it supports fuzzer tests # that ultimately are built and run as a part of the Chromium ecosystem, which # does not set the rtc_include_tests flag. rtc_library("neteq_tools_minimal") { visibility += webrtc_default_visibility sources = [ "neteq/tools/audio_sink.cc", "neteq/tools/audio_sink.h", "neteq/tools/encode_neteq_input.cc", "neteq/tools/encode_neteq_input.h", "neteq/tools/neteq_input.cc", "neteq/tools/neteq_input.h", "neteq/tools/neteq_test.cc", "neteq/tools/neteq_test.h", "neteq/tools/packet.cc", "neteq/tools/packet.h", "neteq/tools/packet_source.cc", "neteq/tools/packet_source.h", ] deps = [ ":default_neteq_factory", ":neteq", "../../api:neteq_simulator_api", "../../api:rtp_headers", "../../api/audio:audio_frame_api", "../../api/audio_codecs:audio_codecs_api", "../../api/neteq:custom_neteq_factory", "../../api/neteq:default_neteq_controller_factory", "../../api/neteq:neteq_api", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../../system_wrappers", "../rtp_rtcp", "../rtp_rtcp:rtp_rtcp_format", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] defines = audio_codec_defines } rtc_library("neteq_test_tools") { visibility += webrtc_default_visibility testonly = true sources = [ "neteq/tools/audio_checksum.h", "neteq/tools/audio_loop.cc", "neteq/tools/audio_loop.h", "neteq/tools/constant_pcm_packet_source.cc", "neteq/tools/constant_pcm_packet_source.h", "neteq/tools/initial_packet_inserter_neteq_input.cc", "neteq/tools/initial_packet_inserter_neteq_input.h", "neteq/tools/neteq_packet_source_input.cc", "neteq/tools/neteq_packet_source_input.h", "neteq/tools/output_audio_file.h", "neteq/tools/output_wav_file.h", "neteq/tools/rtp_file_source.cc", "neteq/tools/rtp_file_source.h", "neteq/tools/rtp_generator.cc", "neteq/tools/rtp_generator.h", ] deps = [ ":pcm16b", "../../api:array_view", "../../api:rtp_headers", "../../common_audio", "../../rtc_base", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../../rtc_base/system:arch", "../../test:rtp_test_utils", "../rtp_rtcp", "../rtp_rtcp:rtp_rtcp_format", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] public_deps = [ ":neteq_tools", ":neteq_tools_minimal", ] if (rtc_enable_protobuf) { sources += [ "neteq/tools/neteq_event_log_input.cc", "neteq/tools/neteq_event_log_input.h", ] deps += [ ":rtc_event_log_source" ] } } rtc_library("neteq_tools") { visibility += webrtc_default_visibility sources = [ "neteq/tools/fake_decode_from_file.cc", "neteq/tools/fake_decode_from_file.h", "neteq/tools/neteq_delay_analyzer.cc", "neteq/tools/neteq_delay_analyzer.h", "neteq/tools/neteq_replacement_input.cc", "neteq/tools/neteq_replacement_input.h", "neteq/tools/neteq_stats_getter.cc", "neteq/tools/neteq_stats_getter.h", "neteq/tools/neteq_stats_plotter.cc", "neteq/tools/neteq_stats_plotter.h", ] deps = [ "..:module_api_public", "../../api:array_view", "../../api/audio_codecs:audio_codecs_api", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../rtp_rtcp", "../rtp_rtcp:rtp_rtcp_format", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] public_deps = [ ":neteq_input_audio_tools", ":neteq_tools_minimal", ] } rtc_library("neteq_input_audio_tools") { visibility += webrtc_default_visibility sources = [ "neteq/tools/input_audio_file.cc", "neteq/tools/input_audio_file.h", "neteq/tools/resample_input_audio_file.cc", "neteq/tools/resample_input_audio_file.h", ] deps = [ "../../common_audio", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", ] } if (rtc_enable_protobuf) { rtc_library("rtc_event_log_source") { testonly = true sources = [ "neteq/tools/rtc_event_log_source.cc", "neteq/tools/rtc_event_log_source.h", ] deps = [ ":neteq_tools_minimal", "../../logging:rtc_event_log_parser", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../rtp_rtcp", "../rtp_rtcp:rtp_rtcp_format", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] public_deps = # no-presubmit-check TODO(webrtc:8603) [ "../../logging:rtc_event_log_proto" ] } # Only used for test purpose. Since we want to use it from chromium # (see audio_coding_modules_tests_shared below), we cannot guard it # under rtc_include_tests. proto_library("neteq_unittest_proto") { testonly = true sources = [ "neteq/neteq_unittest.proto" ] proto_out_dir = "modules/audio_coding/neteq" } } # Allow to re-use some test classes from chromium. rtc_library("audio_coding_modules_tests_shared") { testonly = true visibility = [] visibility = [ "*" ] sources = [ "neteq/test/neteq_decoding_test.cc", "neteq/test/neteq_decoding_test.h", "neteq/test/result_sink.cc", "neteq/test/result_sink.h", "test/PCMFile.cc", "test/PCMFile.h", "test/TestStereo.cc", "test/TestStereo.h", "test/opus_test.cc", "test/opus_test.h", ] deps = [ ":audio_coding", ":audio_coding_module_typedefs", ":default_neteq_factory", ":neteq_test_tools", ":neteq_tools_minimal", ":webrtc_opus_wrapper", "..:module_api", "../../api:rtp_headers", "../../api/audio:audio_frame_api", "../../api/audio_codecs:builtin_audio_decoder_factory", "../../api/audio_codecs:builtin_audio_encoder_factory", "../../api/neteq:neteq_api", "../../rtc_base", "../../rtc_base:checks", "../../rtc_base:ignore_wundef", "../../rtc_base:rtc_base_approved", "../../rtc_base:stringutils", "../../system_wrappers", "../../test:fileutils", "../../test:test_support", "../rtp_rtcp:rtp_rtcp_format", "//testing/gtest", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] defines = audio_coding_defines if (rtc_enable_protobuf) { defines += [ "WEBRTC_NETEQ_UNITTEST_BITEXACT" ] deps += [ ":neteq_unittest_proto" ] } } if (rtc_include_tests) { audio_coding_deps = [ ":audio_encoder_cng", ":g711", ":g722", ":pcm16b", "../../common_audio", "../../system_wrappers", ] if (rtc_include_ilbc) { audio_coding_deps += [ ":ilbc" ] } if (rtc_include_opus) { audio_coding_deps += [ ":webrtc_opus" ] } if (current_cpu == "arm") { audio_coding_deps += [ ":isac_fix" ] } else { audio_coding_deps += [ ":isac" ] } if (!build_with_mozilla && !build_with_chromium) { audio_coding_deps += [ ":red" ] } rtc_source_set("mocks") { testonly = true sources = [ "audio_network_adaptor/mock/mock_audio_network_adaptor.h", "audio_network_adaptor/mock/mock_controller.h", "audio_network_adaptor/mock/mock_controller_manager.h", "audio_network_adaptor/mock/mock_debug_dump_writer.h", ] deps = [ ":audio_network_adaptor", "../../test:test_support", ] } group("audio_coding_tests") { visibility += webrtc_default_visibility testonly = true public_deps = [ ":acm_receive_test", ":acm_send_test", ":audio_codec_speed_tests", ":audio_decoder_unittests", ":audio_decoder_unittests", ":g711_test", ":g722_test", ":ilbc_test", ":isac_api_test", ":isac_fix_test", ":isac_switch_samprate_test", ":isac_test", ":neteq_ilbc_quality_test", ":neteq_isac_quality_test", ":neteq_opus_quality_test", ":neteq_pcm16b_quality_test", ":neteq_pcmu_quality_test", ":neteq_speed_test", ":rtp_analyze", ":rtp_encode", ":rtp_jitter", ":rtpcat", ":webrtc_opus_fec_test", ] if (rtc_enable_protobuf) { public_deps += [ ":neteq_rtpplay" ] } } rtc_library("audio_coding_modules_tests") { testonly = true visibility += webrtc_default_visibility sources = [ "test/Channel.cc", "test/Channel.h", "test/EncodeDecodeTest.cc", "test/EncodeDecodeTest.h", "test/PacketLossTest.cc", "test/PacketLossTest.h", "test/RTPFile.cc", "test/RTPFile.h", "test/TestAllCodecs.cc", "test/TestAllCodecs.h", "test/TestRedFec.cc", "test/TestRedFec.h", "test/TestVADDTX.cc", "test/TestVADDTX.h", "test/Tester.cc", "test/TwoWayCommunication.cc", "test/TwoWayCommunication.h", "test/iSACTest.cc", "test/iSACTest.h", "test/target_delay_unittest.cc", ] deps = [ ":audio_coding", ":audio_coding_module_typedefs", ":audio_coding_modules_tests_shared", ":audio_encoder_cng", ":pcm16b_c", ":red", ":webrtc_opus_wrapper", "..:module_api", "../../api:rtp_headers", "../../api/audio:audio_frame_api", "../../api/audio_codecs:audio_codecs_api", "../../api/audio_codecs:builtin_audio_decoder_factory", "../../api/audio_codecs:builtin_audio_encoder_factory", "../../api/audio_codecs/L16:audio_decoder_L16", "../../api/audio_codecs/L16:audio_encoder_L16", "../../api/audio_codecs/g711:audio_decoder_g711", "../../api/audio_codecs/g711:audio_encoder_g711", "../../api/audio_codecs/g722:audio_decoder_g722", "../../api/audio_codecs/g722:audio_encoder_g722", "../../api/audio_codecs/ilbc:audio_decoder_ilbc", "../../api/audio_codecs/ilbc:audio_encoder_ilbc", "../../api/audio_codecs/isac:audio_decoder_isac_float", "../../api/audio_codecs/isac:audio_encoder_isac_float", "../../api/audio_codecs/opus:audio_decoder_opus", "../../api/audio_codecs/opus:audio_encoder_opus", "../../common_audio", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../../rtc_base/synchronization:mutex", "../../rtc_base/synchronization:rw_lock_wrapper", "../../system_wrappers", "../../test:fileutils", "../../test:test_support", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] defines = audio_coding_defines } rtc_library("audio_coding_perf_tests") { testonly = true visibility += webrtc_default_visibility sources = [ "codecs/opus/opus_complexity_unittest.cc", "neteq/test/neteq_performance_unittest.cc", ] deps = [ ":neteq_test_support", ":neteq_test_tools", "../../api/audio_codecs/opus:audio_encoder_opus", "../../rtc_base:rtc_base_approved", "../../system_wrappers", "../../system_wrappers:field_trial", "../../test:fileutils", "../../test:perf_test", "../../test:test_support", ] } rtc_library("acm_receive_test") { testonly = true sources = [ "acm2/acm_receive_test.cc", "acm2/acm_receive_test.h", ] defines = audio_coding_defines deps = audio_coding_deps + [ "../../api:scoped_refptr", "..:module_api", ":audio_coding", "../../api/audio_codecs:audio_codecs_api", "../../api/audio_codecs:builtin_audio_decoder_factory", ":neteq_tools", "../../rtc_base:rtc_base_approved", "../../test:test_support", "//testing/gtest", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } rtc_library("acm_send_test") { testonly = true sources = [ "acm2/acm_send_test.cc", "acm2/acm_send_test.h", ] defines = audio_coding_defines deps = audio_coding_deps + [ "//third_party/abseil-cpp/absl/strings", "../../api/audio:audio_frame_api", "../../rtc_base:checks", ":audio_coding", ":neteq_tools", "../../api/audio_codecs:builtin_audio_decoder_factory", "../../api/audio_codecs:builtin_audio_encoder_factory", "../../api/audio_codecs:audio_codecs_api", "../../rtc_base:rtc_base_approved", "../../test:test_support", "//testing/gtest", ] } audio_decoder_unittests_resources = [ "../../resources/audio_coding/testfile32kHz.pcm" ] if (is_ios) { bundle_data("audio_decoder_unittests_bundle_data") { testonly = true sources = audio_decoder_unittests_resources outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ] } } rtc_test("audio_decoder_unittests") { testonly = true sources = [ "neteq/audio_decoder_unittest.cc" ] defines = neteq_defines deps = [ ":ilbc", ":isac", ":isac_fix", ":neteq", ":neteq_tools", "../../test:fileutils", "../../api/audio_codecs:audio_codecs_api", "../../api/audio_codecs/opus:audio_encoder_opus", "../../common_audio", "../../rtc_base/system:arch", "../../test:test_main", "//testing/gtest", "../../test:test_support", ] + audio_coding_deps data = audio_decoder_unittests_resources if (is_android) { deps += [ "//testing/android/native_test:native_test_native_code" ] shard_timeout = 900 } if (is_ios) { deps += [ ":audio_decoder_unittests_bundle_data" ] } } if (rtc_enable_protobuf) { rtc_library("neteq_test_factory") { testonly = true visibility += webrtc_default_visibility defines = audio_codec_defines deps = [ "../../rtc_base:checks", "../../test:fileutils", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] sources = [ "neteq/tools/neteq_test_factory.cc", "neteq/tools/neteq_test_factory.h", ] deps += [ ":neteq", ":neteq_test_tools", "../../api/audio_codecs:builtin_audio_decoder_factory", "../../api/neteq:neteq_api", "../../rtc_base:rtc_base_approved", "../../test:audio_codec_mocks", "../../test:field_trial", "../../test:test_support", ] } rtc_executable("neteq_rtpplay") { testonly = true visibility += [ "*" ] defines = [] deps = [ ":neteq_test_factory", ":neteq_test_tools", "../../rtc_base:rtc_base_approved", "../../rtc_base:stringutils", "../../system_wrappers:field_trial", "../../test:field_trial", "//third_party/abseil-cpp/absl/flags:flag", "//third_party/abseil-cpp/absl/flags:parse", "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] sources = [ "neteq/tools/neteq_rtpplay.cc" ] } } audio_codec_speed_tests_resources = [ "//resources/audio_coding/music_stereo_48kHz.pcm", "//resources/audio_coding/speech_mono_16kHz.pcm", "//resources/audio_coding/speech_mono_32_48kHz.pcm", ] if (is_ios) { bundle_data("audio_codec_speed_tests_data") { testonly = true sources = audio_codec_speed_tests_resources outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ] } } rtc_test("audio_codec_speed_tests") { testonly = true defines = [] deps = [ "../../test:fileutils" ] sources = [ "codecs/isac/fix/test/isac_speed_test.cc", "codecs/opus/opus_speed_test.cc", "codecs/tools/audio_codec_speed_test.cc", "codecs/tools/audio_codec_speed_test.h", ] data = audio_codec_speed_tests_resources if (is_android) { deps += [ "//testing/android/native_test:native_test_native_code" ] shard_timeout = 900 } if (is_ios) { deps += [ ":audio_codec_speed_tests_data" ] } deps += [ ":isac_fix", ":webrtc_opus", "../../rtc_base:rtc_base_approved", "../../test:test_main", "../../test:test_support", "../audio_processing", "//testing/gtest", ] } rtc_library("neteq_test_support") { testonly = true sources = [ "neteq/tools/neteq_performance_test.cc", "neteq/tools/neteq_performance_test.h", ] deps = [ ":default_neteq_factory", ":neteq", ":neteq_test_tools", ":pcm16b", "../../api/audio:audio_frame_api", "../../api/audio_codecs:audio_codecs_api", "../../api/audio_codecs:builtin_audio_decoder_factory", "../../api/neteq:neteq_api", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../../system_wrappers", "../../test:fileutils", "../../test:test_support", "//testing/gtest", ] } rtc_library("neteq_quality_test_support") { testonly = true sources = [ "neteq/tools/neteq_quality_test.cc", "neteq/tools/neteq_quality_test.h", ] deps = [ ":default_neteq_factory", ":neteq", ":neteq_test_tools", "../../api/audio_codecs:builtin_audio_decoder_factory", "../../api/neteq:neteq_api", "../../rtc_base:checks", "../../system_wrappers", "../../test:fileutils", "../../test:test_support", "//testing/gtest", ] absl_deps = [ "//third_party/abseil-cpp/absl/flags:flag" ] } rtc_executable("rtp_encode") { testonly = true deps = audio_coding_deps + [ "//third_party/abseil-cpp/absl/flags:flag", "//third_party/abseil-cpp/absl/flags:parse", ":audio_coding", ":audio_encoder_cng", ":neteq_input_audio_tools", "../../api/audio:audio_frame_api", "../../api/audio_codecs/g711:audio_encoder_g711", "../../api/audio_codecs/L16:audio_encoder_L16", "../../api/audio_codecs/g722:audio_encoder_g722", "../../api/audio_codecs/ilbc:audio_encoder_ilbc", "../../api/audio_codecs/isac:audio_encoder_isac", "../../api/audio_codecs/opus:audio_encoder_opus", "../../rtc_base:safe_conversions", "//third_party/abseil-cpp/absl/memory", ] sources = [ "neteq/tools/rtp_encode.cc" ] defines = audio_coding_defines } rtc_executable("rtp_jitter") { testonly = true deps = audio_coding_deps + [ "../rtp_rtcp:rtp_rtcp_format", "../../api:array_view", "../../rtc_base:rtc_base_approved", ] sources = [ "neteq/tools/rtp_jitter.cc" ] defines = audio_coding_defines } rtc_executable("rtpcat") { testonly = true sources = [ "neteq/tools/rtpcat.cc" ] deps = [ "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../../test:rtp_test_utils", "//testing/gtest", ] } rtc_executable("rtp_analyze") { testonly = true sources = [ "neteq/tools/rtp_analyze.cc" ] deps = [ ":neteq", ":neteq_test_tools", ":pcm16b", "//testing/gtest", "//third_party/abseil-cpp/absl/flags:flag", "//third_party/abseil-cpp/absl/flags:parse", ] } rtc_executable("neteq_opus_quality_test") { testonly = true sources = [ "neteq/test/neteq_opus_quality_test.cc" ] deps = [ ":neteq", ":neteq_quality_test_support", ":neteq_tools", ":webrtc_opus", "../../rtc_base:rtc_base_approved", "../../test:test_main", "//testing/gtest", "//third_party/abseil-cpp/absl/flags:flag", ] } rtc_executable("neteq_speed_test") { testonly = true sources = [ "neteq/test/neteq_speed_test.cc" ] deps = [ ":neteq", ":neteq_test_support", "../../rtc_base:checks", "../../test:test_support", "//third_party/abseil-cpp/absl/flags:flag", "//third_party/abseil-cpp/absl/flags:parse", ] } rtc_executable("neteq_ilbc_quality_test") { testonly = true sources = [ "neteq/test/neteq_ilbc_quality_test.cc" ] deps = [ ":ilbc", ":neteq", ":neteq_quality_test_support", ":neteq_tools", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../../test:fileutils", "../../test:test_main", "//testing/gtest", "//third_party/abseil-cpp/absl/flags:flag", ] } rtc_executable("neteq_isac_quality_test") { testonly = true sources = [ "neteq/test/neteq_isac_quality_test.cc" ] deps = [ ":isac_fix", ":neteq", ":neteq_quality_test_support", "../../rtc_base:rtc_base_approved", "../../test:test_main", "//testing/gtest", "//third_party/abseil-cpp/absl/flags:flag", ] } rtc_executable("neteq_pcmu_quality_test") { testonly = true sources = [ "neteq/test/neteq_pcmu_quality_test.cc" ] deps = [ ":g711", ":neteq", ":neteq_quality_test_support", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../../test:fileutils", "../../test:test_main", "//testing/gtest", "//third_party/abseil-cpp/absl/flags:flag", ] } rtc_executable("neteq_pcm16b_quality_test") { testonly = true sources = [ "neteq/test/neteq_pcm16b_quality_test.cc" ] deps = [ ":neteq", ":neteq_quality_test_support", ":pcm16b", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../../test:fileutils", "../../test:test_main", "//testing/gtest", "//third_party/abseil-cpp/absl/flags:flag", ] } rtc_executable("isac_fix_test") { testonly = true sources = [ "codecs/isac/fix/test/kenny.cc" ] deps = [ ":isac_fix", "../../test:perf_test", "../../test:test_support", ] data = [ "../../resources/speech_and_misc_wb.pcm" ] } rtc_library("isac_test_util") { testonly = true sources = [ "codecs/isac/main/util/utility.c", "codecs/isac/main/util/utility.h", ] } rtc_executable("isac_test") { testonly = true sources = [ "codecs/isac/main/test/simpleKenny.c" ] deps = [ ":isac", ":isac_test_util", "../../rtc_base:rtc_base_approved", ] } rtc_executable("g711_test") { testonly = true sources = [ "codecs/g711/test/testG711.cc" ] deps = [ ":g711" ] } rtc_executable("g722_test") { testonly = true sources = [ "codecs/g722/test/testG722.cc" ] deps = [ ":g722" ] } rtc_executable("isac_api_test") { testonly = true sources = [ "codecs/isac/main/test/ReleaseTest-API/ReleaseTest-API.cc" ] deps = [ ":isac", ":isac_test_util", "../../rtc_base:rtc_base_approved", ] } rtc_executable("isac_switch_samprate_test") { testonly = true sources = [ "codecs/isac/main/test/SwitchingSampRate/SwitchingSampRate.cc" ] deps = [ ":isac", ":isac_test_util", "../../common_audio", "../../common_audio:common_audio_c", ] } rtc_executable("ilbc_test") { testonly = true sources = [ "codecs/ilbc/test/iLBC_test.c" ] deps = [ ":ilbc" ] } rtc_executable("webrtc_opus_fec_test") { testonly = true sources = [ "codecs/opus/opus_fec_test.cc" ] deps = [ ":webrtc_opus", "../../common_audio", "../../rtc_base:rtc_base_approved", "../../test:fileutils", "../../test:test_main", "../../test:test_support", "//testing/gtest", ] } rtc_library("audio_coding_unittests") { testonly = true visibility += webrtc_default_visibility sources = [ "acm2/acm_receiver_unittest.cc", "acm2/acm_remixing_unittest.cc", "acm2/audio_coding_module_unittest.cc", "acm2/call_statistics_unittest.cc", "audio_network_adaptor/audio_network_adaptor_impl_unittest.cc", "audio_network_adaptor/bitrate_controller_unittest.cc", "audio_network_adaptor/channel_controller_unittest.cc", "audio_network_adaptor/controller_manager_unittest.cc", "audio_network_adaptor/dtx_controller_unittest.cc", "audio_network_adaptor/event_log_writer_unittest.cc", "audio_network_adaptor/fec_controller_plr_based_unittest.cc", "audio_network_adaptor/frame_length_controller_unittest.cc", "audio_network_adaptor/frame_length_controller_v2_unittest.cc", "audio_network_adaptor/util/threshold_curve_unittest.cc", "codecs/builtin_audio_decoder_factory_unittest.cc", "codecs/builtin_audio_encoder_factory_unittest.cc", "codecs/cng/audio_encoder_cng_unittest.cc", "codecs/cng/cng_unittest.cc", "codecs/ilbc/ilbc_unittest.cc", "codecs/isac/fix/source/filterbanks_unittest.cc", "codecs/isac/fix/source/filters_unittest.cc", "codecs/isac/fix/source/lpc_masking_model_unittest.cc", "codecs/isac/fix/source/transform_unittest.cc", "codecs/isac/isac_webrtc_api_test.cc", "codecs/isac/main/source/audio_encoder_isac_unittest.cc", "codecs/isac/main/source/isac_unittest.cc", "codecs/legacy_encoded_audio_frame_unittest.cc", "codecs/opus/audio_decoder_multi_channel_opus_unittest.cc", "codecs/opus/audio_encoder_multi_channel_opus_unittest.cc", "codecs/opus/audio_encoder_opus_unittest.cc", "codecs/opus/opus_bandwidth_unittest.cc", "codecs/opus/opus_unittest.cc", "codecs/red/audio_encoder_copy_red_unittest.cc", "neteq/audio_multi_vector_unittest.cc", "neteq/audio_vector_unittest.cc", "neteq/background_noise_unittest.cc", "neteq/buffer_level_filter_unittest.cc", "neteq/comfort_noise_unittest.cc", "neteq/decision_logic_unittest.cc", "neteq/decoder_database_unittest.cc", "neteq/delay_manager_unittest.cc", "neteq/dsp_helper_unittest.cc", "neteq/dtmf_buffer_unittest.cc", "neteq/dtmf_tone_generator_unittest.cc", "neteq/expand_unittest.cc", "neteq/histogram_unittest.cc", "neteq/merge_unittest.cc", "neteq/mock/mock_decoder_database.h", "neteq/mock/mock_dtmf_buffer.h", "neteq/mock/mock_dtmf_tone_generator.h", "neteq/mock/mock_expand.h", "neteq/mock/mock_histogram.h", "neteq/mock/mock_neteq_controller.h", "neteq/mock/mock_packet_buffer.h", "neteq/mock/mock_red_payload_splitter.h", "neteq/mock/mock_statistics_calculator.h", "neteq/nack_tracker_unittest.cc", "neteq/neteq_decoder_plc_unittest.cc", "neteq/neteq_impl_unittest.cc", "neteq/neteq_network_stats_unittest.cc", "neteq/neteq_stereo_unittest.cc", "neteq/neteq_unittest.cc", "neteq/normal_unittest.cc", "neteq/packet_buffer_unittest.cc", "neteq/post_decode_vad_unittest.cc", "neteq/random_vector_unittest.cc", "neteq/red_payload_splitter_unittest.cc", "neteq/statistics_calculator_unittest.cc", "neteq/sync_buffer_unittest.cc", "neteq/time_stretch_unittest.cc", "neteq/timestamp_scaler_unittest.cc", "neteq/tools/input_audio_file_unittest.cc", "neteq/tools/packet_unittest.cc", ] deps = [ ":acm_receive_test", ":acm_send_test", ":audio_coding", ":audio_coding_module_typedefs", ":audio_coding_modules_tests_shared", ":audio_coding_opus_common", ":audio_encoder_cng", ":audio_network_adaptor", ":default_neteq_factory", ":g711", ":ilbc", ":isac", ":isac_c", ":isac_common", ":isac_fix", ":legacy_encoded_audio_frame", ":mocks", ":neteq", ":neteq_test_support", ":neteq_test_tools", ":pcm16b", ":red", ":webrtc_cng", ":webrtc_opus", "..:module_api", "..:module_api_public", "../../api:array_view", "../../api/audio:audio_frame_api", "../../api/audio_codecs:audio_codecs_api", "../../api/audio_codecs:builtin_audio_decoder_factory", "../../api/audio_codecs:builtin_audio_encoder_factory", "../../api/audio_codecs/isac:audio_decoder_isac_fix", "../../api/audio_codecs/isac:audio_decoder_isac_float", "../../api/audio_codecs/isac:audio_encoder_isac_fix", "../../api/audio_codecs/isac:audio_encoder_isac_float", "../../api/audio_codecs/opus:audio_decoder_multiopus", "../../api/audio_codecs/opus:audio_decoder_opus", "../../api/audio_codecs/opus:audio_encoder_multiopus", "../../api/audio_codecs/opus:audio_encoder_opus", "../../api/neteq:default_neteq_controller_factory", "../../api/neteq:neteq_api", "../../api/neteq:neteq_controller_api", "../../api/neteq:tick_timer", "../../api/neteq:tick_timer_unittest", "../../api/rtc_event_log", "../../common_audio", "../../common_audio:common_audio_c", "../../common_audio:mock_common_audio", "../../logging:mocks", "../../logging:rtc_event_audio", "../../modules/rtp_rtcp:rtp_rtcp_format", "../../rtc_base", "../../rtc_base:checks", "../../rtc_base:ignore_wundef", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_base_tests_utils", "../../rtc_base:sanitizer", "../../rtc_base:timeutils", "../../rtc_base/synchronization:mutex", "../../rtc_base/system:arch", "../../system_wrappers", "../../test:audio_codec_mocks", "../../test:field_trial", "../../test:fileutils", "../../test:rtc_expect_death", "../../test:rtp_test_utils", "../../test:test_common", "../../test:test_support", "codecs/opus/test", "codecs/opus/test:test_unittest", "//testing/gtest", ] absl_deps = [ "//third_party/abseil-cpp/absl/flags:flag", "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] defines = audio_coding_defines if (rtc_enable_protobuf) { defines += [ "WEBRTC_NETEQ_UNITTEST_BITEXACT" ] deps += [ ":ana_config_proto", ":neteq_unittest_proto", ] } } } # For backwards compatibility only! Use # webrtc/api/audio_codecs:audio_codecs_api instead. # TODO(kwiberg): Remove this. rtc_source_set("audio_decoder_interface") { visibility += [ "*" ] sources = [ "codecs/audio_decoder.h" ] deps = [ "../../api/audio_codecs:audio_codecs_api" ] } # For backwards compatibility only! Use # webrtc/api/audio_codecs:audio_codecs_api instead. # TODO(ossu): Remove this. rtc_source_set("audio_encoder_interface") { visibility += [ "*" ] sources = [ "codecs/audio_encoder.h" ] deps = [ "../../api/audio_codecs:audio_codecs_api" ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/0000775000175000017500000000000014475643423023510 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/audio_decoder.h0000664000175000017500000000136614475643423026455 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // This file is for backwards compatibility only! Use // webrtc/api/audio_codecs/audio_decoder.h instead! // TODO(kwiberg): Remove it. #ifndef MODULES_AUDIO_CODING_CODECS_AUDIO_DECODER_H_ #define MODULES_AUDIO_CODING_CODECS_AUDIO_DECODER_H_ #include "api/audio_codecs/audio_decoder.h" #endif // MODULES_AUDIO_CODING_CODECS_AUDIO_DECODER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/audio_encoder.h0000664000175000017500000000136314475643423026464 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // This file is for backwards compatibility only! Use // webrtc/api/audio_codecs/audio_encoder.h instead! // TODO(ossu): Remove it. #ifndef MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_ #define MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_ #include "api/audio_codecs/audio_encoder.h" #endif // MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/cng/0000775000175000017500000000000014475643423024257 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/cng/webrtc_cng.h0000664000175000017500000001234114475643423026546 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_CNG_MAIN_INCLUDE_WEBRTC_CNG_H_ #define WEBRTC_MODULES_AUDIO_CODING_CODECS_CNG_MAIN_INCLUDE_WEBRTC_CNG_H_ #include #include "webrtc/typedefs.h" #ifdef __cplusplus extern "C" { #endif #define WEBRTC_CNG_MAX_LPC_ORDER 12 #define WEBRTC_CNG_MAX_OUTSIZE_ORDER 640 /* Define Error codes. */ /* 6100 Encoder */ #define CNG_ENCODER_NOT_INITIATED 6120 #define CNG_DISALLOWED_LPC_ORDER 6130 #define CNG_DISALLOWED_FRAME_SIZE 6140 #define CNG_DISALLOWED_SAMPLING_FREQUENCY 6150 /* 6200 Decoder */ #define CNG_DECODER_NOT_INITIATED 6220 typedef struct WebRtcCngEncInst CNG_enc_inst; typedef struct WebRtcCngDecInst CNG_dec_inst; /**************************************************************************** * WebRtcCng_CreateEnc/Dec(...) * * These functions create an instance to the specified structure * * Input: * - XXX_inst : Pointer to created instance that should be created * * Return value : 0 - Ok * -1 - Error */ int16_t WebRtcCng_CreateEnc(CNG_enc_inst** cng_inst); int16_t WebRtcCng_CreateDec(CNG_dec_inst** cng_inst); /**************************************************************************** * WebRtcCng_InitEnc/Dec(...) * * This function initializes a instance * * Input: * - cng_inst : Instance that should be initialized * * - fs : 8000 for narrowband and 16000 for wideband * - interval : generate SID data every interval ms * - quality : Number of refl. coefs, maximum allowed is 12 * * Output: * - cng_inst : Initialized instance * * Return value : 0 - Ok * -1 - Error */ int WebRtcCng_InitEnc(CNG_enc_inst* cng_inst, int fs, int16_t interval, int16_t quality); void WebRtcCng_InitDec(CNG_dec_inst* cng_inst); /**************************************************************************** * WebRtcCng_FreeEnc/Dec(...) * * These functions frees the dynamic memory of a specified instance * * Input: * - cng_inst : Pointer to created instance that should be freed * * Return value : 0 - Ok * -1 - Error */ int16_t WebRtcCng_FreeEnc(CNG_enc_inst* cng_inst); int16_t WebRtcCng_FreeDec(CNG_dec_inst* cng_inst); /**************************************************************************** * WebRtcCng_Encode(...) * * These functions analyzes background noise * * Input: * - cng_inst : Pointer to created instance * - speech : Signal to be analyzed * - nrOfSamples : Size of speech vector * - forceSID : not zero to force SID frame and reset * * Output: * - bytesOut : Nr of bytes to transmit, might be 0 * * Return value : 0 - Ok * -1 - Error */ int WebRtcCng_Encode(CNG_enc_inst* cng_inst, int16_t* speech, size_t nrOfSamples, uint8_t* SIDdata, size_t* bytesOut, int16_t forceSID); /**************************************************************************** * WebRtcCng_UpdateSid(...) * * These functions updates the CN state, when a new SID packet arrives * * Input: * - cng_inst : Pointer to created instance that should be freed * - SID : SID packet, all headers removed * - length : Length in bytes of SID packet * * Return value : 0 - Ok * -1 - Error */ int16_t WebRtcCng_UpdateSid(CNG_dec_inst* cng_inst, uint8_t* SID, size_t length); /**************************************************************************** * WebRtcCng_Generate(...) * * These functions generates CN data when needed * * Input: * - cng_inst : Pointer to created instance that should be freed * - outData : pointer to area to write CN data * - nrOfSamples : How much data to generate * - new_period : >0 if a new period of CNG, will reset history * * Return value : 0 - Ok * -1 - Error */ int16_t WebRtcCng_Generate(CNG_dec_inst* cng_inst, int16_t* outData, size_t nrOfSamples, int16_t new_period); /***************************************************************************** * WebRtcCng_GetErrorCodeEnc/Dec(...) * * This functions can be used to check the error code of a CNG instance. When * a function returns -1 a error code will be set for that instance. The * function below extract the code of the last error that occurred in the * specified instance. * * Input: * - CNG_inst : CNG enc/dec instance * * Return value : Error code */ int16_t WebRtcCng_GetErrorCodeEnc(CNG_enc_inst* cng_inst); int16_t WebRtcCng_GetErrorCodeDec(CNG_dec_inst* cng_inst); #ifdef __cplusplus } #endif #endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_CNG_MAIN_INCLUDE_WEBRTC_CNG_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/0000775000175000017500000000000014475643423024427 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h0000664000175000017500000000320214475643423030705 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_H_ #include #include "absl/types/optional.h" #include "api/audio_codecs/audio_decoder.h" #include "api/scoped_refptr.h" #include "rtc_base/constructor_magic.h" namespace webrtc { template class AudioDecoderIsacT final : public AudioDecoder { public: struct Config { bool IsOk() const; int sample_rate_hz = 16000; }; explicit AudioDecoderIsacT(const Config& config); virtual ~AudioDecoderIsacT() override; bool HasDecodePlc() const override; size_t DecodePlc(size_t num_frames, int16_t* decoded) override; void Reset() override; int ErrorCode() override; int SampleRateHz() const override; size_t Channels() const override; int DecodeInternal(const uint8_t* encoded, size_t encoded_len, int sample_rate_hz, int16_t* decoded, SpeechType* speech_type) override; private: typename T::instance_type* isac_state_; int sample_rate_hz_; RTC_DISALLOW_COPY_AND_ASSIGN(AudioDecoderIsacT); }; } // namespace webrtc #endif // MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h0000664000175000017500000000500114475643423031725 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_IMPL_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_IMPL_H_ #include "rtc_base/checks.h" namespace webrtc { template bool AudioDecoderIsacT::Config::IsOk() const { return (sample_rate_hz == 16000 || sample_rate_hz == 32000); } template AudioDecoderIsacT::AudioDecoderIsacT(const Config& config) : sample_rate_hz_(config.sample_rate_hz) { RTC_CHECK(config.IsOk()) << "Unsupported sample rate " << config.sample_rate_hz; RTC_CHECK_EQ(0, T::Create(&isac_state_)); T::DecoderInit(isac_state_); RTC_CHECK_EQ(0, T::SetDecSampRate(isac_state_, sample_rate_hz_)); } template AudioDecoderIsacT::~AudioDecoderIsacT() { RTC_CHECK_EQ(0, T::Free(isac_state_)); } template int AudioDecoderIsacT::DecodeInternal(const uint8_t* encoded, size_t encoded_len, int sample_rate_hz, int16_t* decoded, SpeechType* speech_type) { RTC_CHECK_EQ(sample_rate_hz_, sample_rate_hz); int16_t temp_type = 1; // Default is speech. int ret = T::DecodeInternal(isac_state_, encoded, encoded_len, decoded, &temp_type); *speech_type = ConvertSpeechType(temp_type); return ret; } template bool AudioDecoderIsacT::HasDecodePlc() const { return false; } template size_t AudioDecoderIsacT::DecodePlc(size_t num_frames, int16_t* decoded) { return T::DecodePlc(isac_state_, decoded, num_frames); } template void AudioDecoderIsacT::Reset() { T::DecoderInit(isac_state_); } template int AudioDecoderIsacT::ErrorCode() { return T::GetErrorCode(isac_state_); } template int AudioDecoderIsacT::SampleRateHz() const { return sample_rate_hz_; } template size_t AudioDecoderIsacT::Channels() const { return 1; } } // namespace webrtc #endif // MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_IMPL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h0000664000175000017500000000763514475643423030735 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_H_ #include #include #include "absl/types/optional.h" #include "api/audio_codecs/audio_encoder.h" #include "api/scoped_refptr.h" #include "api/units/time_delta.h" #include "rtc_base/constructor_magic.h" #include "system_wrappers/include/field_trial.h" namespace webrtc { template class AudioEncoderIsacT final : public AudioEncoder { public: // Allowed combinations of sample rate, frame size, and bit rate are // - 16000 Hz, 30 ms, 10000-32000 bps // - 16000 Hz, 60 ms, 10000-32000 bps // - 32000 Hz, 30 ms, 10000-56000 bps (if T has super-wideband support) struct Config { bool IsOk() const; int payload_type = 103; int sample_rate_hz = 16000; int frame_size_ms = 30; int bit_rate = kDefaultBitRate; // Limit on the short-term average bit // rate, in bits/s. int max_payload_size_bytes = -1; int max_bit_rate = -1; }; explicit AudioEncoderIsacT(const Config& config); ~AudioEncoderIsacT() override; int SampleRateHz() const override; size_t NumChannels() const override; size_t Num10MsFramesInNextPacket() const override; size_t Max10MsFramesInAPacket() const override; int GetTargetBitrate() const override; void SetTargetBitrate(int target_bps) override; void OnReceivedTargetAudioBitrate(int target_bps) override; void OnReceivedUplinkBandwidth( int target_audio_bitrate_bps, absl::optional bwe_period_ms) override; void OnReceivedUplinkAllocation(BitrateAllocationUpdate update) override; void OnReceivedOverhead(size_t overhead_bytes_per_packet) override; EncodedInfo EncodeImpl(uint32_t rtp_timestamp, rtc::ArrayView audio, rtc::Buffer* encoded) override; void Reset() override; absl::optional> GetFrameLengthRange() const override; private: // This value is taken from STREAM_SIZE_MAX_60 for iSAC float (60 ms) and // STREAM_MAXW16_60MS for iSAC fix (60 ms). static const size_t kSufficientEncodeBufferSizeBytes = 400; static constexpr int kDefaultBitRate = 32000; static constexpr int kMinBitrateBps = 10000; static constexpr int MaxBitrateBps(int sample_rate_hz) { return sample_rate_hz == 32000 ? 56000 : 32000; } void SetTargetBitrate(int target_bps, bool subtract_per_packet_overhead); // Recreate the iSAC encoder instance with the given settings, and save them. void RecreateEncoderInstance(const Config& config); Config config_; typename T::instance_type* isac_state_ = nullptr; // Have we accepted input but not yet emitted it in a packet? bool packet_in_progress_ = false; // Timestamp of the first input of the currently in-progress packet. uint32_t packet_timestamp_; // Timestamp of the previously encoded packet. uint32_t last_encoded_timestamp_; // Cache the value of the "WebRTC-SendSideBwe-WithOverhead" field trial. const bool send_side_bwe_with_overhead_ = field_trial::IsEnabled("WebRTC-SendSideBwe-WithOverhead"); // When we send a packet, expect this many bytes of headers to be added to it. // Start out with a reasonable default that we can use until we receive a real // value. DataSize overhead_per_packet_ = DataSize::Bytes(28); RTC_DISALLOW_COPY_AND_ASSIGN(AudioEncoderIsacT); }; } // namespace webrtc #endif // MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h0000664000175000017500000001651414475643423031752 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_ #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_minmax.h" namespace webrtc { template bool AudioEncoderIsacT::Config::IsOk() const { if (max_bit_rate < 32000 && max_bit_rate != -1) return false; if (max_payload_size_bytes < 120 && max_payload_size_bytes != -1) return false; switch (sample_rate_hz) { case 16000: if (max_bit_rate > 53400) return false; if (max_payload_size_bytes > 400) return false; return (frame_size_ms == 30 || frame_size_ms == 60) && (bit_rate == 0 || (bit_rate >= 10000 && bit_rate <= 32000)); case 32000: if (max_bit_rate > 160000) return false; if (max_payload_size_bytes > 600) return false; return T::has_swb && (frame_size_ms == 30 && (bit_rate == 0 || (bit_rate >= 10000 && bit_rate <= 56000))); default: return false; } } template AudioEncoderIsacT::AudioEncoderIsacT(const Config& config) { RecreateEncoderInstance(config); } template AudioEncoderIsacT::~AudioEncoderIsacT() { RTC_CHECK_EQ(0, T::Free(isac_state_)); } template int AudioEncoderIsacT::SampleRateHz() const { return T::EncSampRate(isac_state_); } template size_t AudioEncoderIsacT::NumChannels() const { return 1; } template size_t AudioEncoderIsacT::Num10MsFramesInNextPacket() const { const int samples_in_next_packet = T::GetNewFrameLen(isac_state_); return static_cast(rtc::CheckedDivExact( samples_in_next_packet, rtc::CheckedDivExact(SampleRateHz(), 100))); } template size_t AudioEncoderIsacT::Max10MsFramesInAPacket() const { return 6; // iSAC puts at most 60 ms in a packet. } template int AudioEncoderIsacT::GetTargetBitrate() const { return config_.bit_rate == 0 ? kDefaultBitRate : config_.bit_rate; } template void AudioEncoderIsacT::SetTargetBitrate(int target_bps) { // Set target bitrate directly without subtracting per-packet overhead, // because that's what AudioEncoderOpus does. SetTargetBitrate(target_bps, /*subtract_per_packet_overhead=*/false); } template void AudioEncoderIsacT::OnReceivedTargetAudioBitrate(int target_bps) { // Set target bitrate directly without subtracting per-packet overhead, // because that's what AudioEncoderOpus does. SetTargetBitrate(target_bps, /*subtract_per_packet_overhead=*/false); } template void AudioEncoderIsacT::OnReceivedUplinkBandwidth( int target_audio_bitrate_bps, absl::optional /*bwe_period_ms*/) { // Set target bitrate, subtracting the per-packet overhead if // WebRTC-SendSideBwe-WithOverhead is enabled, because that's what // AudioEncoderOpus does. SetTargetBitrate( target_audio_bitrate_bps, /*subtract_per_packet_overhead=*/send_side_bwe_with_overhead_); } template void AudioEncoderIsacT::OnReceivedUplinkAllocation( BitrateAllocationUpdate update) { // Set target bitrate, subtracting the per-packet overhead if // WebRTC-SendSideBwe-WithOverhead is enabled, because that's what // AudioEncoderOpus does. SetTargetBitrate( update.target_bitrate.bps(), /*subtract_per_packet_overhead=*/send_side_bwe_with_overhead_); } template void AudioEncoderIsacT::OnReceivedOverhead( size_t overhead_bytes_per_packet) { overhead_per_packet_ = DataSize::Bytes(overhead_bytes_per_packet); } template AudioEncoder::EncodedInfo AudioEncoderIsacT::EncodeImpl( uint32_t rtp_timestamp, rtc::ArrayView audio, rtc::Buffer* encoded) { if (!packet_in_progress_) { // Starting a new packet; remember the timestamp for later. packet_in_progress_ = true; packet_timestamp_ = rtp_timestamp; } size_t encoded_bytes = encoded->AppendData( kSufficientEncodeBufferSizeBytes, [&](rtc::ArrayView encoded) { int r = T::Encode(isac_state_, audio.data(), encoded.data()); RTC_CHECK_GE(r, 0) << "Encode failed (error code " << T::GetErrorCode(isac_state_) << ")"; return static_cast(r); }); if (encoded_bytes == 0) return EncodedInfo(); // Got enough input to produce a packet. Return the saved timestamp from // the first chunk of input that went into the packet. packet_in_progress_ = false; EncodedInfo info; info.encoded_bytes = encoded_bytes; info.encoded_timestamp = packet_timestamp_; info.payload_type = config_.payload_type; info.encoder_type = CodecType::kIsac; return info; } template void AudioEncoderIsacT::Reset() { RecreateEncoderInstance(config_); } template absl::optional> AudioEncoderIsacT::GetFrameLengthRange() const { return {{TimeDelta::Millis(config_.frame_size_ms), TimeDelta::Millis(config_.frame_size_ms)}}; } template void AudioEncoderIsacT::SetTargetBitrate(int target_bps, bool subtract_per_packet_overhead) { if (subtract_per_packet_overhead) { const DataRate overhead_rate = overhead_per_packet_ / TimeDelta::Millis(config_.frame_size_ms); target_bps -= overhead_rate.bps(); } target_bps = rtc::SafeClamp(target_bps, kMinBitrateBps, MaxBitrateBps(config_.sample_rate_hz)); int result = T::Control(isac_state_, target_bps, config_.frame_size_ms); RTC_DCHECK_EQ(result, 0); config_.bit_rate = target_bps; } template void AudioEncoderIsacT::RecreateEncoderInstance(const Config& config) { RTC_CHECK(config.IsOk()); packet_in_progress_ = false; if (isac_state_) RTC_CHECK_EQ(0, T::Free(isac_state_)); RTC_CHECK_EQ(0, T::Create(&isac_state_)); RTC_CHECK_EQ(0, T::EncoderInit(isac_state_, /*coding_mode=*/1)); RTC_CHECK_EQ(0, T::SetEncSampRate(isac_state_, config.sample_rate_hz)); const int bit_rate = config.bit_rate == 0 ? kDefaultBitRate : config.bit_rate; RTC_CHECK_EQ(0, T::Control(isac_state_, bit_rate, config.frame_size_ms)); if (config.max_payload_size_bytes != -1) RTC_CHECK_EQ( 0, T::SetMaxPayloadSize(isac_state_, config.max_payload_size_bytes)); if (config.max_bit_rate != -1) RTC_CHECK_EQ(0, T::SetMaxRate(isac_state_, config.max_bit_rate)); // Set the decoder sample rate even though we just use the encoder. This // doesn't appear to be necessary to produce a valid encoding, but without it // we get an encoding that isn't bit-for-bit identical with what a combined // encoder+decoder object produces. RTC_CHECK_EQ(0, T::SetDecSampRate(isac_state_, config.sample_rate_hz)); config_ = config; } } // namespace webrtc #endif // MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/bandwidth_info.h0000664000175000017500000000140314475643423027555 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_BANDWIDTH_INFO_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_BANDWIDTH_INFO_H_ #include typedef struct { int in_use; int32_t send_bw_avg; int32_t send_max_delay_avg; int16_t bottleneck_idx; int16_t jitter_info; } IsacBandwidthInfo; #endif // MODULES_AUDIO_CODING_CODECS_ISAC_BANDWIDTH_INFO_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.h0000664000175000017500000000264614475643423031110 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_LOCKED_BANDWIDTH_INFO_H_ #define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_LOCKED_BANDWIDTH_INFO_H_ #include "webrtc/base/scoped_ptr.h" #include "webrtc/base/thread_annotations.h" #include "webrtc/modules/audio_coding/codecs/isac/bandwidth_info.h" #include "webrtc/system_wrappers/include/critical_section_wrapper.h" namespace webrtc { // An IsacBandwidthInfo that's safe to access from multiple threads because // it's protected by a mutex. class LockedIsacBandwidthInfo final { public: LockedIsacBandwidthInfo(); ~LockedIsacBandwidthInfo(); IsacBandwidthInfo Get() const { CriticalSectionScoped cs(lock_.get()); return bwinfo_; } void Set(const IsacBandwidthInfo& bwinfo) { CriticalSectionScoped cs(lock_.get()); bwinfo_ = bwinfo; } private: const rtc::scoped_ptr lock_; IsacBandwidthInfo bwinfo_ GUARDED_BY(lock_); }; } // namespace webrtc #endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_LOCKED_BANDWIDTH_INFO_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/0000775000175000017500000000000014475643423025353 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/include/0000775000175000017500000000000014475643423026776 5ustar00arunarun././@PaxHeader0000000000000000000000000000020500000000000010212 xustar00111 path=webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.0000664000175000017500000000160014475643423032561 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_DECODER_ISAC_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_DECODER_ISAC_H_ #include "modules/audio_coding/codecs/isac/audio_decoder_isac_t.h" #include "modules/audio_coding/codecs/isac/main/source/isac_float_type.h" namespace webrtc { using AudioDecoderIsacFloatImpl = AudioDecoderIsacT; } // namespace webrtc #endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_ ././@PaxHeader0000000000000000000000000000020500000000000010212 xustar00111 path=webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.0000664000175000017500000000160014475643423032573 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_ #include "modules/audio_coding/codecs/isac/audio_encoder_isac_t.h" #include "modules/audio_coding/codecs/isac/main/source/isac_float_type.h" namespace webrtc { using AudioEncoderIsacFloatImpl = AudioEncoderIsacT; } // namespace webrtc #endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/include/isac.h0000664000175000017500000005540514475643423030077 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_ISAC_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_ISAC_H_ #include #include "modules/audio_coding/codecs/isac/bandwidth_info.h" typedef struct WebRtcISACStruct ISACStruct; #if defined(__cplusplus) extern "C" { #endif /****************************************************************************** * WebRtcIsac_Create(...) * * This function creates an ISAC instance, which will contain the state * information for one coding/decoding channel. * * Input: * - *ISAC_main_inst : a pointer to the coder instance. * * Return value : 0 - Ok * -1 - Error */ int16_t WebRtcIsac_Create(ISACStruct** ISAC_main_inst); /****************************************************************************** * WebRtcIsac_Free(...) * * This function frees the ISAC instance created at the beginning. * * Input: * - ISAC_main_inst : an ISAC instance. * * Return value : 0 - Ok * -1 - Error */ int16_t WebRtcIsac_Free(ISACStruct* ISAC_main_inst); /****************************************************************************** * WebRtcIsac_EncoderInit(...) * * This function initializes an ISAC instance prior to the encoder calls. * * Input: * - ISAC_main_inst : ISAC instance. * - CodingMode : 0 -> Bit rate and frame length are * automatically adjusted to available bandwidth * on transmission channel, just valid if codec * is created to work in wideband mode. * 1 -> User sets a frame length and a target bit * rate which is taken as the maximum * short-term average bit rate. * * Return value : 0 - Ok * -1 - Error */ int16_t WebRtcIsac_EncoderInit(ISACStruct* ISAC_main_inst, int16_t CodingMode); /****************************************************************************** * WebRtcIsac_Encode(...) * * This function encodes 10ms audio blocks and inserts it into a package. * Input speech length has 160 samples if operating at 16 kHz sampling * rate, or 320 if operating at 32 kHz sampling rate. The encoder buffers the * input audio until the whole frame is buffered then proceeds with encoding. * * * Input: * - ISAC_main_inst : ISAC instance. * - speechIn : input speech vector. * * Output: * - encoded : the encoded data vector * * Return value: * : >0 - Length (in bytes) of coded data * : 0 - The buffer didn't reach the chosen * frame-size so it keeps buffering speech * samples. * : -1 - Error */ int WebRtcIsac_Encode(ISACStruct* ISAC_main_inst, const int16_t* speechIn, uint8_t* encoded); /****************************************************************************** * WebRtcIsac_DecoderInit(...) * * This function initializes an ISAC instance prior to the decoder calls. * * Input: * - ISAC_main_inst : ISAC instance. */ void WebRtcIsac_DecoderInit(ISACStruct* ISAC_main_inst); /****************************************************************************** * WebRtcIsac_UpdateBwEstimate(...) * * This function updates the estimate of the bandwidth. * * Input: * - ISAC_main_inst : ISAC instance. * - encoded : encoded ISAC frame(s). * - packet_size : size of the packet. * - rtp_seq_number : the RTP number of the packet. * - send_ts : the RTP send timestamp, given in samples * - arr_ts : the arrival time of the packet (from NetEq) * in samples. * * Return value : 0 - Ok * -1 - Error */ int16_t WebRtcIsac_UpdateBwEstimate(ISACStruct* ISAC_main_inst, const uint8_t* encoded, size_t packet_size, uint16_t rtp_seq_number, uint32_t send_ts, uint32_t arr_ts); /****************************************************************************** * WebRtcIsac_Decode(...) * * This function decodes an ISAC frame. At 16 kHz sampling rate, the length * of the output audio could be either 480 or 960 samples, equivalent to * 30 or 60 ms respectively. At 32 kHz sampling rate, the length of the * output audio is 960 samples, which is 30 ms. * * Input: * - ISAC_main_inst : ISAC instance. * - encoded : encoded ISAC frame(s). * - len : bytes in encoded vector. * * Output: * - decoded : The decoded vector. * * Return value : >0 - number of samples in decoded vector. * -1 - Error. */ int WebRtcIsac_Decode(ISACStruct* ISAC_main_inst, const uint8_t* encoded, size_t len, int16_t* decoded, int16_t* speechType); /****************************************************************************** * WebRtcIsac_DecodePlc(...) * * This function conducts PLC for ISAC frame(s). Output speech length * will be a multiple of frames, i.e. multiples of 30 ms audio. Therefore, * the output is multiple of 480 samples if operating at 16 kHz and multiple * of 960 if operating at 32 kHz. * * Input: * - ISAC_main_inst : ISAC instance. * - noOfLostFrames : Number of PLC frames to produce. * * Output: * - decoded : The decoded vector. * * Return value : Number of samples in decoded PLC vector */ size_t WebRtcIsac_DecodePlc(ISACStruct* ISAC_main_inst, int16_t* decoded, size_t noOfLostFrames); /****************************************************************************** * WebRtcIsac_Control(...) * * This function sets the limit on the short-term average bit-rate and the * frame length. Should be used only in Instantaneous mode. At 16 kHz sampling * rate, an average bit-rate between 10000 to 32000 bps is valid and a * frame-size of 30 or 60 ms is acceptable. At 32 kHz, an average bit-rate * between 10000 to 56000 is acceptable, and the valid frame-size is 30 ms. * * Input: * - ISAC_main_inst : ISAC instance. * - rate : limit on the short-term average bit rate, * in bits/second. * - framesize : frame-size in millisecond. * * Return value : 0 - ok * -1 - Error */ int16_t WebRtcIsac_Control(ISACStruct* ISAC_main_inst, int32_t rate, int framesize); void WebRtcIsac_SetInitialBweBottleneck(ISACStruct* ISAC_main_inst, int bottleneck_bits_per_second); /****************************************************************************** * WebRtcIsac_ControlBwe(...) * * This function sets the initial values of bottleneck and frame-size if * iSAC is used in channel-adaptive mode. Therefore, this API is not * applicable if the codec is created to operate in super-wideband mode. * * Through this API, users can enforce a frame-size for all values of * bottleneck. Then iSAC will not automatically change the frame-size. * * * Input: * - ISAC_main_inst : ISAC instance. * - rateBPS : initial value of bottleneck in bits/second * 10000 <= rateBPS <= 56000 is accepted * For default bottleneck set rateBPS = 0 * - frameSizeMs : number of milliseconds per frame (30 or 60) * - enforceFrameSize : 1 to enforce the given frame-size through * out the adaptation process, 0 to let iSAC * change the frame-size if required. * * Return value : 0 - ok * -1 - Error */ int16_t WebRtcIsac_ControlBwe(ISACStruct* ISAC_main_inst, int32_t rateBPS, int frameSizeMs, int16_t enforceFrameSize); /****************************************************************************** * WebRtcIsac_ReadFrameLen(...) * * This function returns the length of the frame represented in the packet. * * Input: * - encoded : Encoded bit-stream * * Output: * - frameLength : Length of frame in packet (in samples) * */ int16_t WebRtcIsac_ReadFrameLen(const ISACStruct* ISAC_main_inst, const uint8_t* encoded, int16_t* frameLength); /****************************************************************************** * WebRtcIsac_version(...) * * This function returns the version number. * * Output: * - version : Pointer to character string * */ void WebRtcIsac_version(char* version); /****************************************************************************** * WebRtcIsac_GetErrorCode(...) * * This function can be used to check the error code of an iSAC instance. When * a function returns -1 a error code will be set for that instance. The * function below extract the code of the last error that occurred in the * specified instance. * * Input: * - ISAC_main_inst : ISAC instance * * Return value : Error code */ int16_t WebRtcIsac_GetErrorCode(ISACStruct* ISAC_main_inst); /**************************************************************************** * WebRtcIsac_GetUplinkBw(...) * * This function outputs the target bottleneck of the codec. In * channel-adaptive mode, the target bottleneck is specified through in-band * signalling retreived by bandwidth estimator. * In channel-independent, also called instantaneous mode, the target * bottleneck is provided to the encoder by calling xxx_control(...). If * xxx_control is never called the default values is returned. The default * value for bottleneck at 16 kHz encoder sampling rate is 32000 bits/sec, * and it is 56000 bits/sec for 32 kHz sampling rate. * Note that the output is the iSAC internal operating bottleneck which might * differ slightly from the one provided through xxx_control(). * * Input: * - ISAC_main_inst : iSAC instance * * Output: * - *bottleneck : bottleneck in bits/sec * * Return value : -1 if error happens * 0 bit-rates computed correctly. */ int16_t WebRtcIsac_GetUplinkBw(ISACStruct* ISAC_main_inst, int32_t* bottleneck); /****************************************************************************** * WebRtcIsac_SetMaxPayloadSize(...) * * This function sets a limit for the maximum payload size of iSAC. The same * value is used both for 30 and 60 ms packets. If the encoder sampling rate * is 16 kHz the maximum payload size is between 120 and 400 bytes. If the * encoder sampling rate is 32 kHz the maximum payload size is between 120 * and 600 bytes. * * If an out of range limit is used, the function returns -1, but the closest * valid value will be applied. * * --------------- * IMPORTANT NOTES * --------------- * The size of a packet is limited to the minimum of 'max-payload-size' and * 'max-rate.' For instance, let's assume the max-payload-size is set to * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms * frame-size. Then a packet with a frame-size of 30 ms is limited to 150, * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to * 170 bytes, i.e. min(170, 300). * * Input: * - ISAC_main_inst : iSAC instance * - maxPayloadBytes : maximum size of the payload in bytes * valid values are between 120 and 400 bytes * if encoder sampling rate is 16 kHz. For * 32 kHz encoder sampling rate valid values * are between 120 and 600 bytes. * * Return value : 0 if successful * -1 if error happens */ int16_t WebRtcIsac_SetMaxPayloadSize(ISACStruct* ISAC_main_inst, int16_t maxPayloadBytes); /****************************************************************************** * WebRtcIsac_SetMaxRate(...) * * This function sets the maximum rate which the codec may not exceed for * any signal packet. The maximum rate is defined and payload-size per * frame-size in bits per second. * * The codec has a maximum rate of 53400 bits per second (200 bytes per 30 * ms) if the encoder sampling rate is 16kHz, and 160 kbps (600 bytes/30 ms) * if the encoder sampling rate is 32 kHz. * * It is possible to set a maximum rate between 32000 and 53400 bits/sec * in wideband mode, and 32000 to 160000 bits/sec in super-wideband mode. * * If an out of range limit is used, the function returns -1, but the closest * valid value will be applied. * * --------------- * IMPORTANT NOTES * --------------- * The size of a packet is limited to the minimum of 'max-payload-size' and * 'max-rate.' For instance, let's assume the max-payload-size is set to * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms * frame-size. Then a packet with a frame-size of 30 ms is limited to 150, * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to * 170 bytes, min(170, 300). * * Input: * - ISAC_main_inst : iSAC instance * - maxRate : maximum rate in bits per second, * valid values are 32000 to 53400 bits/sec in * wideband mode, and 32000 to 160000 bits/sec in * super-wideband mode. * * Return value : 0 if successful * -1 if error happens */ int16_t WebRtcIsac_SetMaxRate(ISACStruct* ISAC_main_inst, int32_t maxRate); /****************************************************************************** * WebRtcIsac_DecSampRate() * Return the sampling rate of the decoded audio. * * Input: * - ISAC_main_inst : iSAC instance * * Return value : sampling frequency in Hertz. * */ uint16_t WebRtcIsac_DecSampRate(ISACStruct* ISAC_main_inst); /****************************************************************************** * WebRtcIsac_EncSampRate() * * Input: * - ISAC_main_inst : iSAC instance * * Return value : sampling rate in Hertz. * */ uint16_t WebRtcIsac_EncSampRate(ISACStruct* ISAC_main_inst); /****************************************************************************** * WebRtcIsac_SetDecSampRate() * Set the sampling rate of the decoder. Initialization of the decoder WILL * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz * which is set when the instance is created. * * Input: * - ISAC_main_inst : iSAC instance * - sampRate : sampling rate in Hertz. * * Return value : 0 if successful * -1 if failed. */ int16_t WebRtcIsac_SetDecSampRate(ISACStruct* ISAC_main_inst, uint16_t samp_rate_hz); /****************************************************************************** * WebRtcIsac_SetEncSampRate() * Set the sampling rate of the encoder. Initialization of the encoder WILL * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz * which is set when the instance is created. The encoding-mode and the * bottleneck remain unchanged by this call, however, the maximum rate and * maximum payload-size will reset to their default value. * * Input: * - ISAC_main_inst : iSAC instance * - sampRate : sampling rate in Hertz. * * Return value : 0 if successful * -1 if failed. */ int16_t WebRtcIsac_SetEncSampRate(ISACStruct* ISAC_main_inst, uint16_t sample_rate_hz); /****************************************************************************** * WebRtcIsac_GetNewBitStream(...) * * This function returns encoded data, with the recieved bwe-index in the * stream. If the rate is set to a value less than bottleneck of codec * the new bistream will be re-encoded with the given target rate. * It should always return a complete packet, i.e. only called once * even for 60 msec frames. * * NOTE 1! This function does not write in the ISACStruct, it is not allowed. * NOTE 2! Currently not implemented for SWB mode. * NOTE 3! Rates larger than the bottleneck of the codec will be limited * to the current bottleneck. * * Input: * - ISAC_main_inst : ISAC instance. * - bweIndex : Index of bandwidth estimate to put in new * bitstream * - rate : target rate of the transcoder is bits/sec. * Valid values are the accepted rate in iSAC, * i.e. 10000 to 56000. * - isRCU : if the new bit-stream is an RCU * stream. Note that the rate parameter always indicates the target rate of the * main payload, regardless of 'isRCU' value. * * Output: * - encoded : The encoded data vector * * Return value : >0 - Length (in bytes) of coded data * -1 - Error or called in SWB mode * NOTE! No error code is written to * the struct since it is only allowed to read * the struct. */ int16_t WebRtcIsac_GetNewBitStream(ISACStruct* ISAC_main_inst, int16_t bweIndex, int16_t jitterInfo, int32_t rate, uint8_t* encoded, int16_t isRCU); /**************************************************************************** * WebRtcIsac_GetDownLinkBwIndex(...) * * This function returns index representing the Bandwidth estimate from * other side to this side. * * Input: * - ISAC_main_inst : iSAC struct * * Output: * - bweIndex : Bandwidth estimate to transmit to other side. * */ int16_t WebRtcIsac_GetDownLinkBwIndex(ISACStruct* ISAC_main_inst, int16_t* bweIndex, int16_t* jitterInfo); /**************************************************************************** * WebRtcIsac_UpdateUplinkBw(...) * * This function takes an index representing the Bandwidth estimate from * this side to other side and updates BWE. * * Input: * - ISAC_main_inst : iSAC struct * - bweIndex : Bandwidth estimate from other side. * */ int16_t WebRtcIsac_UpdateUplinkBw(ISACStruct* ISAC_main_inst, int16_t bweIndex); /**************************************************************************** * WebRtcIsac_ReadBwIndex(...) * * This function returns the index of the Bandwidth estimate from the bitstream. * * Input: * - encoded : Encoded bitstream * * Output: * - frameLength : Length of frame in packet (in samples) * - bweIndex : Bandwidth estimate in bitstream * */ int16_t WebRtcIsac_ReadBwIndex(const uint8_t* encoded, int16_t* bweIndex); /******************************************************************************* * WebRtcIsac_GetNewFrameLen(...) * * returns the frame lenght (in samples) of the next packet. In the case of * channel-adaptive mode, iSAC decides on its frame lenght based on the * estimated bottleneck this allows a user to prepare for the next packet (at * the encoder) * * The primary usage is in CE to make the iSAC works in channel-adaptive mode * * Input: * - ISAC_main_inst : iSAC struct * * Return Value : frame lenght in samples * */ int16_t WebRtcIsac_GetNewFrameLen(ISACStruct* ISAC_main_inst); /**************************************************************************** * WebRtcIsac_GetRedPayload(...) * * Populates "encoded" with the redundant payload of the recently encoded * frame. This function has to be called once that WebRtcIsac_Encode(...) * returns a positive value. Regardless of the frame-size this function will * be called only once after encoding is completed. * * Input: * - ISAC_main_inst : iSAC struct * * Output: * - encoded : the encoded data vector * * * Return value: * : >0 - Length (in bytes) of coded data * : -1 - Error * * */ int16_t WebRtcIsac_GetRedPayload(ISACStruct* ISAC_main_inst, uint8_t* encoded); /**************************************************************************** * WebRtcIsac_DecodeRcu(...) * * This function decodes a redundant (RCU) iSAC frame. Function is called in * NetEq with a stored RCU payload i case of packet loss. Output speech length * will be a multiple of 480 samples: 480 or 960 samples, * depending on the framesize (30 or 60 ms). * * Input: * - ISAC_main_inst : ISAC instance. * - encoded : encoded ISAC RCU frame(s) * - len : bytes in encoded vector * * Output: * - decoded : The decoded vector * * Return value : >0 - number of samples in decoded vector * -1 - Error */ int WebRtcIsac_DecodeRcu(ISACStruct* ISAC_main_inst, const uint8_t* encoded, size_t len, int16_t* decoded, int16_t* speechType); /* If |inst| is a decoder but not an encoder: tell it what sample rate the encoder is using, for bandwidth estimation purposes. */ void WebRtcIsac_SetEncSampRateInDecoder(ISACStruct* inst, int sample_rate_hz); #if defined(__cplusplus) } #endif #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_ISAC_H_ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/0000775000175000017500000000000014475643423026653 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines.c0000664000175000017500000000370614475643423032064 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_coding/codecs/isac/main/source/arith_routines.h" #include "modules/audio_coding/codecs/isac/main/source/settings.h" /* * terminate and return byte stream; * returns the number of bytes in the stream */ int WebRtcIsac_EncTerminate(Bitstr *streamdata) /* in-/output struct containing bitstream */ { uint8_t *stream_ptr; /* point to the right place in the stream buffer */ stream_ptr = streamdata->stream + streamdata->stream_index; /* find minimum length (determined by current interval width) */ if ( streamdata->W_upper > 0x01FFFFFF ) { streamdata->streamval += 0x01000000; /* add carry to buffer */ if (streamdata->streamval < 0x01000000) { /* propagate carry */ while ( !(++(*--stream_ptr)) ); /* put pointer back to the old value */ stream_ptr = streamdata->stream + streamdata->stream_index; } /* write remaining data to bitstream */ *stream_ptr++ = (uint8_t) (streamdata->streamval >> 24); } else { streamdata->streamval += 0x00010000; /* add carry to buffer */ if (streamdata->streamval < 0x00010000) { /* propagate carry */ while ( !(++(*--stream_ptr)) ); /* put pointer back to the old value */ stream_ptr = streamdata->stream + streamdata->stream_index; } /* write remaining data to bitstream */ *stream_ptr++ = (uint8_t) (streamdata->streamval >> 24); *stream_ptr++ = (uint8_t) ((streamdata->streamval >> 16) & 0x00FF); } /* calculate stream length */ return (int)(stream_ptr - streamdata->stream); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines.h0000664000175000017500000000545714475643423032076 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * arith_routines.h * * Functions for arithmetic coding. * */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_ #include "modules/audio_coding/codecs/isac/main/source/structs.h" int WebRtcIsac_EncLogisticMulti2( Bitstr* streamdata, /* in-/output struct containing bitstream */ int16_t* dataQ7, /* input: data vector */ const uint16_t* env, /* input: side info vector defining the width of the pdf */ const int N, /* input: data vector length */ const int16_t isSWB12kHz); /* if the codec is working in 12kHz bandwidth */ /* returns the number of bytes in the stream */ int WebRtcIsac_EncTerminate( Bitstr* streamdata); /* in-/output struct containing bitstream */ /* returns the number of bytes in the stream so far */ int WebRtcIsac_DecLogisticMulti2( int16_t* data, /* output: data vector */ Bitstr* streamdata, /* in-/output struct containing bitstream */ const uint16_t* env, /* input: side info vector defining the width of the pdf */ const int16_t* dither, /* input: dither vector */ const int N, /* input: data vector length */ const int16_t isSWB12kHz); /* if the codec is working in 12kHz bandwidth */ void WebRtcIsac_EncHistMulti( Bitstr* streamdata, /* in-/output struct containing bitstream */ const int* data, /* input: data vector */ const uint16_t* const* cdf, /* input: array of cdf arrays */ const int N); /* input: data vector length */ int WebRtcIsac_DecHistBisectMulti( int* data, /* output: data vector */ Bitstr* streamdata, /* in-/output struct containing bitstream */ const uint16_t* const* cdf, /* input: array of cdf arrays */ const uint16_t* cdf_size, /* input: array of cdf table sizes+1 (power of two: 2^k) */ const int N); /* input: data vector length */ int WebRtcIsac_DecHistOneStepMulti( int* data, /* output: data vector */ Bitstr* streamdata, /* in-/output struct containing bitstream */ const uint16_t* const* cdf, /* input: array of cdf arrays */ const uint16_t* init_index, /* input: vector of initial cdf table search entries */ const int N); /* input: data vector length */ #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_ */ ././@PaxHeader0000000000000000000000000000020500000000000010212 xustar00111 path=webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines_hist.c 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines_hist.0000664000175000017500000002115314475643423032744 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_coding/codecs/isac/main/source/settings.h" #include "modules/audio_coding/codecs/isac/main/source/arith_routines.h" /* * code symbols into arithmetic bytestream */ void WebRtcIsac_EncHistMulti(Bitstr *streamdata, /* in-/output struct containing bitstream */ const int *data, /* input: data vector */ const uint16_t *const *cdf, /* input: array of cdf arrays */ const int N) /* input: data vector length */ { uint32_t W_lower, W_upper; uint32_t W_upper_LSB, W_upper_MSB; uint8_t *stream_ptr; uint8_t *stream_ptr_carry; uint32_t cdf_lo, cdf_hi; int k; /* point to beginning of stream buffer */ stream_ptr = streamdata->stream + streamdata->stream_index; W_upper = streamdata->W_upper; for (k=N; k>0; k--) { /* fetch cdf_lower and cdf_upper from cdf tables */ cdf_lo = (uint32_t) *(*cdf + *data); cdf_hi = (uint32_t) *(*cdf++ + *data++ + 1); /* update interval */ W_upper_LSB = W_upper & 0x0000FFFF; W_upper_MSB = W_upper >> 16; W_lower = W_upper_MSB * cdf_lo; W_lower += (W_upper_LSB * cdf_lo) >> 16; W_upper = W_upper_MSB * cdf_hi; W_upper += (W_upper_LSB * cdf_hi) >> 16; /* shift interval such that it begins at zero */ W_upper -= ++W_lower; /* add integer to bitstream */ streamdata->streamval += W_lower; /* handle carry */ if (streamdata->streamval < W_lower) { /* propagate carry */ stream_ptr_carry = stream_ptr; while (!(++(*--stream_ptr_carry))); } /* renormalize interval, store most significant byte of streamval and update streamval */ while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */ { W_upper <<= 8; *stream_ptr++ = (uint8_t) (streamdata->streamval >> 24); streamdata->streamval <<= 8; } } /* calculate new stream_index */ streamdata->stream_index = (int)(stream_ptr - streamdata->stream); streamdata->W_upper = W_upper; return; } /* * function to decode more symbols from the arithmetic bytestream, using method of bisection * cdf tables should be of size 2^k-1 (which corresponds to an alphabet size of 2^k-2) */ int WebRtcIsac_DecHistBisectMulti(int *data, /* output: data vector */ Bitstr *streamdata, /* in-/output struct containing bitstream */ const uint16_t *const *cdf, /* input: array of cdf arrays */ const uint16_t *cdf_size, /* input: array of cdf table sizes+1 (power of two: 2^k) */ const int N) /* input: data vector length */ { uint32_t W_lower, W_upper; uint32_t W_tmp; uint32_t W_upper_LSB, W_upper_MSB; uint32_t streamval; const uint8_t *stream_ptr; const uint16_t *cdf_ptr; int size_tmp; int k; W_lower = 0; //to remove warning -DH stream_ptr = streamdata->stream + streamdata->stream_index; W_upper = streamdata->W_upper; if (W_upper == 0) /* Should not be possible in normal operation */ return -2; if (streamdata->stream_index == 0) /* first time decoder is called for this stream */ { /* read first word from bytestream */ streamval = *stream_ptr << 24; streamval |= *++stream_ptr << 16; streamval |= *++stream_ptr << 8; streamval |= *++stream_ptr; } else { streamval = streamdata->streamval; } for (k=N; k>0; k--) { /* find the integer *data for which streamval lies in [W_lower+1, W_upper] */ W_upper_LSB = W_upper & 0x0000FFFF; W_upper_MSB = W_upper >> 16; /* start halfway the cdf range */ size_tmp = *cdf_size++ >> 1; cdf_ptr = *cdf + (size_tmp - 1); /* method of bisection */ for ( ;; ) { W_tmp = W_upper_MSB * *cdf_ptr; W_tmp += (W_upper_LSB * *cdf_ptr) >> 16; size_tmp >>= 1; if (size_tmp == 0) break; if (streamval > W_tmp) { W_lower = W_tmp; cdf_ptr += size_tmp; } else { W_upper = W_tmp; cdf_ptr -= size_tmp; } } if (streamval > W_tmp) { W_lower = W_tmp; *data++ = (int)(cdf_ptr - *cdf++); } else { W_upper = W_tmp; *data++ = (int)(cdf_ptr - *cdf++ - 1); } /* shift interval to start at zero */ W_upper -= ++W_lower; /* add integer to bitstream */ streamval -= W_lower; /* renormalize interval and update streamval */ while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */ { /* read next byte from stream */ streamval = (streamval << 8) | *++stream_ptr; W_upper <<= 8; } if (W_upper == 0) /* Should not be possible in normal operation */ return -2; } streamdata->stream_index = (int)(stream_ptr - streamdata->stream); streamdata->W_upper = W_upper; streamdata->streamval = streamval; /* find number of bytes in original stream (determined by current interval width) */ if ( W_upper > 0x01FFFFFF ) return streamdata->stream_index - 2; else return streamdata->stream_index - 1; } /* * function to decode more symbols from the arithmetic bytestream, taking single step up or * down at a time * cdf tables can be of arbitrary size, but large tables may take a lot of iterations */ int WebRtcIsac_DecHistOneStepMulti(int *data, /* output: data vector */ Bitstr *streamdata, /* in-/output struct containing bitstream */ const uint16_t *const *cdf, /* input: array of cdf arrays */ const uint16_t *init_index, /* input: vector of initial cdf table search entries */ const int N) /* input: data vector length */ { uint32_t W_lower, W_upper; uint32_t W_tmp; uint32_t W_upper_LSB, W_upper_MSB; uint32_t streamval; const uint8_t *stream_ptr; const uint16_t *cdf_ptr; int k; stream_ptr = streamdata->stream + streamdata->stream_index; W_upper = streamdata->W_upper; if (W_upper == 0) /* Should not be possible in normal operation */ return -2; if (streamdata->stream_index == 0) /* first time decoder is called for this stream */ { /* read first word from bytestream */ streamval = (uint32_t)(*stream_ptr) << 24; streamval |= (uint32_t)(*++stream_ptr) << 16; streamval |= (uint32_t)(*++stream_ptr) << 8; streamval |= (uint32_t)(*++stream_ptr); } else { streamval = streamdata->streamval; } for (k=N; k>0; k--) { /* find the integer *data for which streamval lies in [W_lower+1, W_upper] */ W_upper_LSB = W_upper & 0x0000FFFF; W_upper_MSB = W_upper >> 16; /* start at the specified table entry */ cdf_ptr = *cdf + (*init_index++); W_tmp = W_upper_MSB * *cdf_ptr; W_tmp += (W_upper_LSB * *cdf_ptr) >> 16; if (streamval > W_tmp) { for ( ;; ) { W_lower = W_tmp; if (cdf_ptr[0]==65535) /* range check */ return -3; W_tmp = W_upper_MSB * *++cdf_ptr; W_tmp += (W_upper_LSB * *cdf_ptr) >> 16; if (streamval <= W_tmp) break; } W_upper = W_tmp; *data++ = (int)(cdf_ptr - *cdf++ - 1); } else { for ( ;; ) { W_upper = W_tmp; --cdf_ptr; if (cdf_ptr<*cdf) { /* range check */ return -3; } W_tmp = W_upper_MSB * *cdf_ptr; W_tmp += (W_upper_LSB * *cdf_ptr) >> 16; if (streamval > W_tmp) break; } W_lower = W_tmp; *data++ = (int)(cdf_ptr - *cdf++); } /* shift interval to start at zero */ W_upper -= ++W_lower; /* add integer to bitstream */ streamval -= W_lower; /* renormalize interval and update streamval */ while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */ { /* read next byte from stream */ streamval = (streamval << 8) | *++stream_ptr; W_upper <<= 8; } } streamdata->stream_index = (int)(stream_ptr - streamdata->stream); streamdata->W_upper = W_upper; streamdata->streamval = streamval; /* find number of bytes in original stream (determined by current interval width) */ if ( W_upper > 0x01FFFFFF ) return streamdata->stream_index - 2; else return streamdata->stream_index - 1; } ././@PaxHeader0000000000000000000000000000020700000000000010214 xustar00113 path=webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines_logist.c 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines_logis0000664000175000017500000002211214475643423033030 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * arith_routines.h * * This file contains functions for arithmatically encoding and * decoding DFT coefficients. * */ #include "modules/audio_coding/codecs/isac/main/source/arith_routines.h" static const int32_t kHistEdgesQ15[51] = { -327680, -314573, -301466, -288359, -275252, -262144, -249037, -235930, -222823, -209716, -196608, -183501, -170394, -157287, -144180, -131072, -117965, -104858, -91751, -78644, -65536, -52429, -39322, -26215, -13108, 0, 13107, 26214, 39321, 52428, 65536, 78643, 91750, 104857, 117964, 131072, 144179, 157286, 170393, 183500, 196608, 209715, 222822, 235929, 249036, 262144, 275251, 288358, 301465, 314572, 327680}; static const int kCdfSlopeQ0[51] = { /* Q0 */ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 13, 23, 47, 87, 154, 315, 700, 1088, 2471, 6064, 14221, 21463, 36634, 36924, 19750, 13270, 5806, 2312, 1095, 660, 316, 145, 86, 41, 32, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 0}; static const int kCdfQ16[51] = { /* Q16 */ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 29, 38, 57, 92, 153, 279, 559, 994, 1983, 4408, 10097, 18682, 33336, 48105, 56005, 61313, 63636, 64560, 64998, 65262, 65389, 65447, 65481, 65497, 65510, 65512, 65514, 65516, 65518, 65520, 65522, 65524, 65526, 65528, 65530, 65532, 65534, 65535}; /* function to be converted to fixed point */ static __inline uint32_t piecewise(int32_t xinQ15) { int32_t ind, qtmp1, qtmp2, qtmp3; uint32_t tmpUW32; qtmp2 = xinQ15; if (qtmp2 < kHistEdgesQ15[0]) { qtmp2 = kHistEdgesQ15[0]; } if (qtmp2 > kHistEdgesQ15[50]) { qtmp2 = kHistEdgesQ15[50]; } qtmp1 = qtmp2 - kHistEdgesQ15[0]; /* Q15 - Q15 = Q15 */ ind = (qtmp1 * 5) >> 16; /* 2^16 / 5 = 0.4 in Q15 */ /* Q15 -> Q0 */ qtmp1 = qtmp2 - kHistEdgesQ15[ind]; /* Q15 - Q15 = Q15 */ qtmp2 = kCdfSlopeQ0[ind] * qtmp1; /* Q0 * Q15 = Q15 */ qtmp3 = qtmp2>>15; /* Q15 -> Q0 */ tmpUW32 = kCdfQ16[ind] + qtmp3; /* Q0 + Q0 = Q0 */ return tmpUW32; } int WebRtcIsac_EncLogisticMulti2( Bitstr *streamdata, /* in-/output struct containing bitstream */ int16_t *dataQ7, /* input: data vector */ const uint16_t *envQ8, /* input: side info vector defining the width of the pdf */ const int N, /* input: data vector length / 2 */ const int16_t isSWB12kHz) { uint32_t W_lower, W_upper; uint32_t W_upper_LSB, W_upper_MSB; uint8_t *stream_ptr; uint8_t *maxStreamPtr; uint8_t *stream_ptr_carry; uint32_t cdf_lo, cdf_hi; int k; /* point to beginning of stream buffer */ stream_ptr = streamdata->stream + streamdata->stream_index; W_upper = streamdata->W_upper; maxStreamPtr = streamdata->stream + STREAM_SIZE_MAX_60 - 1; for (k = 0; k < N; k++) { /* compute cdf_lower and cdf_upper by evaluating the piecewise linear cdf */ cdf_lo = piecewise((*dataQ7 - 64) * *envQ8); cdf_hi = piecewise((*dataQ7 + 64) * *envQ8); /* test and clip if probability gets too small */ while (cdf_lo+1 >= cdf_hi) { /* clip */ if (*dataQ7 > 0) { *dataQ7 -= 128; cdf_hi = cdf_lo; cdf_lo = piecewise((*dataQ7 - 64) * *envQ8); } else { *dataQ7 += 128; cdf_lo = cdf_hi; cdf_hi = piecewise((*dataQ7 + 64) * *envQ8); } } dataQ7++; // increment only once per 4 iterations for SWB-16kHz or WB // increment only once per 2 iterations for SWB-12kHz envQ8 += (isSWB12kHz)? (k & 1):((k & 1) & (k >> 1)); /* update interval */ W_upper_LSB = W_upper & 0x0000FFFF; W_upper_MSB = W_upper >> 16; W_lower = W_upper_MSB * cdf_lo; W_lower += (W_upper_LSB * cdf_lo) >> 16; W_upper = W_upper_MSB * cdf_hi; W_upper += (W_upper_LSB * cdf_hi) >> 16; /* shift interval such that it begins at zero */ W_upper -= ++W_lower; /* add integer to bitstream */ streamdata->streamval += W_lower; /* handle carry */ if (streamdata->streamval < W_lower) { /* propagate carry */ stream_ptr_carry = stream_ptr; while (!(++(*--stream_ptr_carry))); } /* renormalize interval, store most significant byte of streamval and update streamval */ while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */ { W_upper <<= 8; *stream_ptr++ = (uint8_t) (streamdata->streamval >> 24); if(stream_ptr > maxStreamPtr) { return -ISAC_DISALLOWED_BITSTREAM_LENGTH; } streamdata->streamval <<= 8; } } /* calculate new stream_index */ streamdata->stream_index = (int)(stream_ptr - streamdata->stream); streamdata->W_upper = W_upper; return 0; } int WebRtcIsac_DecLogisticMulti2( int16_t *dataQ7, /* output: data vector */ Bitstr *streamdata, /* in-/output struct containing bitstream */ const uint16_t *envQ8, /* input: side info vector defining the width of the pdf */ const int16_t *ditherQ7,/* input: dither vector */ const int N, /* input: data vector length */ const int16_t isSWB12kHz) { uint32_t W_lower, W_upper; uint32_t W_tmp; uint32_t W_upper_LSB, W_upper_MSB; uint32_t streamval; const uint8_t *stream_ptr; uint32_t cdf_tmp; int16_t candQ7; int k; // Position just past the end of the stream. STREAM_SIZE_MAX_60 instead of // STREAM_SIZE_MAX (which is the size of the allocated buffer) because that's // the limit to how much data is filled in. const uint8_t* const stream_end = streamdata->stream + STREAM_SIZE_MAX_60; stream_ptr = streamdata->stream + streamdata->stream_index; W_upper = streamdata->W_upper; if (streamdata->stream_index == 0) /* first time decoder is called for this stream */ { /* read first word from bytestream */ if (stream_ptr + 3 >= stream_end) return -1; // Would read out of bounds. Malformed input? streamval = *stream_ptr << 24; streamval |= *++stream_ptr << 16; streamval |= *++stream_ptr << 8; streamval |= *++stream_ptr; } else { streamval = streamdata->streamval; } for (k = 0; k < N; k++) { /* find the integer *data for which streamval lies in [W_lower+1, W_upper] */ W_upper_LSB = W_upper & 0x0000FFFF; W_upper_MSB = W_upper >> 16; /* find first candidate by inverting the logistic cdf */ candQ7 = - *ditherQ7 + 64; cdf_tmp = piecewise(candQ7 * *envQ8); W_tmp = W_upper_MSB * cdf_tmp; W_tmp += (W_upper_LSB * cdf_tmp) >> 16; if (streamval > W_tmp) { W_lower = W_tmp; candQ7 += 128; cdf_tmp = piecewise(candQ7 * *envQ8); W_tmp = W_upper_MSB * cdf_tmp; W_tmp += (W_upper_LSB * cdf_tmp) >> 16; while (streamval > W_tmp) { W_lower = W_tmp; candQ7 += 128; cdf_tmp = piecewise(candQ7 * *envQ8); W_tmp = W_upper_MSB * cdf_tmp; W_tmp += (W_upper_LSB * cdf_tmp) >> 16; /* error check */ if (W_lower == W_tmp) return -1; } W_upper = W_tmp; /* another sample decoded */ *dataQ7 = candQ7 - 64; } else { W_upper = W_tmp; candQ7 -= 128; cdf_tmp = piecewise(candQ7 * *envQ8); W_tmp = W_upper_MSB * cdf_tmp; W_tmp += (W_upper_LSB * cdf_tmp) >> 16; while ( !(streamval > W_tmp) ) { W_upper = W_tmp; candQ7 -= 128; cdf_tmp = piecewise(candQ7 * *envQ8); W_tmp = W_upper_MSB * cdf_tmp; W_tmp += (W_upper_LSB * cdf_tmp) >> 16; /* error check */ if (W_upper == W_tmp) return -1; } W_lower = W_tmp; /* another sample decoded */ *dataQ7 = candQ7 + 64; } ditherQ7++; dataQ7++; // increment only once per 4 iterations for SWB-16kHz or WB // increment only once per 2 iterations for SWB-12kHz envQ8 += (isSWB12kHz)? (k & 1):((k & 1) & (k >> 1)); /* shift interval to start at zero */ W_upper -= ++W_lower; /* add integer to bitstream */ streamval -= W_lower; /* renormalize interval and update streamval */ while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */ { /* read next byte from stream */ if (stream_ptr + 1 >= stream_end) return -1; // Would read out of bounds. Malformed input? streamval = (streamval << 8) | *++stream_ptr; W_upper <<= 8; } } streamdata->stream_index = (int)(stream_ptr - streamdata->stream); streamdata->W_upper = W_upper; streamdata->streamval = streamval; /* find number of bytes in original stream (determined by current interval width) */ if ( W_upper > 0x01FFFFFF ) return streamdata->stream_index - 2; else return streamdata->stream_index - 1; } ././@PaxHeader0000000000000000000000000000020500000000000010212 xustar00111 path=webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/audio_decoder_isac.cc 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/audio_decoder_isac.c0000664000175000017500000000125214475643423032604 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h" #include "modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h" namespace webrtc { // Explicit instantiation: template class AudioDecoderIsacT; } // namespace webrtc ././@PaxHeader0000000000000000000000000000020500000000000010212 xustar00111 path=webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac.cc 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac.c0000664000175000017500000000125214475643423032616 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h" #include "modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h" namespace webrtc { // Explicit instantiation: template class AudioEncoderIsacT; } // namespace webrtc ././@PaxHeader0000000000000000000000000000020500000000000010212 xustar00111 path=webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.0000664000175000017500000007246714475643423032727 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * BwEstimator.c * * This file contains the code for the Bandwidth Estimator designed * for iSAC. * */ #include #include #include "modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h" #include "modules/audio_coding/codecs/isac/main/source/settings.h" #include "modules/audio_coding/codecs/isac/main/include/isac.h" #include "rtc_base/checks.h" /* array of quantization levels for bottle neck info; Matlab code: */ /* sprintf('%4.1ff, ', logspace(log10(5000), log10(40000), 12)) */ static const float kQRateTableWb[12] = { 10000.0f, 11115.3f, 12355.1f, 13733.1f, 15264.8f, 16967.3f, 18859.8f, 20963.3f, 23301.4f, 25900.3f, 28789.0f, 32000.0f}; static const float kQRateTableSwb[24] = { 10000.0f, 11115.3f, 12355.1f, 13733.1f, 15264.8f, 16967.3f, 18859.8f, 20963.3f, 23153.1f, 25342.9f, 27532.7f, 29722.5f, 31912.3f, 34102.1f, 36291.9f, 38481.7f, 40671.4f, 42861.2f, 45051.0f, 47240.8f, 49430.6f, 51620.4f, 53810.2f, 56000.0f, }; int32_t WebRtcIsac_InitBandwidthEstimator( BwEstimatorstr* bwest_str, enum IsacSamplingRate encoderSampRate, enum IsacSamplingRate decoderSampRate) { switch(encoderSampRate) { case kIsacWideband: { bwest_str->send_bw_avg = INIT_BN_EST_WB; break; } case kIsacSuperWideband: { bwest_str->send_bw_avg = INIT_BN_EST_SWB; break; } } switch(decoderSampRate) { case kIsacWideband: { bwest_str->prev_frame_length = INIT_FRAME_LEN_WB; bwest_str->rec_bw_inv = 1.0f / (INIT_BN_EST_WB + INIT_HDR_RATE_WB); bwest_str->rec_bw = (int32_t)INIT_BN_EST_WB; bwest_str->rec_bw_avg_Q = INIT_BN_EST_WB; bwest_str->rec_bw_avg = INIT_BN_EST_WB + INIT_HDR_RATE_WB; bwest_str->rec_header_rate = INIT_HDR_RATE_WB; break; } case kIsacSuperWideband: { bwest_str->prev_frame_length = INIT_FRAME_LEN_SWB; bwest_str->rec_bw_inv = 1.0f / (INIT_BN_EST_SWB + INIT_HDR_RATE_SWB); bwest_str->rec_bw = (int32_t)INIT_BN_EST_SWB; bwest_str->rec_bw_avg_Q = INIT_BN_EST_SWB; bwest_str->rec_bw_avg = INIT_BN_EST_SWB + INIT_HDR_RATE_SWB; bwest_str->rec_header_rate = INIT_HDR_RATE_SWB; break; } } bwest_str->prev_rec_rtp_number = 0; bwest_str->prev_rec_arr_ts = 0; bwest_str->prev_rec_send_ts = 0; bwest_str->prev_rec_rtp_rate = 1.0f; bwest_str->last_update_ts = 0; bwest_str->last_reduction_ts = 0; bwest_str->count_tot_updates_rec = -9; bwest_str->rec_jitter = 10.0f; bwest_str->rec_jitter_short_term = 0.0f; bwest_str->rec_jitter_short_term_abs = 5.0f; bwest_str->rec_max_delay = 10.0f; bwest_str->rec_max_delay_avg_Q = 10.0f; bwest_str->num_pkts_rec = 0; bwest_str->send_max_delay_avg = 10.0f; bwest_str->hsn_detect_rec = 0; bwest_str->num_consec_rec_pkts_over_30k = 0; bwest_str->hsn_detect_snd = 0; bwest_str->num_consec_snt_pkts_over_30k = 0; bwest_str->in_wait_period = 0; bwest_str->change_to_WB = 0; bwest_str->numConsecLatePkts = 0; bwest_str->consecLatency = 0; bwest_str->inWaitLatePkts = 0; bwest_str->senderTimestamp = 0; bwest_str->receiverTimestamp = 0; bwest_str->external_bw_info.in_use = 0; return 0; } /* This function updates both bottle neck rates */ /* Parameters: */ /* rtp_number - value from RTP packet, from NetEq */ /* frame length - length of signal frame in ms, from iSAC decoder */ /* send_ts - value in RTP header giving send time in samples */ /* arr_ts - value given by timeGetTime() time of arrival in samples of packet from NetEq */ /* pksize - size of packet in bytes, from NetEq */ /* Index - integer (range 0...23) indicating bottle neck & jitter as estimated by other side */ /* returns 0 if everything went fine, -1 otherwise */ int16_t WebRtcIsac_UpdateBandwidthEstimator( BwEstimatorstr* bwest_str, const uint16_t rtp_number, const int32_t frame_length, const uint32_t send_ts, const uint32_t arr_ts, const size_t pksize /*, const uint16_t Index*/) { float weight = 0.0f; float curr_bw_inv = 0.0f; float rec_rtp_rate; float t_diff_proj; float arr_ts_diff; float send_ts_diff; float arr_time_noise; float arr_time_noise_abs; float delay_correction_factor = 1; float late_diff = 0.0f; int immediate_set = 0; int num_pkts_expected; RTC_DCHECK(!bwest_str->external_bw_info.in_use); // We have to adjust the header-rate if the first packet has a // frame-size different than the initialized value. if ( frame_length != bwest_str->prev_frame_length ) { bwest_str->rec_header_rate = (float)HEADER_SIZE * 8.0f * 1000.0f / (float)frame_length; /* bits/s */ } /* UPDATE ESTIMATES ON THIS SIDE */ /* compute far-side transmission rate */ rec_rtp_rate = ((float)pksize * 8.0f * 1000.0f / (float)frame_length) + bwest_str->rec_header_rate; // rec_rtp_rate packet bits/s + header bits/s /* check for timer wrap-around */ if (arr_ts < bwest_str->prev_rec_arr_ts) { bwest_str->prev_rec_arr_ts = arr_ts; bwest_str->last_update_ts = arr_ts; bwest_str->last_reduction_ts = arr_ts + 3*FS; bwest_str->num_pkts_rec = 0; /* store frame length */ bwest_str->prev_frame_length = frame_length; /* store far-side transmission rate */ bwest_str->prev_rec_rtp_rate = rec_rtp_rate; /* store far-side RTP time stamp */ bwest_str->prev_rec_rtp_number = rtp_number; return 0; } bwest_str->num_pkts_rec++; /* check that it's not one of the first 9 packets */ if ( bwest_str->count_tot_updates_rec > 0 ) { if(bwest_str->in_wait_period > 0 ) { bwest_str->in_wait_period--; } bwest_str->inWaitLatePkts -= ((bwest_str->inWaitLatePkts > 0)? 1:0); send_ts_diff = (float)(send_ts - bwest_str->prev_rec_send_ts); if (send_ts_diff <= (16 * frame_length)*2) //doesn't allow for a dropped packet, not sure necessary to be // that strict -DH { /* if not been updated for a long time, reduce the BN estimate */ if((uint32_t)(arr_ts - bwest_str->last_update_ts) * 1000.0f / FS > 3000) { //how many frames should have been received since the last // update if too many have been dropped or there have been // big delays won't allow this reduction may no longer need // the send_ts_diff here num_pkts_expected = (int)(((float)(arr_ts - bwest_str->last_update_ts) * 1000.0f /(float) FS) / (float)frame_length); if(((float)bwest_str->num_pkts_rec/(float)num_pkts_expected) > 0.9) { float inv_bitrate = (float) pow( 0.99995, (double)((uint32_t)(arr_ts - bwest_str->last_reduction_ts)*1000.0f/FS) ); if ( inv_bitrate ) { bwest_str->rec_bw_inv /= inv_bitrate; //precautionary, likely never necessary if (bwest_str->hsn_detect_snd && bwest_str->hsn_detect_rec) { if (bwest_str->rec_bw_inv > 0.000066f) { bwest_str->rec_bw_inv = 0.000066f; } } } else { bwest_str->rec_bw_inv = 1.0f / (INIT_BN_EST_WB + INIT_HDR_RATE_WB); } /* reset time-since-update counter */ bwest_str->last_reduction_ts = arr_ts; } else //reset here? { bwest_str->last_reduction_ts = arr_ts + 3*FS; bwest_str->last_update_ts = arr_ts; bwest_str->num_pkts_rec = 0; } } } else { bwest_str->last_reduction_ts = arr_ts + 3*FS; bwest_str->last_update_ts = arr_ts; bwest_str->num_pkts_rec = 0; } /* temporarily speed up adaptation if frame length has changed */ if ( frame_length != bwest_str->prev_frame_length ) { bwest_str->count_tot_updates_rec = 10; bwest_str->rec_header_rate = (float)HEADER_SIZE * 8.0f * 1000.0f / (float)frame_length; /* bits/s */ bwest_str->rec_bw_inv = 1.0f /((float)bwest_str->rec_bw + bwest_str->rec_header_rate); } //////////////////////// arr_ts_diff = (float)(arr_ts - bwest_str->prev_rec_arr_ts); if (send_ts_diff > 0 ) { late_diff = arr_ts_diff - send_ts_diff; } else { late_diff = arr_ts_diff - (float)(16 * frame_length); } if((late_diff > 0) && !bwest_str->inWaitLatePkts) { bwest_str->numConsecLatePkts++; bwest_str->consecLatency += late_diff; } else { bwest_str->numConsecLatePkts = 0; bwest_str->consecLatency = 0; } if(bwest_str->numConsecLatePkts > 50) { float latencyMs = bwest_str->consecLatency/(FS/1000); float averageLatencyMs = latencyMs / bwest_str->numConsecLatePkts; delay_correction_factor = frame_length / (frame_length + averageLatencyMs); immediate_set = 1; bwest_str->inWaitLatePkts = (int16_t)((bwest_str->consecLatency/(FS/1000)) / 30);// + 150; bwest_str->start_wait_period = arr_ts; } /////////////////////////////////////////////// /* update only if previous packet was not lost */ if ( rtp_number == bwest_str->prev_rec_rtp_number + 1 ) { if (!(bwest_str->hsn_detect_snd && bwest_str->hsn_detect_rec)) { if ((arr_ts_diff > (float)(16 * frame_length))) { //1/2 second if ((late_diff > 8000.0f) && !bwest_str->in_wait_period) { delay_correction_factor = 0.7f; bwest_str->in_wait_period = 55; bwest_str->start_wait_period = arr_ts; immediate_set = 1; } //320 ms else if (late_diff > 5120.0f && !bwest_str->in_wait_period) { delay_correction_factor = 0.8f; immediate_set = 1; bwest_str->in_wait_period = 44; bwest_str->start_wait_period = arr_ts; } } } if ((bwest_str->prev_rec_rtp_rate > bwest_str->rec_bw_avg) && (rec_rtp_rate > bwest_str->rec_bw_avg) && !bwest_str->in_wait_period) { /* test if still in initiation period and increment counter */ if (bwest_str->count_tot_updates_rec++ > 99) { /* constant weight after initiation part */ weight = 0.01f; } else { /* weight decreases with number of updates */ weight = 1.0f / (float) bwest_str->count_tot_updates_rec; } /* Bottle Neck Estimation */ /* limit outliers */ /* if more than 25 ms too much */ if (arr_ts_diff > frame_length * FS/1000 + 400.0f) { // in samples, why 25ms?? arr_ts_diff = frame_length * FS/1000 + 400.0f; } if(arr_ts_diff < (frame_length * FS/1000) - 160.0f) { /* don't allow it to be less than frame rate - 10 ms */ arr_ts_diff = (float)frame_length * FS/1000 - 160.0f; } /* compute inverse receiving rate for last packet */ curr_bw_inv = arr_ts_diff / ((float)(pksize + HEADER_SIZE) * 8.0f * FS); // (180+35)*8*16000 = 27.5 Mbit.... if(curr_bw_inv < (1.0f / (MAX_ISAC_BW + bwest_str->rec_header_rate))) { // don't allow inv rate to be larger than MAX curr_bw_inv = (1.0f / (MAX_ISAC_BW + bwest_str->rec_header_rate)); } /* update bottle neck rate estimate */ bwest_str->rec_bw_inv = weight * curr_bw_inv + (1.0f - weight) * bwest_str->rec_bw_inv; /* reset time-since-update counter */ bwest_str->last_update_ts = arr_ts; bwest_str->last_reduction_ts = arr_ts + 3 * FS; bwest_str->num_pkts_rec = 0; /* Jitter Estimation */ /* projected difference between arrival times */ t_diff_proj = ((float)(pksize + HEADER_SIZE) * 8.0f * 1000.0f) / bwest_str->rec_bw_avg; // difference between projected and actual // arrival time differences arr_time_noise = (float)(arr_ts_diff*1000.0f/FS) - t_diff_proj; arr_time_noise_abs = (float) fabs( arr_time_noise ); /* long term averaged absolute jitter */ bwest_str->rec_jitter = weight * arr_time_noise_abs + (1.0f - weight) * bwest_str->rec_jitter; if (bwest_str->rec_jitter > 10.0f) { bwest_str->rec_jitter = 10.0f; } /* short term averaged absolute jitter */ bwest_str->rec_jitter_short_term_abs = 0.05f * arr_time_noise_abs + 0.95f * bwest_str->rec_jitter_short_term_abs; /* short term averaged jitter */ bwest_str->rec_jitter_short_term = 0.05f * arr_time_noise + 0.95f * bwest_str->rec_jitter_short_term; } } } else { // reset time-since-update counter when // receiving the first 9 packets bwest_str->last_update_ts = arr_ts; bwest_str->last_reduction_ts = arr_ts + 3*FS; bwest_str->num_pkts_rec = 0; bwest_str->count_tot_updates_rec++; } /* limit minimum bottle neck rate */ if (bwest_str->rec_bw_inv > 1.0f / ((float)MIN_ISAC_BW + bwest_str->rec_header_rate)) { bwest_str->rec_bw_inv = 1.0f / ((float)MIN_ISAC_BW + bwest_str->rec_header_rate); } // limit maximum bitrate if (bwest_str->rec_bw_inv < 1.0f / ((float)MAX_ISAC_BW + bwest_str->rec_header_rate)) { bwest_str->rec_bw_inv = 1.0f / ((float)MAX_ISAC_BW + bwest_str->rec_header_rate); } /* store frame length */ bwest_str->prev_frame_length = frame_length; /* store far-side transmission rate */ bwest_str->prev_rec_rtp_rate = rec_rtp_rate; /* store far-side RTP time stamp */ bwest_str->prev_rec_rtp_number = rtp_number; // Replace bwest_str->rec_max_delay by the new // value (atomic operation) bwest_str->rec_max_delay = 3.0f * bwest_str->rec_jitter; /* store send and arrival time stamp */ bwest_str->prev_rec_arr_ts = arr_ts ; bwest_str->prev_rec_send_ts = send_ts; /* Replace bwest_str->rec_bw by the new value (atomic operation) */ bwest_str->rec_bw = (int32_t)(1.0f / bwest_str->rec_bw_inv - bwest_str->rec_header_rate); if (immediate_set) { bwest_str->rec_bw = (int32_t) (delay_correction_factor * (float) bwest_str->rec_bw); if (bwest_str->rec_bw < (int32_t) MIN_ISAC_BW) { bwest_str->rec_bw = (int32_t) MIN_ISAC_BW; } bwest_str->rec_bw_avg = bwest_str->rec_bw + bwest_str->rec_header_rate; bwest_str->rec_bw_avg_Q = (float) bwest_str->rec_bw; bwest_str->rec_jitter_short_term = 0.0f; bwest_str->rec_bw_inv = 1.0f / (bwest_str->rec_bw + bwest_str->rec_header_rate); bwest_str->count_tot_updates_rec = 1; immediate_set = 0; bwest_str->consecLatency = 0; bwest_str->numConsecLatePkts = 0; } return 0; } /* This function updates the send bottle neck rate */ /* Index - integer (range 0...23) indicating bottle neck & jitter as estimated by other side */ /* returns 0 if everything went fine, -1 otherwise */ int16_t WebRtcIsac_UpdateUplinkBwImpl( BwEstimatorstr* bwest_str, int16_t index, enum IsacSamplingRate encoderSamplingFreq) { RTC_DCHECK(!bwest_str->external_bw_info.in_use); if((index < 0) || (index > 23)) { return -ISAC_RANGE_ERROR_BW_ESTIMATOR; } /* UPDATE ESTIMATES FROM OTHER SIDE */ if(encoderSamplingFreq == kIsacWideband) { if(index > 11) { index -= 12; /* compute the jitter estimate as decoded on the other side */ bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg + 0.1f * (float)MAX_ISAC_MD; } else { /* compute the jitter estimate as decoded on the other side */ bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg + 0.1f * (float)MIN_ISAC_MD; } /* compute the BN estimate as decoded on the other side */ bwest_str->send_bw_avg = 0.9f * bwest_str->send_bw_avg + 0.1f * kQRateTableWb[index]; } else { /* compute the BN estimate as decoded on the other side */ bwest_str->send_bw_avg = 0.9f * bwest_str->send_bw_avg + 0.1f * kQRateTableSwb[index]; } if (bwest_str->send_bw_avg > (float) 28000 && !bwest_str->hsn_detect_snd) { bwest_str->num_consec_snt_pkts_over_30k++; if (bwest_str->num_consec_snt_pkts_over_30k >= 66) { //approx 2 seconds with 30ms frames bwest_str->hsn_detect_snd = 1; } } else if (!bwest_str->hsn_detect_snd) { bwest_str->num_consec_snt_pkts_over_30k = 0; } return 0; } // called when there is upper-band bit-stream to update jitter // statistics. int16_t WebRtcIsac_UpdateUplinkJitter( BwEstimatorstr* bwest_str, int32_t index) { RTC_DCHECK(!bwest_str->external_bw_info.in_use); if((index < 0) || (index > 23)) { return -ISAC_RANGE_ERROR_BW_ESTIMATOR; } if(index > 0) { /* compute the jitter estimate as decoded on the other side */ bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg + 0.1f * (float)MAX_ISAC_MD; } else { /* compute the jitter estimate as decoded on the other side */ bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg + 0.1f * (float)MIN_ISAC_MD; } return 0; } // Returns the bandwidth/jitter estimation code (integer 0...23) // to put in the sending iSAC payload void WebRtcIsac_GetDownlinkBwJitIndexImpl( BwEstimatorstr* bwest_str, int16_t* bottleneckIndex, int16_t* jitterInfo, enum IsacSamplingRate decoderSamplingFreq) { float MaxDelay; //uint16_t MaxDelayBit; float rate; float r; float e1, e2; const float weight = 0.1f; const float* ptrQuantizationTable; int16_t addJitterInfo; int16_t minInd; int16_t maxInd; int16_t midInd; if (bwest_str->external_bw_info.in_use) { *bottleneckIndex = bwest_str->external_bw_info.bottleneck_idx; *jitterInfo = bwest_str->external_bw_info.jitter_info; return; } /* Get Max Delay Bit */ /* get unquantized max delay */ MaxDelay = (float)WebRtcIsac_GetDownlinkMaxDelay(bwest_str); if ( ((1.f - weight) * bwest_str->rec_max_delay_avg_Q + weight * MAX_ISAC_MD - MaxDelay) > (MaxDelay - (1.f-weight) * bwest_str->rec_max_delay_avg_Q - weight * MIN_ISAC_MD) ) { jitterInfo[0] = 0; /* update quantized average */ bwest_str->rec_max_delay_avg_Q = (1.f - weight) * bwest_str->rec_max_delay_avg_Q + weight * (float)MIN_ISAC_MD; } else { jitterInfo[0] = 1; /* update quantized average */ bwest_str->rec_max_delay_avg_Q = (1.f-weight) * bwest_str->rec_max_delay_avg_Q + weight * (float)MAX_ISAC_MD; } // Get unquantized rate. rate = (float)WebRtcIsac_GetDownlinkBandwidth(bwest_str); /* Get Rate Index */ if(decoderSamplingFreq == kIsacWideband) { ptrQuantizationTable = kQRateTableWb; addJitterInfo = 1; maxInd = 11; } else { ptrQuantizationTable = kQRateTableSwb; addJitterInfo = 0; maxInd = 23; } minInd = 0; while(maxInd > minInd + 1) { midInd = (maxInd + minInd) >> 1; if(rate > ptrQuantizationTable[midInd]) { minInd = midInd; } else { maxInd = midInd; } } // Chose the index which gives results an average which is closest // to rate r = (1 - weight) * bwest_str->rec_bw_avg_Q - rate; e1 = weight * ptrQuantizationTable[minInd] + r; e2 = weight * ptrQuantizationTable[maxInd] + r; e1 = (e1 > 0)? e1:-e1; e2 = (e2 > 0)? e2:-e2; if(e1 < e2) { bottleneckIndex[0] = minInd; } else { bottleneckIndex[0] = maxInd; } bwest_str->rec_bw_avg_Q = (1 - weight) * bwest_str->rec_bw_avg_Q + weight * ptrQuantizationTable[bottleneckIndex[0]]; bottleneckIndex[0] += jitterInfo[0] * 12 * addJitterInfo; bwest_str->rec_bw_avg = (1 - weight) * bwest_str->rec_bw_avg + weight * (rate + bwest_str->rec_header_rate); } /* get the bottle neck rate from far side to here, as estimated on this side */ int32_t WebRtcIsac_GetDownlinkBandwidth( const BwEstimatorstr *bwest_str) { int32_t rec_bw; float jitter_sign; float bw_adjust; RTC_DCHECK(!bwest_str->external_bw_info.in_use); /* create a value between -1.0 and 1.0 indicating "average sign" of jitter */ jitter_sign = bwest_str->rec_jitter_short_term / bwest_str->rec_jitter_short_term_abs; /* adjust bw proportionally to negative average jitter sign */ bw_adjust = 1.0f - jitter_sign * (0.15f + 0.15f * jitter_sign * jitter_sign); /* adjust Rate if jitter sign is mostly constant */ rec_bw = (int32_t)(bwest_str->rec_bw * bw_adjust); /* limit range of bottle neck rate */ if (rec_bw < MIN_ISAC_BW) { rec_bw = MIN_ISAC_BW; } else if (rec_bw > MAX_ISAC_BW) { rec_bw = MAX_ISAC_BW; } return rec_bw; } /* Returns the max delay (in ms) */ int32_t WebRtcIsac_GetDownlinkMaxDelay(const BwEstimatorstr *bwest_str) { int32_t rec_max_delay; RTC_DCHECK(!bwest_str->external_bw_info.in_use); rec_max_delay = (int32_t)(bwest_str->rec_max_delay); /* limit range of jitter estimate */ if (rec_max_delay < MIN_ISAC_MD) { rec_max_delay = MIN_ISAC_MD; } else if (rec_max_delay > MAX_ISAC_MD) { rec_max_delay = MAX_ISAC_MD; } return rec_max_delay; } /* Clamp val to the closed interval [min,max]. */ static int32_t clamp(int32_t val, int32_t min, int32_t max) { RTC_DCHECK_LE(min, max); return val < min ? min : (val > max ? max : val); } int32_t WebRtcIsac_GetUplinkBandwidth(const BwEstimatorstr* bwest_str) { return bwest_str->external_bw_info.in_use ? bwest_str->external_bw_info.send_bw_avg : clamp(bwest_str->send_bw_avg, MIN_ISAC_BW, MAX_ISAC_BW); } int32_t WebRtcIsac_GetUplinkMaxDelay(const BwEstimatorstr* bwest_str) { return bwest_str->external_bw_info.in_use ? bwest_str->external_bw_info.send_max_delay_avg : clamp(bwest_str->send_max_delay_avg, MIN_ISAC_MD, MAX_ISAC_MD); } /* * update long-term average bitrate and amount of data in buffer * returns minimum payload size (bytes) */ int WebRtcIsac_GetMinBytes( RateModel* State, int StreamSize, /* bytes in bitstream */ const int FrameSamples, /* samples per frame */ const double BottleNeck, /* bottle neck rate; excl headers (bps) */ const double DelayBuildUp, /* max delay from bottleneck buffering (ms) */ enum ISACBandwidth bandwidth /*,int16_t frequentLargePackets*/) { double MinRate = 0.0; int MinBytes; double TransmissionTime; int burstInterval = BURST_INTERVAL; // first 10 packets @ low rate, then INIT_BURST_LEN packets @ // fixed rate of INIT_RATE bps if (State->InitCounter > 0) { if (State->InitCounter-- <= INIT_BURST_LEN) { if(bandwidth == isac8kHz) { MinRate = INIT_RATE_WB; } else { MinRate = INIT_RATE_SWB; } } else { MinRate = 0; } } else { /* handle burst */ if (State->BurstCounter) { if (State->StillBuffered < (1.0 - 1.0/BURST_LEN) * DelayBuildUp) { /* max bps derived from BottleNeck and DelayBuildUp values */ MinRate = (1.0 + (FS/1000) * DelayBuildUp / (double)(BURST_LEN * FrameSamples)) * BottleNeck; } else { // max bps derived from StillBuffered and DelayBuildUp // values MinRate = (1.0 + (FS/1000) * (DelayBuildUp - State->StillBuffered) / (double)FrameSamples) * BottleNeck; if (MinRate < 1.04 * BottleNeck) { MinRate = 1.04 * BottleNeck; } } State->BurstCounter--; } } /* convert rate from bits/second to bytes/packet */ MinBytes = (int) (MinRate * FrameSamples / (8.0 * FS)); /* StreamSize will be adjusted if less than MinBytes */ if (StreamSize < MinBytes) { StreamSize = MinBytes; } /* keep track of when bottle neck was last exceeded by at least 1% */ if (StreamSize * 8.0 * FS / FrameSamples > 1.01 * BottleNeck) { if (State->PrevExceed) { /* bottle_neck exceded twice in a row, decrease ExceedAgo */ State->ExceedAgo -= /*BURST_INTERVAL*/ burstInterval / (BURST_LEN - 1); if (State->ExceedAgo < 0) State->ExceedAgo = 0; } else { State->ExceedAgo += (FrameSamples * 1000) / FS; /* ms */ State->PrevExceed = 1; } } else { State->PrevExceed = 0; State->ExceedAgo += (FrameSamples * 1000) / FS; /* ms */ } /* set burst flag if bottle neck not exceeded for long time */ if ((State->ExceedAgo > burstInterval) && (State->BurstCounter == 0)) { if (State->PrevExceed) { State->BurstCounter = BURST_LEN - 1; } else { State->BurstCounter = BURST_LEN; } } /* Update buffer delay */ TransmissionTime = StreamSize * 8.0 * 1000.0 / BottleNeck; /* ms */ State->StillBuffered += TransmissionTime; State->StillBuffered -= (FrameSamples * 1000) / FS; /* ms */ if (State->StillBuffered < 0.0) { State->StillBuffered = 0.0; } return MinBytes; } /* * update long-term average bitrate and amount of data in buffer */ void WebRtcIsac_UpdateRateModel( RateModel *State, int StreamSize, /* bytes in bitstream */ const int FrameSamples, /* samples per frame */ const double BottleNeck) /* bottle neck rate; excl headers (bps) */ { double TransmissionTime; /* avoid the initial "high-rate" burst */ State->InitCounter = 0; /* Update buffer delay */ TransmissionTime = StreamSize * 8.0 * 1000.0 / BottleNeck; /* ms */ State->StillBuffered += TransmissionTime; State->StillBuffered -= (FrameSamples * 1000) / FS; /* ms */ if (State->StillBuffered < 0.0) State->StillBuffered = 0.0; } void WebRtcIsac_InitRateModel( RateModel *State) { State->PrevExceed = 0; /* boolean */ State->ExceedAgo = 0; /* ms */ State->BurstCounter = 0; /* packets */ State->InitCounter = INIT_BURST_LEN + 10; /* packets */ State->StillBuffered = 1.0; /* ms */ } int WebRtcIsac_GetNewFrameLength( double bottle_neck, int current_framesamples) { int new_framesamples; const int Thld_20_30 = 20000; //const int Thld_30_20 = 30000; const int Thld_30_20 = 1000000; // disable 20 ms frames const int Thld_30_60 = 18000; //const int Thld_30_60 = 0; // disable 60 ms frames const int Thld_60_30 = 27000; new_framesamples = current_framesamples; /* find new framelength */ switch(current_framesamples) { case 320: if (bottle_neck < Thld_20_30) new_framesamples = 480; break; case 480: if (bottle_neck < Thld_30_60) new_framesamples = 960; else if (bottle_neck > Thld_30_20) new_framesamples = 320; break; case 960: if (bottle_neck >= Thld_60_30) new_framesamples = 480; break; } return new_framesamples; } double WebRtcIsac_GetSnr( double bottle_neck, int framesamples) { double s2nr; const double a_20 = -30.0; const double b_20 = 0.8; const double c_20 = 0.0; const double a_30 = -23.0; const double b_30 = 0.48; const double c_30 = 0.0; const double a_60 = -23.0; const double b_60 = 0.53; const double c_60 = 0.0; /* find new SNR value */ switch(framesamples) { case 320: s2nr = a_20 + b_20 * bottle_neck * 0.001 + c_20 * bottle_neck * bottle_neck * 0.000001; break; case 480: s2nr = a_30 + b_30 * bottle_neck * 0.001 + c_30 * bottle_neck * bottle_neck * 0.000001; break; case 960: s2nr = a_60 + b_60 * bottle_neck * 0.001 + c_60 * bottle_neck * bottle_neck * 0.000001; break; default: s2nr = 0; } return s2nr; } ././@PaxHeader0000000000000000000000000000020500000000000010212 xustar00111 path=webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.0000664000175000017500000001336414475643423032716 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * bandwidth_estimator.h * * This header file contains the API for the Bandwidth Estimator * designed for iSAC. * */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_ #include #include "modules/audio_coding/codecs/isac/main/source/settings.h" #include "modules/audio_coding/codecs/isac/main/source/structs.h" #define MIN_ISAC_BW 10000 #define MIN_ISAC_BW_LB 10000 #define MIN_ISAC_BW_UB 25000 #define MAX_ISAC_BW 56000 #define MAX_ISAC_BW_UB 32000 #define MAX_ISAC_BW_LB 32000 #define MIN_ISAC_MD 5 #define MAX_ISAC_MD 25 // assumed header size, in bytes; we don't know the exact number // (header compression may be used) #define HEADER_SIZE 35 // Initial Frame-Size, in ms, for Wideband & Super-Wideband Mode #define INIT_FRAME_LEN_WB 60 #define INIT_FRAME_LEN_SWB 30 // Initial Bottleneck Estimate, in bits/sec, for // Wideband & Super-wideband mode #define INIT_BN_EST_WB 20e3f #define INIT_BN_EST_SWB 56e3f // Initial Header rate (header rate depends on frame-size), // in bits/sec, for Wideband & Super-Wideband mode. #define INIT_HDR_RATE_WB \ ((float)HEADER_SIZE * 8.0f * 1000.0f / (float)INIT_FRAME_LEN_WB) #define INIT_HDR_RATE_SWB \ ((float)HEADER_SIZE * 8.0f * 1000.0f / (float)INIT_FRAME_LEN_SWB) // number of packets in a row for a high rate burst #define BURST_LEN 3 // ms, max time between two full bursts #define BURST_INTERVAL 500 // number of packets in a row for initial high rate burst #define INIT_BURST_LEN 5 // bits/s, rate for the first BURST_LEN packets #define INIT_RATE_WB INIT_BN_EST_WB #define INIT_RATE_SWB INIT_BN_EST_SWB #if defined(__cplusplus) extern "C" { #endif /* This function initializes the struct */ /* to be called before using the struct for anything else */ /* returns 0 if everything went fine, -1 otherwise */ int32_t WebRtcIsac_InitBandwidthEstimator( BwEstimatorstr* bwest_str, enum IsacSamplingRate encoderSampRate, enum IsacSamplingRate decoderSampRate); /* This function updates the receiving estimate */ /* Parameters: */ /* rtp_number - value from RTP packet, from NetEq */ /* frame length - length of signal frame in ms, from iSAC decoder */ /* send_ts - value in RTP header giving send time in samples */ /* arr_ts - value given by timeGetTime() time of arrival in samples of * packet from NetEq */ /* pksize - size of packet in bytes, from NetEq */ /* Index - integer (range 0...23) indicating bottle neck & jitter as * estimated by other side */ /* returns 0 if everything went fine, -1 otherwise */ int16_t WebRtcIsac_UpdateBandwidthEstimator(BwEstimatorstr* bwest_str, const uint16_t rtp_number, const int32_t frame_length, const uint32_t send_ts, const uint32_t arr_ts, const size_t pksize); /* Update receiving estimates. Used when we only receive BWE index, no iSAC data * packet. */ int16_t WebRtcIsac_UpdateUplinkBwImpl( BwEstimatorstr* bwest_str, int16_t Index, enum IsacSamplingRate encoderSamplingFreq); /* Returns the bandwidth/jitter estimation code (integer 0...23) to put in the * sending iSAC payload */ void WebRtcIsac_GetDownlinkBwJitIndexImpl( BwEstimatorstr* bwest_str, int16_t* bottleneckIndex, int16_t* jitterInfo, enum IsacSamplingRate decoderSamplingFreq); /* Returns the bandwidth estimation (in bps) */ int32_t WebRtcIsac_GetDownlinkBandwidth(const BwEstimatorstr* bwest_str); /* Returns the max delay (in ms) */ int32_t WebRtcIsac_GetDownlinkMaxDelay(const BwEstimatorstr* bwest_str); /* Returns the bandwidth that iSAC should send with in bps */ int32_t WebRtcIsac_GetUplinkBandwidth(const BwEstimatorstr* bwest_str); /* Returns the max delay value from the other side in ms */ int32_t WebRtcIsac_GetUplinkMaxDelay(const BwEstimatorstr* bwest_str); /* * update amount of data in bottle neck buffer and burst handling * returns minimum payload size (bytes) */ int WebRtcIsac_GetMinBytes( RateModel* State, int StreamSize, /* bytes in bitstream */ const int FrameLen, /* ms per frame */ const double BottleNeck, /* bottle neck rate; excl headers (bps) */ const double DelayBuildUp, /* max delay from bottleneck buffering (ms) */ enum ISACBandwidth bandwidth /*,int16_t frequentLargePackets*/); /* * update long-term average bitrate and amount of data in buffer */ void WebRtcIsac_UpdateRateModel( RateModel* State, int StreamSize, /* bytes in bitstream */ const int FrameSamples, /* samples per frame */ const double BottleNeck); /* bottle neck rate; excl headers (bps) */ void WebRtcIsac_InitRateModel(RateModel* State); /* Returns the new framelength value (input argument: bottle_neck) */ int WebRtcIsac_GetNewFrameLength(double bottle_neck, int current_framelength); /* Returns the new SNR value (input argument: bottle_neck) */ double WebRtcIsac_GetSnr(double bottle_neck, int new_framelength); int16_t WebRtcIsac_UpdateUplinkJitter(BwEstimatorstr* bwest_str, int32_t index); #if defined(__cplusplus) } #endif #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_ \ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/codec.h0000664000175000017500000002061114475643423030101 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * codec.h * * This header file contains the calls to the internal encoder * and decoder functions. * */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_ #include #include "modules/audio_coding/codecs/isac/main/source/structs.h" #include "modules/third_party/fft/fft.h" void WebRtcIsac_ResetBitstream(Bitstr* bit_stream); int WebRtcIsac_EstimateBandwidth(BwEstimatorstr* bwest_str, Bitstr* streamdata, size_t packet_size, uint16_t rtp_seq_number, uint32_t send_ts, uint32_t arr_ts, enum IsacSamplingRate encoderSampRate, enum IsacSamplingRate decoderSampRate); int WebRtcIsac_DecodeLb(const TransformTables* transform_tables, float* signal_out, ISACLBDecStruct* ISACdec_obj, int16_t* current_framesamples, int16_t isRCUPayload); int WebRtcIsac_DecodeRcuLb(float* signal_out, ISACLBDecStruct* ISACdec_obj, int16_t* current_framesamples); int WebRtcIsac_EncodeLb(const TransformTables* transform_tables, float* in, ISACLBEncStruct* ISACencLB_obj, int16_t codingMode, int16_t bottleneckIndex); int WebRtcIsac_EncodeStoredDataLb(const IsacSaveEncoderData* ISACSavedEnc_obj, Bitstr* ISACBitStr_obj, int BWnumber, float scale); int WebRtcIsac_EncodeStoredDataUb( const ISACUBSaveEncDataStruct* ISACSavedEnc_obj, Bitstr* bitStream, int32_t jitterInfo, float scale, enum ISACBandwidth bandwidth); int16_t WebRtcIsac_GetRedPayloadUb( const ISACUBSaveEncDataStruct* ISACSavedEncObj, Bitstr* bitStreamObj, enum ISACBandwidth bandwidth); /****************************************************************************** * WebRtcIsac_RateAllocation() * Internal function to perform a rate-allocation for upper and lower-band, * given a total rate. * * Input: * - inRateBitPerSec : a total bit-rate in bits/sec. * * Output: * - rateLBBitPerSec : a bit-rate allocated to the lower-band * in bits/sec. * - rateUBBitPerSec : a bit-rate allocated to the upper-band * in bits/sec. * * Return value : 0 if rate allocation has been successful. * -1 if failed to allocate rates. */ int16_t WebRtcIsac_RateAllocation(int32_t inRateBitPerSec, double* rateLBBitPerSec, double* rateUBBitPerSec, enum ISACBandwidth* bandwidthKHz); /****************************************************************************** * WebRtcIsac_DecodeUb16() * * Decode the upper-band if the codec is in 0-16 kHz mode. * * Input/Output: * -ISACdec_obj : pointer to the upper-band decoder object. The * bit-stream is stored inside the decoder object. * * Output: * -signal_out : decoded audio, 480 samples 30 ms. * * Return value : >0 number of decoded bytes. * <0 if an error occurred. */ int WebRtcIsac_DecodeUb16(const TransformTables* transform_tables, float* signal_out, ISACUBDecStruct* ISACdec_obj, int16_t isRCUPayload); /****************************************************************************** * WebRtcIsac_DecodeUb12() * * Decode the upper-band if the codec is in 0-12 kHz mode. * * Input/Output: * -ISACdec_obj : pointer to the upper-band decoder object. The * bit-stream is stored inside the decoder object. * * Output: * -signal_out : decoded audio, 480 samples 30 ms. * * Return value : >0 number of decoded bytes. * <0 if an error occurred. */ int WebRtcIsac_DecodeUb12(const TransformTables* transform_tables, float* signal_out, ISACUBDecStruct* ISACdec_obj, int16_t isRCUPayload); /****************************************************************************** * WebRtcIsac_EncodeUb16() * * Encode the upper-band if the codec is in 0-16 kHz mode. * * Input: * -in : upper-band audio, 160 samples (10 ms). * * Input/Output: * -ISACdec_obj : pointer to the upper-band encoder object. The * bit-stream is stored inside the encoder object. * * Return value : >0 number of encoded bytes. * <0 if an error occurred. */ int WebRtcIsac_EncodeUb16(const TransformTables* transform_tables, float* in, ISACUBEncStruct* ISACenc_obj, int32_t jitterInfo); /****************************************************************************** * WebRtcIsac_EncodeUb12() * * Encode the upper-band if the codec is in 0-12 kHz mode. * * Input: * -in : upper-band audio, 160 samples (10 ms). * * Input/Output: * -ISACdec_obj : pointer to the upper-band encoder object. The * bit-stream is stored inside the encoder object. * * Return value : >0 number of encoded bytes. * <0 if an error occurred. */ int WebRtcIsac_EncodeUb12(const TransformTables* transform_tables, float* in, ISACUBEncStruct* ISACenc_obj, int32_t jitterInfo); /************************** initialization functions *************************/ void WebRtcIsac_InitMasking(MaskFiltstr* maskdata); void WebRtcIsac_InitPostFilterbank(PostFiltBankstr* postfiltdata); /**************************** transform functions ****************************/ void WebRtcIsac_InitTransform(TransformTables* tables); void WebRtcIsac_Time2Spec(const TransformTables* tables, double* inre1, double* inre2, int16_t* outre, int16_t* outim, FFTstr* fftstr_obj); void WebRtcIsac_Spec2time(const TransformTables* tables, double* inre, double* inim, double* outre1, double* outre2, FFTstr* fftstr_obj); /***************************** filterbank functions **************************/ void WebRtcIsac_FilterAndCombineFloat(float* InLP, float* InHP, float* Out, PostFiltBankstr* postfiltdata); /************************* normalized lattice filters ************************/ void WebRtcIsac_NormLatticeFilterMa(int orderCoef, float* stateF, float* stateG, float* lat_in, double* filtcoeflo, double* lat_out); void WebRtcIsac_NormLatticeFilterAr(int orderCoef, float* stateF, float* stateG, double* lat_in, double* lo_filt_coef, float* lat_out); void WebRtcIsac_Dir2Lat(double* a, int orderCoef, float* sth, float* cth); #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/crc.c0000664000175000017500000001154714475643423027576 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include #include "modules/audio_coding/codecs/isac/main/source/crc.h" #include "common_audio/signal_processing/include/signal_processing_library.h" #define POLYNOMIAL 0x04c11db7L static const uint32_t kCrcTable[256] = { 0, 0x4c11db7, 0x9823b6e, 0xd4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x18aeb13, 0x54bf6a4, 0x808d07d, 0xcc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, 0x315d626, 0x7d4cb91, 0xa97ed48, 0xe56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x29f3d35, 0x65e2082, 0xb1d065b, 0xfdc1bec, 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 }; /**************************************************************************** * WebRtcIsac_GetCrc(...) * * This function returns a 32 bit CRC checksum of a bit stream * * Input: * - bitstream : payload bitstream * - len_bitstream_in_bytes : number of 8-bit words in the bit stream * * Output: * - crc : checksum * * Return value : 0 - Ok * -1 - Error */ int WebRtcIsac_GetCrc(const int16_t* bitstream, int len_bitstream_in_bytes, uint32_t* crc) { uint8_t* bitstream_ptr_uw8; uint32_t crc_state; int byte_cntr; int crc_tbl_indx; /* Sanity Check. */ if (bitstream == NULL) { return -1; } /* cast to UWord8 pointer */ bitstream_ptr_uw8 = (uint8_t *)bitstream; /* initialize */ crc_state = 0xFFFFFFFF; for (byte_cntr = 0; byte_cntr < len_bitstream_in_bytes; byte_cntr++) { crc_tbl_indx = (WEBRTC_SPL_RSHIFT_U32(crc_state, 24) ^ bitstream_ptr_uw8[byte_cntr]) & 0xFF; crc_state = (crc_state << 8) ^ kCrcTable[crc_tbl_indx]; } *crc = ~crc_state; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/crc.h0000664000175000017500000000217014475643423027573 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * crc.h * * Checksum functions * */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_ #include /**************************************************************************** * WebRtcIsac_GetCrc(...) * * This function returns a 32 bit CRC checksum of a bit stream * * Input: * - encoded : payload bit stream * - no_of_word8s : number of 8-bit words in the bit stream * * Output: * - crc : checksum * * Return value : 0 - Ok * -1 - Error */ int WebRtcIsac_GetCrc(const int16_t* encoded, int no_of_word8s, uint32_t* crc); #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/decode.c0000664000175000017500000002455314475643423030253 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * decode_B.c * * This file contains definition of funtions for decoding. * Decoding of lower-band, including normal-decoding and RCU decoding. * Decoding of upper-band, including 8-12 kHz, when the bandwidth is * 0-12 kHz, and 8-16 kHz, when the bandwidth is 0-16 kHz. * */ #include #include #include #include "modules/audio_coding/codecs/isac/main/source/codec.h" #include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h" #include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h" #include "modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h" #include "modules/audio_coding/codecs/isac/main/source/structs.h" #include "modules/audio_coding/codecs/isac/main/source/settings.h" #include "modules/audio_coding/codecs/isac/main/source/pitch_filter.h" /* * function to decode the bitstream * returns the total number of bytes in the stream */ int WebRtcIsac_DecodeLb(const TransformTables* transform_tables, float* signal_out, ISACLBDecStruct* ISACdecLB_obj, int16_t* current_framesamples, int16_t isRCUPayload) { int k; int len, err; int16_t bandwidthInd; float LP_dec_float[FRAMESAMPLES_HALF]; float HP_dec_float[FRAMESAMPLES_HALF]; double LPw[FRAMESAMPLES_HALF]; double HPw[FRAMESAMPLES_HALF]; double LPw_pf[FRAMESAMPLES_HALF]; double lo_filt_coef[(ORDERLO + 1)*SUBFRAMES]; double hi_filt_coef[(ORDERHI + 1)*SUBFRAMES]; double real_f[FRAMESAMPLES_HALF]; double imag_f[FRAMESAMPLES_HALF]; double PitchLags[4]; double PitchGains[4]; double AvgPitchGain; int16_t PitchGains_Q12[4]; int16_t AvgPitchGain_Q12; float gain; int frame_nb; /* counter */ int frame_mode; /* 0 30ms, 1 for 60ms */ /* Processed_samples: 480 (30, 60 ms). Cannot take other values. */ WebRtcIsac_ResetBitstream(&(ISACdecLB_obj->bitstr_obj)); len = 0; /* Decode framelength and BW estimation - not used, only for stream pointer*/ err = WebRtcIsac_DecodeFrameLen(&ISACdecLB_obj->bitstr_obj, current_framesamples); if (err < 0) { return err; } /* Frame_mode: * 0: indicates 30 ms frame (480 samples) * 1: indicates 60 ms frame (960 samples) */ frame_mode = *current_framesamples / MAX_FRAMESAMPLES; err = WebRtcIsac_DecodeSendBW(&ISACdecLB_obj->bitstr_obj, &bandwidthInd); if (err < 0) { return err; } /* One loop if it's one frame (20 or 30ms), 2 loops if 2 frames bundled together (60ms). */ for (frame_nb = 0; frame_nb <= frame_mode; frame_nb++) { /* Decode & de-quantize pitch parameters */ err = WebRtcIsac_DecodePitchGain(&ISACdecLB_obj->bitstr_obj, PitchGains_Q12); if (err < 0) { return err; } err = WebRtcIsac_DecodePitchLag(&ISACdecLB_obj->bitstr_obj, PitchGains_Q12, PitchLags); if (err < 0) { return err; } AvgPitchGain_Q12 = (PitchGains_Q12[0] + PitchGains_Q12[1] + PitchGains_Q12[2] + PitchGains_Q12[3]) >> 2; /* Decode & de-quantize filter coefficients. */ err = WebRtcIsac_DecodeLpc(&ISACdecLB_obj->bitstr_obj, lo_filt_coef, hi_filt_coef); if (err < 0) { return err; } /* Decode & de-quantize spectrum. */ len = WebRtcIsac_DecodeSpec(&ISACdecLB_obj->bitstr_obj, AvgPitchGain_Q12, kIsacLowerBand, real_f, imag_f); if (len < 0) { return len; } /* Inverse transform. */ WebRtcIsac_Spec2time(transform_tables, real_f, imag_f, LPw, HPw, &ISACdecLB_obj->fftstr_obj); /* Convert PitchGains back to float for pitchfilter_post */ for (k = 0; k < 4; k++) { PitchGains[k] = ((float)PitchGains_Q12[k]) / 4096; } if (isRCUPayload) { for (k = 0; k < 240; k++) { LPw[k] *= RCU_TRANSCODING_SCALE_INVERSE; HPw[k] *= RCU_TRANSCODING_SCALE_INVERSE; } } /* Inverse pitch filter. */ WebRtcIsac_PitchfilterPost(LPw, LPw_pf, &ISACdecLB_obj->pitchfiltstr_obj, PitchLags, PitchGains); /* Convert AvgPitchGain back to float for computation of gain. */ AvgPitchGain = ((float)AvgPitchGain_Q12) / 4096; gain = 1.0f - 0.45f * (float)AvgPitchGain; for (k = 0; k < FRAMESAMPLES_HALF; k++) { /* Reduce gain to compensate for pitch enhancer. */ LPw_pf[k] *= gain; } if (isRCUPayload) { for (k = 0; k < FRAMESAMPLES_HALF; k++) { /* Compensation for transcoding gain changes. */ LPw_pf[k] *= RCU_TRANSCODING_SCALE; HPw[k] *= RCU_TRANSCODING_SCALE; } } /* Perceptual post-filtering (using normalized lattice filter). */ WebRtcIsac_NormLatticeFilterAr( ORDERLO, ISACdecLB_obj->maskfiltstr_obj.PostStateLoF, (ISACdecLB_obj->maskfiltstr_obj).PostStateLoG, LPw_pf, lo_filt_coef, LP_dec_float); WebRtcIsac_NormLatticeFilterAr( ORDERHI, ISACdecLB_obj->maskfiltstr_obj.PostStateHiF, (ISACdecLB_obj->maskfiltstr_obj).PostStateHiG, HPw, hi_filt_coef, HP_dec_float); /* Recombine the 2 bands. */ WebRtcIsac_FilterAndCombineFloat(LP_dec_float, HP_dec_float, signal_out + frame_nb * FRAMESAMPLES, &ISACdecLB_obj->postfiltbankstr_obj); } return len; } /* * This decode function is called when the codec is operating in 16 kHz * bandwidth to decode the upperband, i.e. 8-16 kHz. * * Contrary to lower-band, the upper-band (8-16 kHz) is not split in * frequency, but split to 12 sub-frames, i.e. twice as lower-band. */ int WebRtcIsac_DecodeUb16(const TransformTables* transform_tables, float* signal_out, ISACUBDecStruct* ISACdecUB_obj, int16_t isRCUPayload) { int len, err; double halfFrameFirst[FRAMESAMPLES_HALF]; double halfFrameSecond[FRAMESAMPLES_HALF]; double percepFilterParam[(UB_LPC_ORDER + 1) * (SUBFRAMES << 1) + (UB_LPC_ORDER + 1)]; double real_f[FRAMESAMPLES_HALF]; double imag_f[FRAMESAMPLES_HALF]; const int16_t kAveragePitchGain = 0; /* No pitch-gain for upper-band. */ len = 0; /* Decode & de-quantize filter coefficients. */ memset(percepFilterParam, 0, sizeof(percepFilterParam)); err = WebRtcIsac_DecodeInterpolLpcUb(&ISACdecUB_obj->bitstr_obj, percepFilterParam, isac16kHz); if (err < 0) { return err; } /* Decode & de-quantize spectrum. */ len = WebRtcIsac_DecodeSpec(&ISACdecUB_obj->bitstr_obj, kAveragePitchGain, kIsacUpperBand16, real_f, imag_f); if (len < 0) { return len; } if (isRCUPayload) { int n; for (n = 0; n < 240; n++) { real_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE; imag_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE; } } /* Inverse transform. */ WebRtcIsac_Spec2time(transform_tables, real_f, imag_f, halfFrameFirst, halfFrameSecond, &ISACdecUB_obj->fftstr_obj); /* Perceptual post-filtering (using normalized lattice filter). */ WebRtcIsac_NormLatticeFilterAr( UB_LPC_ORDER, ISACdecUB_obj->maskfiltstr_obj.PostStateLoF, (ISACdecUB_obj->maskfiltstr_obj).PostStateLoG, halfFrameFirst, &percepFilterParam[(UB_LPC_ORDER + 1)], signal_out); WebRtcIsac_NormLatticeFilterAr( UB_LPC_ORDER, ISACdecUB_obj->maskfiltstr_obj.PostStateLoF, (ISACdecUB_obj->maskfiltstr_obj).PostStateLoG, halfFrameSecond, &percepFilterParam[(UB_LPC_ORDER + 1) * SUBFRAMES + (UB_LPC_ORDER + 1)], &signal_out[FRAMESAMPLES_HALF]); return len; } /* * This decode function is called when the codec operates at 0-12 kHz * bandwidth to decode the upperband, i.e. 8-12 kHz. * * At the encoder the upper-band is split into two band, 8-12 kHz & 12-16 * kHz, and only 8-12 kHz is encoded. At the decoder, 8-12 kHz band is * reconstructed and 12-16 kHz replaced with zeros. Then two bands * are combined, to reconstruct the upperband 8-16 kHz. */ int WebRtcIsac_DecodeUb12(const TransformTables* transform_tables, float* signal_out, ISACUBDecStruct* ISACdecUB_obj, int16_t isRCUPayload) { int len, err; float LP_dec_float[FRAMESAMPLES_HALF]; float HP_dec_float[FRAMESAMPLES_HALF]; double LPw[FRAMESAMPLES_HALF]; double HPw[FRAMESAMPLES_HALF]; double percepFilterParam[(UB_LPC_ORDER + 1)*SUBFRAMES]; double real_f[FRAMESAMPLES_HALF]; double imag_f[FRAMESAMPLES_HALF]; const int16_t kAveragePitchGain = 0; /* No pitch-gain for upper-band. */ len = 0; /* Decode & dequantize filter coefficients. */ err = WebRtcIsac_DecodeInterpolLpcUb(&ISACdecUB_obj->bitstr_obj, percepFilterParam, isac12kHz); if (err < 0) { return err; } /* Decode & de-quantize spectrum. */ len = WebRtcIsac_DecodeSpec(&ISACdecUB_obj->bitstr_obj, kAveragePitchGain, kIsacUpperBand12, real_f, imag_f); if (len < 0) { return len; } if (isRCUPayload) { int n; for (n = 0; n < 240; n++) { real_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE; imag_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE; } } /* Inverse transform. */ WebRtcIsac_Spec2time(transform_tables, real_f, imag_f, LPw, HPw, &ISACdecUB_obj->fftstr_obj); /* perceptual post-filtering (using normalized lattice filter) */ WebRtcIsac_NormLatticeFilterAr(UB_LPC_ORDER, ISACdecUB_obj->maskfiltstr_obj.PostStateLoF, (ISACdecUB_obj->maskfiltstr_obj).PostStateLoG, LPw, percepFilterParam, LP_dec_float); /* Zero for 12-16 kHz. */ memset(HP_dec_float, 0, sizeof(float) * (FRAMESAMPLES_HALF)); /* Recombine the 2 bands. */ WebRtcIsac_FilterAndCombineFloat(HP_dec_float, LP_dec_float, signal_out, &ISACdecUB_obj->postfiltbankstr_obj); return len; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/decode_bwe.c0000664000175000017500000000564214475643423031106 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_coding/codecs/isac/main/source/structs.h" #include "modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h" #include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h" #include "modules/audio_coding/codecs/isac/main/source/codec.h" int WebRtcIsac_EstimateBandwidth( BwEstimatorstr* bwest_str, Bitstr* streamdata, size_t packet_size, uint16_t rtp_seq_number, uint32_t send_ts, uint32_t arr_ts, enum IsacSamplingRate encoderSampRate, enum IsacSamplingRate decoderSampRate) { int16_t index; int16_t frame_samples; uint32_t sendTimestampIn16kHz; uint32_t arrivalTimestampIn16kHz; uint32_t diffSendTime; uint32_t diffArrivalTime; int err; /* decode framelength and BW estimation */ err = WebRtcIsac_DecodeFrameLen(streamdata, &frame_samples); if(err < 0) // error check { return err; } err = WebRtcIsac_DecodeSendBW(streamdata, &index); if(err < 0) // error check { return err; } /* UPDATE ESTIMATES FROM OTHER SIDE */ err = WebRtcIsac_UpdateUplinkBwImpl(bwest_str, index, encoderSampRate); if(err < 0) { return err; } // We like BWE to work at 16 kHz sampling rate, // therefore, we have to change the timestamps accordingly. // translate the send timestamp if required diffSendTime = (uint32_t)((uint32_t)send_ts - (uint32_t)bwest_str->senderTimestamp); bwest_str->senderTimestamp = send_ts; diffArrivalTime = (uint32_t)((uint32_t)arr_ts - (uint32_t)bwest_str->receiverTimestamp); bwest_str->receiverTimestamp = arr_ts; if(decoderSampRate == kIsacSuperWideband) { diffArrivalTime = (uint32_t)diffArrivalTime >> 1; diffSendTime = (uint32_t)diffSendTime >> 1; } // arrival timestamp in 16 kHz arrivalTimestampIn16kHz = (uint32_t)((uint32_t) bwest_str->prev_rec_arr_ts + (uint32_t)diffArrivalTime); // send timestamp in 16 kHz sendTimestampIn16kHz = (uint32_t)((uint32_t) bwest_str->prev_rec_send_ts + (uint32_t)diffSendTime); err = WebRtcIsac_UpdateBandwidthEstimator(bwest_str, rtp_seq_number, (frame_samples * 1000) / FS, sendTimestampIn16kHz, arrivalTimestampIn16kHz, packet_size); // error check if(err < 0) { return err; } return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/encode.c0000664000175000017500000013767314475643423030275 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * encode.c * * This file contains definition of funtions for encoding. * Decoding of upper-band, including 8-12 kHz, when the bandwidth is * 0-12 kHz, and 8-16 kHz, when the bandwidth is 0-16 kHz. * */ #include #include #include #include "modules/audio_coding/codecs/isac/main/source/structs.h" #include "modules/audio_coding/codecs/isac/main/source/codec.h" #include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h" #include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h" #include "modules/audio_coding/codecs/isac/main/source/arith_routines.h" #include "modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h" #include "modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h" #include "modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h" #include "modules/audio_coding/codecs/isac/main/source/lpc_tables.h" #include "modules/audio_coding/codecs/isac/main/source/lpc_analysis.h" #include "modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h" #include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h" #include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h" #include "modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h" #include "modules/audio_coding/codecs/isac/main/source/isac_vad.h" #include "modules/audio_coding/codecs/isac/main/source/pitch_filter.h" #define UB_LOOKAHEAD 24 /* Rate allocation tables of lower and upper-band bottleneck for 12kHz & 16kHz bandwidth. 12 kHz bandwidth ----------------- The overall bottleneck of the coder is between 38 kbps and 45 kbps. We have considered 7 enteries, uniformly distributed in this interval, i.e. 38, 39.17, 40.33, 41.5, 42.67, 43.83 and 45. For every entery, the lower-band and the upper-band bottlenecks are specified in 'kLowerBandBitRate12' and 'kUpperBandBitRate12' tables, respectively. E.g. the overall rate of 41.5 kbps corresponts to a bottleneck of 31 kbps for lower-band and 27 kbps for upper-band. Given an overall bottleneck of the codec, we use linear interpolation to get lower-band and upper-band bottlenecks. 16 kHz bandwidth ----------------- The overall bottleneck of the coder is between 50 kbps and 56 kbps. We have considered 7 enteries, uniformly distributed in this interval, i.e. 50, 51.2, 52.4, 53.6, 54.8 and 56. For every entery, the lower-band and the upper-band bottlenecks are specified in 'kLowerBandBitRate16' and 'kUpperBandBitRate16' tables, respectively. E.g. the overall rate of 53.6 kbps corresponts to a bottleneck of 32 kbps for lower-band and 30 kbps for upper-band. Given an overall bottleneck of the codec, we use linear interpolation to get lower-band and upper-band bottlenecks. */ /* 38 39.17 40.33 41.5 42.67 43.83 45 */ static const int16_t kLowerBandBitRate12[7] = { 29000, 30000, 30000, 31000, 31000, 32000, 32000 }; static const int16_t kUpperBandBitRate12[7] = { 25000, 25000, 27000, 27000, 29000, 29000, 32000 }; /* 50 51.2 52.4 53.6 54.8 56 */ static const int16_t kLowerBandBitRate16[6] = { 31000, 31000, 32000, 32000, 32000, 32000 }; static const int16_t kUpperBandBitRate16[6] = { 28000, 29000, 29000, 30000, 31000, 32000 }; /****************************************************************************** * WebRtcIsac_RateAllocation() * Internal function to perform a rate-allocation for upper and lower-band, * given a total rate. * * Input: * - inRateBitPerSec : a total bottleneck in bits/sec. * * Output: * - rateLBBitPerSec : a bottleneck allocated to the lower-band * in bits/sec. * - rateUBBitPerSec : a bottleneck allocated to the upper-band * in bits/sec. * * Return value : 0 if rate allocation has been successful. * -1 if failed to allocate rates. */ int16_t WebRtcIsac_RateAllocation(int32_t inRateBitPerSec, double* rateLBBitPerSec, double* rateUBBitPerSec, enum ISACBandwidth* bandwidthKHz) { int16_t idx; double idxD; double idxErr; if (inRateBitPerSec < 38000) { /* If the given overall bottleneck is less than 38000 then * then codec has to operate in wideband mode, i.e. 8 kHz * bandwidth. */ *rateLBBitPerSec = (int16_t)((inRateBitPerSec > 32000) ? 32000 : inRateBitPerSec); *rateUBBitPerSec = 0; *bandwidthKHz = isac8kHz; } else if ((inRateBitPerSec >= 38000) && (inRateBitPerSec < 50000)) { /* At a bottleneck between 38 and 50 kbps the codec is operating * at 12 kHz bandwidth. Using xxxBandBitRate12[] to calculates * upper/lower bottleneck */ /* Find the bottlenecks by linear interpolation, * step is (45000 - 38000)/6.0 we use the inverse of it. */ const double stepSizeInv = 8.5714286e-4; idxD = (inRateBitPerSec - 38000) * stepSizeInv; idx = (idxD >= 6) ? 6 : ((int16_t)idxD); idxErr = idxD - idx; *rateLBBitPerSec = kLowerBandBitRate12[idx]; *rateUBBitPerSec = kUpperBandBitRate12[idx]; if (idx < 6) { *rateLBBitPerSec += (int16_t)( idxErr * (kLowerBandBitRate12[idx + 1] - kLowerBandBitRate12[idx])); *rateUBBitPerSec += (int16_t)( idxErr * (kUpperBandBitRate12[idx + 1] - kUpperBandBitRate12[idx])); } *bandwidthKHz = isac12kHz; } else if ((inRateBitPerSec >= 50000) && (inRateBitPerSec <= 56000)) { /* A bottleneck between 50 and 56 kbps corresponds to bandwidth * of 16 kHz. Using xxxBandBitRate16[] to calculates * upper/lower bottleneck. */ /* Find the bottlenecks by linear interpolation * step is (56000 - 50000)/5 we use the inverse of it. */ const double stepSizeInv = 8.3333333e-4; idxD = (inRateBitPerSec - 50000) * stepSizeInv; idx = (idxD >= 5) ? 5 : ((int16_t)idxD); idxErr = idxD - idx; *rateLBBitPerSec = kLowerBandBitRate16[idx]; *rateUBBitPerSec = kUpperBandBitRate16[idx]; if (idx < 5) { *rateLBBitPerSec += (int16_t)(idxErr * (kLowerBandBitRate16[idx + 1] - kLowerBandBitRate16[idx])); *rateUBBitPerSec += (int16_t)(idxErr * (kUpperBandBitRate16[idx + 1] - kUpperBandBitRate16[idx])); } *bandwidthKHz = isac16kHz; } else { /* Out-of-range botlteneck value. */ return -1; } /* limit the values. */ *rateLBBitPerSec = (*rateLBBitPerSec > 32000) ? 32000 : *rateLBBitPerSec; *rateUBBitPerSec = (*rateUBBitPerSec > 32000) ? 32000 : *rateUBBitPerSec; return 0; } void WebRtcIsac_ResetBitstream(Bitstr* bit_stream) { bit_stream->W_upper = 0xFFFFFFFF; bit_stream->stream_index = 0; bit_stream->streamval = 0; } int WebRtcIsac_EncodeLb(const TransformTables* transform_tables, float* in, ISACLBEncStruct* ISACencLB_obj, int16_t codingMode, int16_t bottleneckIndex) { int stream_length = 0; int err; int k; int iterCntr; double lofilt_coef[(ORDERLO + 1)*SUBFRAMES]; double hifilt_coef[(ORDERHI + 1)*SUBFRAMES]; float LP[FRAMESAMPLES_HALF]; float HP[FRAMESAMPLES_HALF]; double LP_lookahead[FRAMESAMPLES_HALF]; double HP_lookahead[FRAMESAMPLES_HALF]; double LP_lookahead_pf[FRAMESAMPLES_HALF + QLOOKAHEAD]; double LPw[FRAMESAMPLES_HALF]; double HPw[FRAMESAMPLES_HALF]; double LPw_pf[FRAMESAMPLES_HALF]; int16_t fre[FRAMESAMPLES_HALF]; /* Q7 */ int16_t fim[FRAMESAMPLES_HALF]; /* Q7 */ double PitchLags[4]; double PitchGains[4]; int16_t PitchGains_Q12[4]; int16_t AvgPitchGain_Q12; int frame_mode; /* 0 for 30ms, 1 for 60ms */ int status = 0; int my_index; transcode_obj transcodingParam; double bytesLeftSpecCoding; uint16_t payloadLimitBytes; /* Copy new frame-length and bottleneck rate only for the first 10 ms data */ if (ISACencLB_obj->buffer_index == 0) { /* Set the framelength for the next packet. */ ISACencLB_obj->current_framesamples = ISACencLB_obj->new_framelength; } /* 'frame_mode' is 0 (30 ms) or 1 (60 ms). */ frame_mode = ISACencLB_obj->current_framesamples / MAX_FRAMESAMPLES; /* buffer speech samples (by 10ms packet) until the frame-length */ /* is reached (30 or 60 ms). */ /*****************************************************************/ /* fill the buffer with 10ms input data */ for (k = 0; k < FRAMESAMPLES_10ms; k++) { ISACencLB_obj->data_buffer_float[k + ISACencLB_obj->buffer_index] = in[k]; } /* If buffersize is not equal to current framesize then increase index * and return. We do no encoding untill we have enough audio. */ if (ISACencLB_obj->buffer_index + FRAMESAMPLES_10ms != FRAMESAMPLES) { ISACencLB_obj->buffer_index += FRAMESAMPLES_10ms; return 0; } /* If buffer reached the right size, reset index and continue with * encoding the frame. */ ISACencLB_obj->buffer_index = 0; /* End of buffer function. */ /**************************/ /* Encoding */ /************/ if (frame_mode == 0 || ISACencLB_obj->frame_nb == 0) { /* This is to avoid Linux warnings until we change 'int' to 'Word32' * at all places. */ int intVar; /* reset bitstream */ WebRtcIsac_ResetBitstream(&(ISACencLB_obj->bitstr_obj)); if ((codingMode == 0) && (frame_mode == 0) && (ISACencLB_obj->enforceFrameSize == 0)) { ISACencLB_obj->new_framelength = WebRtcIsac_GetNewFrameLength( ISACencLB_obj->bottleneck, ISACencLB_obj->current_framesamples); } ISACencLB_obj->s2nr = WebRtcIsac_GetSnr( ISACencLB_obj->bottleneck, ISACencLB_obj->current_framesamples); /* Encode frame length. */ status = WebRtcIsac_EncodeFrameLen( ISACencLB_obj->current_framesamples, &ISACencLB_obj->bitstr_obj); if (status < 0) { /* Wrong frame size. */ return status; } /* Save framelength for multiple packets memory. */ ISACencLB_obj->SaveEnc_obj.framelength = ISACencLB_obj->current_framesamples; /* To be used for Redundant Coding. */ ISACencLB_obj->lastBWIdx = bottleneckIndex; intVar = (int)bottleneckIndex; WebRtcIsac_EncodeReceiveBw(&intVar, &ISACencLB_obj->bitstr_obj); } /* Split signal in two bands. */ WebRtcIsac_SplitAndFilterFloat(ISACencLB_obj->data_buffer_float, LP, HP, LP_lookahead, HP_lookahead, &ISACencLB_obj->prefiltbankstr_obj); /* estimate pitch parameters and pitch-filter lookahead signal */ WebRtcIsac_PitchAnalysis(LP_lookahead, LP_lookahead_pf, &ISACencLB_obj->pitchanalysisstr_obj, PitchLags, PitchGains); /* Encode in FIX Q12. */ /* Convert PitchGain to Fixed point. */ for (k = 0; k < PITCH_SUBFRAMES; k++) { PitchGains_Q12[k] = (int16_t)(PitchGains[k] * 4096.0); } /* Set where to store data in multiple packets memory. */ if (frame_mode == 0 || ISACencLB_obj->frame_nb == 0) { ISACencLB_obj->SaveEnc_obj.startIdx = 0; } else { ISACencLB_obj->SaveEnc_obj.startIdx = 1; } /* Quantize & encode pitch parameters. */ WebRtcIsac_EncodePitchGain(PitchGains_Q12, &ISACencLB_obj->bitstr_obj, &ISACencLB_obj->SaveEnc_obj); WebRtcIsac_EncodePitchLag(PitchLags, PitchGains_Q12, &ISACencLB_obj->bitstr_obj, &ISACencLB_obj->SaveEnc_obj); AvgPitchGain_Q12 = (PitchGains_Q12[0] + PitchGains_Q12[1] + PitchGains_Q12[2] + PitchGains_Q12[3]) >> 2; /* Find coefficients for perceptual pre-filters. */ WebRtcIsac_GetLpcCoefLb(LP_lookahead_pf, HP_lookahead, &ISACencLB_obj->maskfiltstr_obj, ISACencLB_obj->s2nr, PitchGains_Q12, lofilt_coef, hifilt_coef); /* Code LPC model and shape - gains not quantized yet. */ WebRtcIsac_EncodeLpcLb(lofilt_coef, hifilt_coef, &ISACencLB_obj->bitstr_obj, &ISACencLB_obj->SaveEnc_obj); /* Convert PitchGains back to FLOAT for pitchfilter_pre. */ for (k = 0; k < 4; k++) { PitchGains[k] = ((float)PitchGains_Q12[k]) / 4096; } /* Store the state of arithmetic coder before coding LPC gains. */ transcodingParam.W_upper = ISACencLB_obj->bitstr_obj.W_upper; transcodingParam.stream_index = ISACencLB_obj->bitstr_obj.stream_index; transcodingParam.streamval = ISACencLB_obj->bitstr_obj.streamval; transcodingParam.stream[0] = ISACencLB_obj->bitstr_obj.stream[ISACencLB_obj->bitstr_obj.stream_index - 2]; transcodingParam.stream[1] = ISACencLB_obj->bitstr_obj.stream[ISACencLB_obj->bitstr_obj.stream_index - 1]; transcodingParam.stream[2] = ISACencLB_obj->bitstr_obj.stream[ISACencLB_obj->bitstr_obj.stream_index]; /* Store LPC Gains before encoding them. */ for (k = 0; k < SUBFRAMES; k++) { transcodingParam.loFiltGain[k] = lofilt_coef[(LPC_LOBAND_ORDER + 1) * k]; transcodingParam.hiFiltGain[k] = hifilt_coef[(LPC_HIBAND_ORDER + 1) * k]; } /* Code gains */ WebRtcIsac_EncodeLpcGainLb(lofilt_coef, hifilt_coef, &ISACencLB_obj->bitstr_obj, &ISACencLB_obj->SaveEnc_obj); /* Get the correct value for the payload limit and calculate the * number of bytes left for coding the spectrum. */ if ((frame_mode == 1) && (ISACencLB_obj->frame_nb == 0)) { /* It is a 60ms and we are in the first 30ms then the limit at * this point should be half of the assigned value. */ payloadLimitBytes = ISACencLB_obj->payloadLimitBytes60 >> 1; } else if (frame_mode == 0) { /* It is a 30ms frame */ /* Subract 3 because termination process may add 3 bytes. */ payloadLimitBytes = ISACencLB_obj->payloadLimitBytes30 - 3; } else { /* This is the second half of a 60ms frame. */ /* Subract 3 because termination process may add 3 bytes. */ payloadLimitBytes = ISACencLB_obj->payloadLimitBytes60 - 3; } bytesLeftSpecCoding = payloadLimitBytes - transcodingParam.stream_index; /* Perceptual pre-filtering (using normalized lattice filter). */ /* Low-band filtering. */ WebRtcIsac_NormLatticeFilterMa(ORDERLO, ISACencLB_obj->maskfiltstr_obj.PreStateLoF, ISACencLB_obj->maskfiltstr_obj.PreStateLoG, LP, lofilt_coef, LPw); /* High-band filtering. */ WebRtcIsac_NormLatticeFilterMa(ORDERHI, ISACencLB_obj->maskfiltstr_obj.PreStateHiF, ISACencLB_obj->maskfiltstr_obj.PreStateHiG, HP, hifilt_coef, HPw); /* Pitch filter. */ WebRtcIsac_PitchfilterPre(LPw, LPw_pf, &ISACencLB_obj->pitchfiltstr_obj, PitchLags, PitchGains); /* Transform */ WebRtcIsac_Time2Spec(transform_tables, LPw_pf, HPw, fre, fim, &ISACencLB_obj->fftstr_obj); /* Save data for multiple packets memory. */ my_index = ISACencLB_obj->SaveEnc_obj.startIdx * FRAMESAMPLES_HALF; memcpy(&ISACencLB_obj->SaveEnc_obj.fre[my_index], fre, sizeof(fre)); memcpy(&ISACencLB_obj->SaveEnc_obj.fim[my_index], fim, sizeof(fim)); ISACencLB_obj->SaveEnc_obj.AvgPitchGain[ISACencLB_obj->SaveEnc_obj.startIdx] = AvgPitchGain_Q12; /* Quantization and loss-less coding. */ err = WebRtcIsac_EncodeSpec(fre, fim, AvgPitchGain_Q12, kIsacLowerBand, &ISACencLB_obj->bitstr_obj); if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { /* There has been an error but it was not too large payload (we can cure too large payload). */ if (frame_mode == 1 && ISACencLB_obj->frame_nb == 1) { /* If this is the second 30ms of a 60ms frame reset this such that in the next call encoder starts fresh. */ ISACencLB_obj->frame_nb = 0; } return err; } iterCntr = 0; while ((ISACencLB_obj->bitstr_obj.stream_index > payloadLimitBytes) || (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { double bytesSpecCoderUsed; double transcodeScale; if (iterCntr >= MAX_PAYLOAD_LIMIT_ITERATION) { /* We were not able to limit the payload size */ if ((frame_mode == 1) && (ISACencLB_obj->frame_nb == 0)) { /* This was the first 30ms of a 60ms frame. Although the payload is larger than it should be but we let the second 30ms be encoded. Maybe together we won't exceed the limit. */ ISACencLB_obj->frame_nb = 1; return 0; } else if ((frame_mode == 1) && (ISACencLB_obj->frame_nb == 1)) { ISACencLB_obj->frame_nb = 0; } if (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH) { return -ISAC_PAYLOAD_LARGER_THAN_LIMIT; } else { return status; } } if (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH) { bytesSpecCoderUsed = STREAM_SIZE_MAX; /* Being conservative */ transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed * 0.5; } else { bytesSpecCoderUsed = ISACencLB_obj->bitstr_obj.stream_index - transcodingParam.stream_index; transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed; } /* To be safe, we reduce the scale depending on the number of iterations. */ transcodeScale *= (1.0 - (0.9 * (double)iterCntr / (double)MAX_PAYLOAD_LIMIT_ITERATION)); /* Scale the LPC Gains. */ for (k = 0; k < SUBFRAMES; k++) { lofilt_coef[(LPC_LOBAND_ORDER + 1) * k] = transcodingParam.loFiltGain[k] * transcodeScale; hifilt_coef[(LPC_HIBAND_ORDER + 1) * k] = transcodingParam.hiFiltGain[k] * transcodeScale; transcodingParam.loFiltGain[k] = lofilt_coef[(LPC_LOBAND_ORDER + 1) * k]; transcodingParam.hiFiltGain[k] = hifilt_coef[(LPC_HIBAND_ORDER + 1) * k]; } /* Scale DFT coefficients. */ for (k = 0; k < FRAMESAMPLES_HALF; k++) { fre[k] = (int16_t)(fre[k] * transcodeScale); fim[k] = (int16_t)(fim[k] * transcodeScale); } /* Save data for multiple packets memory. */ my_index = ISACencLB_obj->SaveEnc_obj.startIdx * FRAMESAMPLES_HALF; memcpy(&ISACencLB_obj->SaveEnc_obj.fre[my_index], fre, sizeof(fre)); memcpy(&ISACencLB_obj->SaveEnc_obj.fim[my_index], fim, sizeof(fim)); /* Re-store the state of arithmetic coder before coding LPC gains. */ ISACencLB_obj->bitstr_obj.W_upper = transcodingParam.W_upper; ISACencLB_obj->bitstr_obj.stream_index = transcodingParam.stream_index; ISACencLB_obj->bitstr_obj.streamval = transcodingParam.streamval; ISACencLB_obj->bitstr_obj.stream[transcodingParam.stream_index - 2] = transcodingParam.stream[0]; ISACencLB_obj->bitstr_obj.stream[transcodingParam.stream_index - 1] = transcodingParam.stream[1]; ISACencLB_obj->bitstr_obj.stream[transcodingParam.stream_index] = transcodingParam.stream[2]; /* Code gains. */ WebRtcIsac_EncodeLpcGainLb(lofilt_coef, hifilt_coef, &ISACencLB_obj->bitstr_obj, &ISACencLB_obj->SaveEnc_obj); /* Update the number of bytes left for encoding the spectrum. */ bytesLeftSpecCoding = payloadLimitBytes - transcodingParam.stream_index; /* Encode the spectrum. */ err = WebRtcIsac_EncodeSpec(fre, fim, AvgPitchGain_Q12, kIsacLowerBand, &ISACencLB_obj->bitstr_obj); if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { /* There has been an error but it was not too large payload (we can cure too large payload). */ if (frame_mode == 1 && ISACencLB_obj->frame_nb == 1) { /* If this is the second 30 ms of a 60 ms frame reset this such that in the next call encoder starts fresh. */ ISACencLB_obj->frame_nb = 0; } return err; } iterCntr++; } /* If 60 ms frame-size and just processed the first 30 ms, */ /* go back to main function to buffer the other 30 ms speech frame. */ if (frame_mode == 1) { if (ISACencLB_obj->frame_nb == 0) { ISACencLB_obj->frame_nb = 1; return 0; } else if (ISACencLB_obj->frame_nb == 1) { ISACencLB_obj->frame_nb = 0; /* Also update the frame-length for next packet, in Adaptive mode only. */ if (codingMode == 0 && (ISACencLB_obj->enforceFrameSize == 0)) { ISACencLB_obj->new_framelength = WebRtcIsac_GetNewFrameLength(ISACencLB_obj->bottleneck, ISACencLB_obj->current_framesamples); } } } else { ISACencLB_obj->frame_nb = 0; } /* Complete arithmetic coding. */ stream_length = WebRtcIsac_EncTerminate(&ISACencLB_obj->bitstr_obj); return stream_length; } static int LimitPayloadUb(ISACUBEncStruct* ISACencUB_obj, uint16_t payloadLimitBytes, double bytesLeftSpecCoding, transcode_obj* transcodingParam, int16_t* fre, int16_t* fim, double* lpcGains, enum ISACBand band, int status) { int iterCntr = 0; int k; double bytesSpecCoderUsed; double transcodeScale; const int16_t kAveragePitchGain = 0.0; do { if (iterCntr >= MAX_PAYLOAD_LIMIT_ITERATION) { /* We were not able to limit the payload size. */ return -ISAC_PAYLOAD_LARGER_THAN_LIMIT; } if (status == -ISAC_DISALLOWED_BITSTREAM_LENGTH) { bytesSpecCoderUsed = STREAM_SIZE_MAX; /* Being conservative. */ transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed * 0.5; } else { bytesSpecCoderUsed = ISACencUB_obj->bitstr_obj.stream_index - transcodingParam->stream_index; transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed; } /* To be safe, we reduce the scale depending on the number of iterations. */ transcodeScale *= (1.0 - (0.9 * (double)iterCntr / (double)MAX_PAYLOAD_LIMIT_ITERATION)); /* Scale the LPC Gains. */ if (band == kIsacUpperBand16) { /* Two sets of coefficients if 16 kHz. */ for (k = 0; k < SUBFRAMES; k++) { transcodingParam->loFiltGain[k] *= transcodeScale; transcodingParam->hiFiltGain[k] *= transcodeScale; } } else { /* One sets of coefficients if 12 kHz. */ for (k = 0; k < SUBFRAMES; k++) { transcodingParam->loFiltGain[k] *= transcodeScale; } } /* Scale DFT coefficients. */ for (k = 0; k < FRAMESAMPLES_HALF; k++) { fre[k] = (int16_t)(fre[k] * transcodeScale + 0.5); fim[k] = (int16_t)(fim[k] * transcodeScale + 0.5); } /* Store FFT coefficients for multiple encoding. */ memcpy(ISACencUB_obj->SaveEnc_obj.realFFT, fre, sizeof(ISACencUB_obj->SaveEnc_obj.realFFT)); memcpy(ISACencUB_obj->SaveEnc_obj.imagFFT, fim, sizeof(ISACencUB_obj->SaveEnc_obj.imagFFT)); /* Store the state of arithmetic coder before coding LPC gains */ ISACencUB_obj->bitstr_obj.W_upper = transcodingParam->W_upper; ISACencUB_obj->bitstr_obj.stream_index = transcodingParam->stream_index; ISACencUB_obj->bitstr_obj.streamval = transcodingParam->streamval; ISACencUB_obj->bitstr_obj.stream[transcodingParam->stream_index - 2] = transcodingParam->stream[0]; ISACencUB_obj->bitstr_obj.stream[transcodingParam->stream_index - 1] = transcodingParam->stream[1]; ISACencUB_obj->bitstr_obj.stream[transcodingParam->stream_index] = transcodingParam->stream[2]; /* Store the gains for multiple encoding. */ memcpy(ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains, SUBFRAMES * sizeof(double)); /* Entropy Code lpc-gains, indices are stored for a later use.*/ WebRtcIsac_EncodeLpcGainUb(transcodingParam->loFiltGain, &ISACencUB_obj->bitstr_obj, ISACencUB_obj->SaveEnc_obj.lpcGainIndex); /* If 16kHz should do one more set. */ if (band == kIsacUpperBand16) { /* Store the gains for multiple encoding. */ memcpy(&ISACencUB_obj->SaveEnc_obj.lpcGain[SUBFRAMES], &lpcGains[SUBFRAMES], SUBFRAMES * sizeof(double)); /* Entropy Code lpc-gains, indices are stored for a later use.*/ WebRtcIsac_EncodeLpcGainUb( transcodingParam->hiFiltGain, &ISACencUB_obj->bitstr_obj, &ISACencUB_obj->SaveEnc_obj.lpcGainIndex[SUBFRAMES]); } /* Update the number of bytes left for encoding the spectrum. */ bytesLeftSpecCoding = payloadLimitBytes - ISACencUB_obj->bitstr_obj.stream_index; /* Save the bit-stream object at this point for FEC. */ memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj, &ISACencUB_obj->bitstr_obj, sizeof(Bitstr)); /* Encode the spectrum. */ status = WebRtcIsac_EncodeSpec(fre, fim, kAveragePitchGain, band, &ISACencUB_obj->bitstr_obj); if ((status < 0) && (status != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { /* There has been an error but it was not too large payload (we can cure too large payload). */ return status; } iterCntr++; } while ((ISACencUB_obj->bitstr_obj.stream_index > payloadLimitBytes) || (status == -ISAC_DISALLOWED_BITSTREAM_LENGTH)); return 0; } int WebRtcIsac_EncodeUb16(const TransformTables* transform_tables, float* in, ISACUBEncStruct* ISACencUB_obj, int32_t jitterInfo) { int err; int k; double lpcVecs[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; double percepFilterParams[(1 + UB_LPC_ORDER) * (SUBFRAMES << 1) + (1 + UB_LPC_ORDER)]; double LP_lookahead[FRAMESAMPLES]; int16_t fre[FRAMESAMPLES_HALF]; /* Q7 */ int16_t fim[FRAMESAMPLES_HALF]; /* Q7 */ int status = 0; double varscale[2]; double corr[SUBFRAMES << 1][UB_LPC_ORDER + 1]; double lpcGains[SUBFRAMES << 1]; transcode_obj transcodingParam; uint16_t payloadLimitBytes; double s2nr; const int16_t kAveragePitchGain = 0.0; int bytesLeftSpecCoding; /* Buffer speech samples (by 10ms packet) until the frame-length is */ /* reached (30 ms). */ /*********************************************************************/ /* fill the buffer with 10ms input data */ memcpy(&ISACencUB_obj->data_buffer_float[ISACencUB_obj->buffer_index], in, FRAMESAMPLES_10ms * sizeof(float)); /* If buffer size is not equal to current frame-size, and end of file is * not reached yet, we don't do encoding unless we have the whole frame. */ if (ISACencUB_obj->buffer_index + FRAMESAMPLES_10ms < FRAMESAMPLES) { ISACencUB_obj->buffer_index += FRAMESAMPLES_10ms; return 0; } /* End of buffer function. */ /**************************/ /* Encoding */ /************/ /* Reset bit-stream */ WebRtcIsac_ResetBitstream(&(ISACencUB_obj->bitstr_obj)); /* Encoding of bandwidth information. */ WebRtcIsac_EncodeJitterInfo(jitterInfo, &ISACencUB_obj->bitstr_obj); status = WebRtcIsac_EncodeBandwidth(isac16kHz, &ISACencUB_obj->bitstr_obj); if (status < 0) { return status; } s2nr = WebRtcIsac_GetSnr(ISACencUB_obj->bottleneck, FRAMESAMPLES); memcpy(lpcVecs, ISACencUB_obj->lastLPCVec, UB_LPC_ORDER * sizeof(double)); for (k = 0; k < FRAMESAMPLES; k++) { LP_lookahead[k] = ISACencUB_obj->data_buffer_float[UB_LOOKAHEAD + k]; } /* Find coefficients for perceptual pre-filters. */ WebRtcIsac_GetLpcCoefUb(LP_lookahead, &ISACencUB_obj->maskfiltstr_obj, &lpcVecs[UB_LPC_ORDER], corr, varscale, isac16kHz); memcpy(ISACencUB_obj->lastLPCVec, &lpcVecs[(UB16_LPC_VEC_PER_FRAME - 1) * (UB_LPC_ORDER)], sizeof(double) * UB_LPC_ORDER); /* Code LPC model and shape - gains not quantized yet. */ WebRtcIsac_EncodeLpcUB(lpcVecs, &ISACencUB_obj->bitstr_obj, percepFilterParams, isac16kHz, &ISACencUB_obj->SaveEnc_obj); /* the first set of lpc parameters are from the last sub-frame of * the previous frame. so we don't care about them. */ WebRtcIsac_GetLpcGain(s2nr, &percepFilterParams[UB_LPC_ORDER + 1], (SUBFRAMES << 1), lpcGains, corr, varscale); /* Store the state of arithmetic coder before coding LPC gains */ transcodingParam.stream_index = ISACencUB_obj->bitstr_obj.stream_index; transcodingParam.W_upper = ISACencUB_obj->bitstr_obj.W_upper; transcodingParam.streamval = ISACencUB_obj->bitstr_obj.streamval; transcodingParam.stream[0] = ISACencUB_obj->bitstr_obj.stream[ISACencUB_obj->bitstr_obj.stream_index - 2]; transcodingParam.stream[1] = ISACencUB_obj->bitstr_obj.stream[ISACencUB_obj->bitstr_obj.stream_index - 1]; transcodingParam.stream[2] = ISACencUB_obj->bitstr_obj.stream[ISACencUB_obj->bitstr_obj.stream_index]; /* Store LPC Gains before encoding them. */ for (k = 0; k < SUBFRAMES; k++) { transcodingParam.loFiltGain[k] = lpcGains[k]; transcodingParam.hiFiltGain[k] = lpcGains[SUBFRAMES + k]; } /* Store the gains for multiple encoding. */ memcpy(ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains, (SUBFRAMES << 1) * sizeof(double)); WebRtcIsac_EncodeLpcGainUb(lpcGains, &ISACencUB_obj->bitstr_obj, ISACencUB_obj->SaveEnc_obj.lpcGainIndex); WebRtcIsac_EncodeLpcGainUb( &lpcGains[SUBFRAMES], &ISACencUB_obj->bitstr_obj, &ISACencUB_obj->SaveEnc_obj.lpcGainIndex[SUBFRAMES]); /* Get the correct value for the payload limit and calculate the number of bytes left for coding the spectrum. It is a 30ms frame Subract 3 because termination process may add 3 bytes */ payloadLimitBytes = ISACencUB_obj->maxPayloadSizeBytes - ISACencUB_obj->numBytesUsed - 3; bytesLeftSpecCoding = payloadLimitBytes - ISACencUB_obj->bitstr_obj.stream_index; for (k = 0; k < (SUBFRAMES << 1); k++) { percepFilterParams[k * (UB_LPC_ORDER + 1) + (UB_LPC_ORDER + 1)] = lpcGains[k]; } /* LPC filtering (using normalized lattice filter), */ /* first half-frame. */ WebRtcIsac_NormLatticeFilterMa(UB_LPC_ORDER, ISACencUB_obj->maskfiltstr_obj.PreStateLoF, ISACencUB_obj->maskfiltstr_obj.PreStateLoG, &ISACencUB_obj->data_buffer_float[0], &percepFilterParams[UB_LPC_ORDER + 1], &LP_lookahead[0]); /* Second half-frame filtering. */ WebRtcIsac_NormLatticeFilterMa( UB_LPC_ORDER, ISACencUB_obj->maskfiltstr_obj.PreStateLoF, ISACencUB_obj->maskfiltstr_obj.PreStateLoG, &ISACencUB_obj->data_buffer_float[FRAMESAMPLES_HALF], &percepFilterParams[(UB_LPC_ORDER + 1) + SUBFRAMES * (UB_LPC_ORDER + 1)], &LP_lookahead[FRAMESAMPLES_HALF]); WebRtcIsac_Time2Spec(transform_tables, &LP_lookahead[0], &LP_lookahead[FRAMESAMPLES_HALF], fre, fim, &ISACencUB_obj->fftstr_obj); /* Store FFT coefficients for multiple encoding. */ memcpy(ISACencUB_obj->SaveEnc_obj.realFFT, fre, sizeof(fre)); memcpy(ISACencUB_obj->SaveEnc_obj.imagFFT, fim, sizeof(fim)); /* Prepare the audio buffer for the next packet * move the last 3 ms to the beginning of the buffer. */ memcpy(ISACencUB_obj->data_buffer_float, &ISACencUB_obj->data_buffer_float[FRAMESAMPLES], LB_TOTAL_DELAY_SAMPLES * sizeof(float)); /* start writing with 3 ms delay to compensate for the delay * of the lower-band. */ ISACencUB_obj->buffer_index = LB_TOTAL_DELAY_SAMPLES; /* Save the bit-stream object at this point for FEC. */ memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj, &ISACencUB_obj->bitstr_obj, sizeof(Bitstr)); /* Qantization and lossless coding */ /* Note that there is no pitch-gain for this band so kAveragePitchGain = 0 * is passed to the function. In fact, the function ignores the 3rd parameter * for this band. */ err = WebRtcIsac_EncodeSpec(fre, fim, kAveragePitchGain, kIsacUpperBand16, &ISACencUB_obj->bitstr_obj); if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { return err; } if ((ISACencUB_obj->bitstr_obj.stream_index > payloadLimitBytes) || (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { err = LimitPayloadUb(ISACencUB_obj, payloadLimitBytes, bytesLeftSpecCoding, &transcodingParam, fre, fim, lpcGains, kIsacUpperBand16, err); } if (err < 0) { return err; } /* Complete arithmetic coding. */ return WebRtcIsac_EncTerminate(&ISACencUB_obj->bitstr_obj); } int WebRtcIsac_EncodeUb12(const TransformTables* transform_tables, float* in, ISACUBEncStruct* ISACencUB_obj, int32_t jitterInfo) { int err; int k; double lpcVecs[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME]; double percepFilterParams[(1 + UB_LPC_ORDER) * SUBFRAMES]; float LP[FRAMESAMPLES_HALF]; float HP[FRAMESAMPLES_HALF]; double LP_lookahead[FRAMESAMPLES_HALF]; double HP_lookahead[FRAMESAMPLES_HALF]; double LPw[FRAMESAMPLES_HALF]; double HPw[FRAMESAMPLES_HALF]; int16_t fre[FRAMESAMPLES_HALF]; /* Q7 */ int16_t fim[FRAMESAMPLES_HALF]; /* Q7 */ int status = 0; double varscale[1]; double corr[UB_LPC_GAIN_DIM][UB_LPC_ORDER + 1]; double lpcGains[SUBFRAMES]; transcode_obj transcodingParam; uint16_t payloadLimitBytes; double s2nr; const int16_t kAveragePitchGain = 0.0; double bytesLeftSpecCoding; /* Buffer speech samples (by 10ms packet) until the framelength is */ /* reached (30 ms). */ /********************************************************************/ /* Fill the buffer with 10ms input data. */ memcpy(&ISACencUB_obj->data_buffer_float[ISACencUB_obj->buffer_index], in, FRAMESAMPLES_10ms * sizeof(float)); /* if buffer-size is not equal to current frame-size then increase the index and return. We do the encoding when we have enough audio. */ if (ISACencUB_obj->buffer_index + FRAMESAMPLES_10ms < FRAMESAMPLES) { ISACencUB_obj->buffer_index += FRAMESAMPLES_10ms; return 0; } /* If buffer reached the right size, reset index and continue with encoding the frame */ ISACencUB_obj->buffer_index = 0; /* End of buffer function */ /**************************/ /* Encoding */ /************/ /* Reset bit-stream. */ WebRtcIsac_ResetBitstream(&(ISACencUB_obj->bitstr_obj)); /* Encoding bandwidth information. */ WebRtcIsac_EncodeJitterInfo(jitterInfo, &ISACencUB_obj->bitstr_obj); status = WebRtcIsac_EncodeBandwidth(isac12kHz, &ISACencUB_obj->bitstr_obj); if (status < 0) { return status; } s2nr = WebRtcIsac_GetSnr(ISACencUB_obj->bottleneck, FRAMESAMPLES); /* Split signal in two bands. */ WebRtcIsac_SplitAndFilterFloat(ISACencUB_obj->data_buffer_float, HP, LP, HP_lookahead, LP_lookahead, &ISACencUB_obj->prefiltbankstr_obj); /* Find coefficients for perceptual pre-filters. */ WebRtcIsac_GetLpcCoefUb(LP_lookahead, &ISACencUB_obj->maskfiltstr_obj, lpcVecs, corr, varscale, isac12kHz); /* Code LPC model and shape - gains not quantized yet. */ WebRtcIsac_EncodeLpcUB(lpcVecs, &ISACencUB_obj->bitstr_obj, percepFilterParams, isac12kHz, &ISACencUB_obj->SaveEnc_obj); WebRtcIsac_GetLpcGain(s2nr, percepFilterParams, SUBFRAMES, lpcGains, corr, varscale); /* Store the state of arithmetic coder before coding LPC gains. */ transcodingParam.W_upper = ISACencUB_obj->bitstr_obj.W_upper; transcodingParam.stream_index = ISACencUB_obj->bitstr_obj.stream_index; transcodingParam.streamval = ISACencUB_obj->bitstr_obj.streamval; transcodingParam.stream[0] = ISACencUB_obj->bitstr_obj.stream[ISACencUB_obj->bitstr_obj.stream_index - 2]; transcodingParam.stream[1] = ISACencUB_obj->bitstr_obj.stream[ISACencUB_obj->bitstr_obj.stream_index - 1]; transcodingParam.stream[2] = ISACencUB_obj->bitstr_obj.stream[ISACencUB_obj->bitstr_obj.stream_index]; /* Store LPC Gains before encoding them. */ for (k = 0; k < SUBFRAMES; k++) { transcodingParam.loFiltGain[k] = lpcGains[k]; } /* Store the gains for multiple encoding. */ memcpy(ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains, SUBFRAMES * sizeof(double)); WebRtcIsac_EncodeLpcGainUb(lpcGains, &ISACencUB_obj->bitstr_obj, ISACencUB_obj->SaveEnc_obj.lpcGainIndex); for (k = 0; k < SUBFRAMES; k++) { percepFilterParams[k * (UB_LPC_ORDER + 1)] = lpcGains[k]; } /* perceptual pre-filtering (using normalized lattice filter) */ /* low-band filtering */ WebRtcIsac_NormLatticeFilterMa(UB_LPC_ORDER, ISACencUB_obj->maskfiltstr_obj.PreStateLoF, ISACencUB_obj->maskfiltstr_obj.PreStateLoG, LP, percepFilterParams, LPw); /* Get the correct value for the payload limit and calculate the number of bytes left for coding the spectrum. It is a 30ms frame Subract 3 because termination process may add 3 bytes */ payloadLimitBytes = ISACencUB_obj->maxPayloadSizeBytes - ISACencUB_obj->numBytesUsed - 3; bytesLeftSpecCoding = payloadLimitBytes - ISACencUB_obj->bitstr_obj.stream_index; memset(HPw, 0, sizeof(HPw)); /* Transform */ WebRtcIsac_Time2Spec(transform_tables, LPw, HPw, fre, fim, &ISACencUB_obj->fftstr_obj); /* Store FFT coefficients for multiple encoding. */ memcpy(ISACencUB_obj->SaveEnc_obj.realFFT, fre, sizeof(ISACencUB_obj->SaveEnc_obj.realFFT)); memcpy(ISACencUB_obj->SaveEnc_obj.imagFFT, fim, sizeof(ISACencUB_obj->SaveEnc_obj.imagFFT)); /* Save the bit-stream object at this point for FEC. */ memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj, &ISACencUB_obj->bitstr_obj, sizeof(Bitstr)); /* Quantization and loss-less coding */ /* The 4th parameter to this function is pitch-gain, which is only used * when encoding 0-8 kHz band, and irrelevant in this function, therefore, * we insert zero here. */ err = WebRtcIsac_EncodeSpec(fre, fim, kAveragePitchGain, kIsacUpperBand12, &ISACencUB_obj->bitstr_obj); if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { /* There has been an error but it was not too large payload (we can cure too large payload) */ return err; } if ((ISACencUB_obj->bitstr_obj.stream_index > payloadLimitBytes) || (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { err = LimitPayloadUb(ISACencUB_obj, payloadLimitBytes, bytesLeftSpecCoding, &transcodingParam, fre, fim, lpcGains, kIsacUpperBand12, err); } if (err < 0) { return err; } /* Complete arithmetic coding. */ return WebRtcIsac_EncTerminate(&ISACencUB_obj->bitstr_obj); } /* This function is used to create a new bit-stream with new BWE. The same data as previously encoded with the function WebRtcIsac_Encoder(). The data needed is taken from the structure, where it was stored when calling the encoder. */ int WebRtcIsac_EncodeStoredDataLb(const IsacSaveEncoderData* ISACSavedEnc_obj, Bitstr* ISACBitStr_obj, int BWnumber, float scale) { int ii; int status; int BWno = BWnumber; const uint16_t* WebRtcIsac_kQPitchGainCdf_ptr[1]; const uint16_t** cdf; double tmpLPCcoeffs_lo[(ORDERLO + 1)*SUBFRAMES * 2]; double tmpLPCcoeffs_hi[(ORDERHI + 1)*SUBFRAMES * 2]; int tmpLPCindex_g[12 * 2]; int16_t tmp_fre[FRAMESAMPLES], tmp_fim[FRAMESAMPLES]; const int kModel = 0; /* Sanity Check - possible values for BWnumber is 0 - 23. */ if ((BWnumber < 0) || (BWnumber > 23)) { return -ISAC_RANGE_ERROR_BW_ESTIMATOR; } /* Reset bit-stream. */ WebRtcIsac_ResetBitstream(ISACBitStr_obj); /* Encode frame length */ status = WebRtcIsac_EncodeFrameLen(ISACSavedEnc_obj->framelength, ISACBitStr_obj); if (status < 0) { /* Wrong frame size. */ return status; } /* Transcoding */ if ((scale > 0.0) && (scale < 1.0)) { /* Compensate LPC gain. */ for (ii = 0; ii < ((ORDERLO + 1)* SUBFRAMES * (1 + ISACSavedEnc_obj->startIdx)); ii++) { tmpLPCcoeffs_lo[ii] = scale * ISACSavedEnc_obj->LPCcoeffs_lo[ii]; } for (ii = 0; ii < ((ORDERHI + 1) * SUBFRAMES * (1 + ISACSavedEnc_obj->startIdx)); ii++) { tmpLPCcoeffs_hi[ii] = scale * ISACSavedEnc_obj->LPCcoeffs_hi[ii]; } /* Scale DFT. */ for (ii = 0; ii < (FRAMESAMPLES_HALF * (1 + ISACSavedEnc_obj->startIdx)); ii++) { tmp_fre[ii] = (int16_t)((scale) * (float)ISACSavedEnc_obj->fre[ii]); tmp_fim[ii] = (int16_t)((scale) * (float)ISACSavedEnc_obj->fim[ii]); } } else { for (ii = 0; ii < (KLT_ORDER_GAIN * (1 + ISACSavedEnc_obj->startIdx)); ii++) { tmpLPCindex_g[ii] = ISACSavedEnc_obj->LPCindex_g[ii]; } for (ii = 0; ii < (FRAMESAMPLES_HALF * (1 + ISACSavedEnc_obj->startIdx)); ii++) { tmp_fre[ii] = ISACSavedEnc_obj->fre[ii]; tmp_fim[ii] = ISACSavedEnc_obj->fim[ii]; } } /* Encode bandwidth estimate. */ WebRtcIsac_EncodeReceiveBw(&BWno, ISACBitStr_obj); /* Loop over number of 30 msec */ for (ii = 0; ii <= ISACSavedEnc_obj->startIdx; ii++) { /* Encode pitch gains. */ *WebRtcIsac_kQPitchGainCdf_ptr = WebRtcIsac_kQPitchGainCdf; WebRtcIsac_EncHistMulti(ISACBitStr_obj, &ISACSavedEnc_obj->pitchGain_index[ii], WebRtcIsac_kQPitchGainCdf_ptr, 1); /* Entropy coding of quantization pitch lags */ /* Voicing classification. */ if (ISACSavedEnc_obj->meanGain[ii] < 0.2) { cdf = WebRtcIsac_kQPitchLagCdfPtrLo; } else if (ISACSavedEnc_obj->meanGain[ii] < 0.4) { cdf = WebRtcIsac_kQPitchLagCdfPtrMid; } else { cdf = WebRtcIsac_kQPitchLagCdfPtrHi; } WebRtcIsac_EncHistMulti(ISACBitStr_obj, &ISACSavedEnc_obj->pitchIndex[PITCH_SUBFRAMES * ii], cdf, PITCH_SUBFRAMES); /* LPC */ /* Only one model exists. The entropy coding is done only for backward * compatibility. */ WebRtcIsac_EncHistMulti(ISACBitStr_obj, &kModel, WebRtcIsac_kQKltModelCdfPtr, 1); /* Entropy coding of quantization indices - LPC shape only. */ WebRtcIsac_EncHistMulti(ISACBitStr_obj, &ISACSavedEnc_obj->LPCindex_s[KLT_ORDER_SHAPE * ii], WebRtcIsac_kQKltCdfPtrShape, KLT_ORDER_SHAPE); /* If transcoding, get new LPC gain indices */ if (scale < 1.0) { WebRtcIsac_TranscodeLPCCoef( &tmpLPCcoeffs_lo[(ORDERLO + 1) * SUBFRAMES * ii], &tmpLPCcoeffs_hi[(ORDERHI + 1)*SUBFRAMES * ii], &tmpLPCindex_g[KLT_ORDER_GAIN * ii]); } /* Entropy coding of quantization indices - LPC gain. */ WebRtcIsac_EncHistMulti(ISACBitStr_obj, &tmpLPCindex_g[KLT_ORDER_GAIN * ii], WebRtcIsac_kQKltCdfPtrGain, KLT_ORDER_GAIN); /* Quantization and loss-less coding. */ status = WebRtcIsac_EncodeSpec(&tmp_fre[ii * FRAMESAMPLES_HALF], &tmp_fim[ii * FRAMESAMPLES_HALF], ISACSavedEnc_obj->AvgPitchGain[ii], kIsacLowerBand, ISACBitStr_obj); if (status < 0) { return status; } } /* Complete arithmetic coding. */ return WebRtcIsac_EncTerminate(ISACBitStr_obj); } int WebRtcIsac_EncodeStoredDataUb( const ISACUBSaveEncDataStruct* ISACSavedEnc_obj, Bitstr* bitStream, int32_t jitterInfo, float scale, enum ISACBandwidth bandwidth) { int n; int err; double lpcGain[SUBFRAMES]; int16_t realFFT[FRAMESAMPLES_HALF]; int16_t imagFFT[FRAMESAMPLES_HALF]; const uint16_t** shape_cdf; int shape_len; const int16_t kAveragePitchGain = 0.0; enum ISACBand band; /* Reset bitstream. */ WebRtcIsac_ResetBitstream(bitStream); /* Encode jitter index. */ WebRtcIsac_EncodeJitterInfo(jitterInfo, bitStream); err = WebRtcIsac_EncodeBandwidth(bandwidth, bitStream); if (err < 0) { return err; } /* Encode LPC-shape. */ if (bandwidth == isac12kHz) { shape_cdf = WebRtcIsac_kLpcShapeCdfMatUb12; shape_len = UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME; band = kIsacUpperBand12; } else { shape_cdf = WebRtcIsac_kLpcShapeCdfMatUb16; shape_len = UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME; band = kIsacUpperBand16; } WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->indexLPCShape, shape_cdf, shape_len); if ((scale <= 0.0) || (scale >= 1.0)) { /* We only consider scales between zero and one. */ WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->lpcGainIndex, WebRtcIsac_kLpcGainCdfMat, UB_LPC_GAIN_DIM); if (bandwidth == isac16kHz) { /* Store gain indices of the second half. */ WebRtcIsac_EncHistMulti(bitStream, &ISACSavedEnc_obj->lpcGainIndex[SUBFRAMES], WebRtcIsac_kLpcGainCdfMat, UB_LPC_GAIN_DIM); } /* Store FFT coefficients. */ err = WebRtcIsac_EncodeSpec(ISACSavedEnc_obj->realFFT, ISACSavedEnc_obj->imagFFT, kAveragePitchGain, band, bitStream); } else { /* Scale LPC gain and FFT coefficients. */ for (n = 0; n < SUBFRAMES; n++) { lpcGain[n] = scale * ISACSavedEnc_obj->lpcGain[n]; } /* Store LPC gains. */ WebRtcIsac_StoreLpcGainUb(lpcGain, bitStream); if (bandwidth == isac16kHz) { /* Scale and code the gains of the second half of the frame, if 16kHz. */ for (n = 0; n < SUBFRAMES; n++) { lpcGain[n] = scale * ISACSavedEnc_obj->lpcGain[n + SUBFRAMES]; } WebRtcIsac_StoreLpcGainUb(lpcGain, bitStream); } for (n = 0; n < FRAMESAMPLES_HALF; n++) { realFFT[n] = (int16_t)(scale * (float)ISACSavedEnc_obj->realFFT[n] + 0.5f); imagFFT[n] = (int16_t)(scale * (float)ISACSavedEnc_obj->imagFFT[n] + 0.5f); } /* Store FFT coefficients. */ err = WebRtcIsac_EncodeSpec(realFFT, imagFFT, kAveragePitchGain, band, bitStream); } if (err < 0) { /* Error happened while encoding FFT coefficients. */ return err; } /* Complete arithmetic coding. */ return WebRtcIsac_EncTerminate(bitStream); } int16_t WebRtcIsac_GetRedPayloadUb( const ISACUBSaveEncDataStruct* ISACSavedEncObj, Bitstr* bitStreamObj, enum ISACBandwidth bandwidth) { int n; int16_t status; int16_t realFFT[FRAMESAMPLES_HALF]; int16_t imagFFT[FRAMESAMPLES_HALF]; enum ISACBand band; const int16_t kAveragePitchGain = 0.0; /* Store bit-stream object. */ memcpy(bitStreamObj, &ISACSavedEncObj->bitStreamObj, sizeof(Bitstr)); /* Scale FFT coefficients. */ for (n = 0; n < FRAMESAMPLES_HALF; n++) { realFFT[n] = (int16_t)((float)ISACSavedEncObj->realFFT[n] * RCU_TRANSCODING_SCALE_UB + 0.5); imagFFT[n] = (int16_t)((float)ISACSavedEncObj->imagFFT[n] * RCU_TRANSCODING_SCALE_UB + 0.5); } band = (bandwidth == isac12kHz) ? kIsacUpperBand12 : kIsacUpperBand16; status = WebRtcIsac_EncodeSpec(realFFT, imagFFT, kAveragePitchGain, band, bitStreamObj); if (status < 0) { return status; } else { /* Terminate entropy coding */ return WebRtcIsac_EncTerminate(bitStreamObj); } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.c0000664000175000017500000004265514475643423032001 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * code_LPC_UB.c * * This file contains definition of functions used to * encode LPC parameters (Shape & gain) of the upper band. * */ #include #include #include #include "modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h" #include "modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h" #include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h" #include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h" #include "modules/audio_coding/codecs/isac/main/source/settings.h" /****************************************************************************** * WebRtcIsac_RemoveLarMean() * * Remove the means from LAR coefficients. * * Input: * -lar : pointer to lar vectors. LAR vectors are * concatenated. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -lar : pointer to mean-removed LAR:s. * * */ int16_t WebRtcIsac_RemoveLarMean( double* lar, int16_t bandwidth) { int16_t coeffCntr; int16_t vecCntr; int16_t numVec; const double* meanLAR; switch(bandwidth) { case isac12kHz: { numVec = UB_LPC_VEC_PER_FRAME; meanLAR = WebRtcIsac_kMeanLarUb12; break; } case isac16kHz: { numVec = UB16_LPC_VEC_PER_FRAME; meanLAR = WebRtcIsac_kMeanLarUb16; break; } default: return -1; } for(vecCntr = 0; vecCntr < numVec; vecCntr++) { for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) { // REMOVE MEAN *lar++ -= meanLAR[coeffCntr]; } } return 0; } /****************************************************************************** * WebRtcIsac_DecorrelateIntraVec() * * Remove the correlation amonge the components of LAR vectors. If LAR vectors * of one frame are put in a matrix where each column is a LAR vector of a * sub-frame, then this is equivalent to multiplying the LAR matrix with * a decorrelting mtrix from left. * * Input: * -inLar : pointer to mean-removed LAR vecrtors. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -out : decorrelated LAR vectors. */ int16_t WebRtcIsac_DecorrelateIntraVec( const double* data, double* out, int16_t bandwidth) { const double* ptrData; const double* ptrRow; int16_t rowCntr; int16_t colCntr; int16_t larVecCntr; int16_t numVec; const double* decorrMat; switch(bandwidth) { case isac12kHz: { decorrMat = &WebRtcIsac_kIntraVecDecorrMatUb12[0][0]; numVec = UB_LPC_VEC_PER_FRAME; break; } case isac16kHz: { decorrMat = &WebRtcIsac_kIintraVecDecorrMatUb16[0][0]; numVec = UB16_LPC_VEC_PER_FRAME; break; } default: return -1; } // // decorrMat * data // // data is assumed to contain 'numVec' of LAR // vectors (mean removed) each of dimension 'UB_LPC_ORDER' // concatenated one after the other. // ptrData = data; for(larVecCntr = 0; larVecCntr < numVec; larVecCntr++) { for(rowCntr = 0; rowCntr < UB_LPC_ORDER; rowCntr++) { ptrRow = &decorrMat[rowCntr * UB_LPC_ORDER]; *out = 0; for(colCntr = 0; colCntr < UB_LPC_ORDER; colCntr++) { *out += ptrData[colCntr] * ptrRow[colCntr]; } out++; } ptrData += UB_LPC_ORDER; } return 0; } /****************************************************************************** * WebRtcIsac_DecorrelateInterVec() * * Remover the correlation among mean-removed LAR vectors. If LAR vectors * of one frame are put in a matrix where each column is a LAR vector of a * sub-frame, then this is equivalent to multiplying the LAR matrix with * a decorrelting mtrix from right. * * Input: * -data : pointer to matrix of LAR vectors. The matrix * is stored column-wise. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -out : decorrelated LAR vectors. */ int16_t WebRtcIsac_DecorrelateInterVec( const double* data, double* out, int16_t bandwidth) { int16_t coeffCntr; int16_t rowCntr; int16_t colCntr; const double* decorrMat; int16_t interVecDim; switch(bandwidth) { case isac12kHz: { decorrMat = &WebRtcIsac_kInterVecDecorrMatUb12[0][0]; interVecDim = UB_LPC_VEC_PER_FRAME; break; } case isac16kHz: { decorrMat = &WebRtcIsac_kInterVecDecorrMatUb16[0][0]; interVecDim = UB16_LPC_VEC_PER_FRAME; break; } default: return -1; } // // data * decorrMat // // data is of size 'interVecDim' * 'UB_LPC_ORDER' // That is 'interVecDim' of LAR vectors (mean removed) // in columns each of dimension 'UB_LPC_ORDER'. // matrix is stored column-wise. // for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) { for(colCntr = 0; colCntr < interVecDim; colCntr++) { out[coeffCntr + colCntr * UB_LPC_ORDER] = 0; for(rowCntr = 0; rowCntr < interVecDim; rowCntr++) { out[coeffCntr + colCntr * UB_LPC_ORDER] += data[coeffCntr + rowCntr * UB_LPC_ORDER] * decorrMat[rowCntr * interVecDim + colCntr]; } } } return 0; } /****************************************************************************** * WebRtcIsac_QuantizeUncorrLar() * * Quantize the uncorrelated parameters. * * Input: * -data : uncorrelated LAR vectors. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -data : quantized version of the input. * -idx : pointer to quantization indices. */ double WebRtcIsac_QuantizeUncorrLar( double* data, int* recIdx, int16_t bandwidth) { int16_t cntr; int32_t idx; int16_t interVecDim; const double* leftRecPoint; double quantizationStepSize; const int16_t* numQuantCell; switch(bandwidth) { case isac12kHz: { leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb12; quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb12; numQuantCell = WebRtcIsac_kLpcShapeNumRecPointUb12; interVecDim = UB_LPC_VEC_PER_FRAME; break; } case isac16kHz: { leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb16; quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb16; numQuantCell = WebRtcIsac_kLpcShapeNumRecPointUb16; interVecDim = UB16_LPC_VEC_PER_FRAME; break; } default: return -1; } // // Quantize the parametrs. // for(cntr = 0; cntr < UB_LPC_ORDER * interVecDim; cntr++) { idx = (int32_t)floor((*data - leftRecPoint[cntr]) / quantizationStepSize + 0.5); if(idx < 0) { idx = 0; } else if(idx >= numQuantCell[cntr]) { idx = numQuantCell[cntr] - 1; } *data++ = leftRecPoint[cntr] + idx * quantizationStepSize; *recIdx++ = idx; } return 0; } /****************************************************************************** * WebRtcIsac_DequantizeLpcParam() * * Get the quantized value of uncorrelated LARs given the quantization indices. * * Input: * -idx : pointer to quantiztion indices. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -out : pointer to quantized values. */ int16_t WebRtcIsac_DequantizeLpcParam( const int* idx, double* out, int16_t bandwidth) { int16_t cntr; int16_t interVecDim; const double* leftRecPoint; double quantizationStepSize; switch(bandwidth) { case isac12kHz: { leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb12; quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb12; interVecDim = UB_LPC_VEC_PER_FRAME; break; } case isac16kHz: { leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb16; quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb16; interVecDim = UB16_LPC_VEC_PER_FRAME; break; } default: return -1; } // // Dequantize given the quantization indices // for(cntr = 0; cntr < UB_LPC_ORDER * interVecDim; cntr++) { *out++ = leftRecPoint[cntr] + *idx++ * quantizationStepSize; } return 0; } /****************************************************************************** * WebRtcIsac_CorrelateIntraVec() * * This is the inverse of WebRtcIsac_DecorrelateIntraVec(). * * Input: * -data : uncorrelated parameters. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -out : correlated parametrs. */ int16_t WebRtcIsac_CorrelateIntraVec( const double* data, double* out, int16_t bandwidth) { int16_t vecCntr; int16_t rowCntr; int16_t colCntr; int16_t numVec; const double* ptrData; const double* intraVecDecorrMat; switch(bandwidth) { case isac12kHz: { numVec = UB_LPC_VEC_PER_FRAME; intraVecDecorrMat = &WebRtcIsac_kIntraVecDecorrMatUb12[0][0]; break; } case isac16kHz: { numVec = UB16_LPC_VEC_PER_FRAME; intraVecDecorrMat = &WebRtcIsac_kIintraVecDecorrMatUb16[0][0]; break; } default: return -1; } ptrData = data; for(vecCntr = 0; vecCntr < numVec; vecCntr++) { for(colCntr = 0; colCntr < UB_LPC_ORDER; colCntr++) { *out = 0; for(rowCntr = 0; rowCntr < UB_LPC_ORDER; rowCntr++) { *out += ptrData[rowCntr] * intraVecDecorrMat[rowCntr * UB_LPC_ORDER + colCntr]; } out++; } ptrData += UB_LPC_ORDER; } return 0; } /****************************************************************************** * WebRtcIsac_CorrelateInterVec() * * This is the inverse of WebRtcIsac_DecorrelateInterVec(). * * Input: * -data * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -out : correlated parametrs. */ int16_t WebRtcIsac_CorrelateInterVec( const double* data, double* out, int16_t bandwidth) { int16_t coeffCntr; int16_t rowCntr; int16_t colCntr; int16_t interVecDim; double myVec[UB16_LPC_VEC_PER_FRAME] = {0.0}; const double* interVecDecorrMat; switch(bandwidth) { case isac12kHz: { interVecDim = UB_LPC_VEC_PER_FRAME; interVecDecorrMat = &WebRtcIsac_kInterVecDecorrMatUb12[0][0]; break; } case isac16kHz: { interVecDim = UB16_LPC_VEC_PER_FRAME; interVecDecorrMat = &WebRtcIsac_kInterVecDecorrMatUb16[0][0]; break; } default: return -1; } for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) { for(rowCntr = 0; rowCntr < interVecDim; rowCntr++) { myVec[rowCntr] = 0; for(colCntr = 0; colCntr < interVecDim; colCntr++) { myVec[rowCntr] += data[coeffCntr + colCntr * UB_LPC_ORDER] * //*ptrData * interVecDecorrMat[rowCntr * interVecDim + colCntr]; //ptrData += UB_LPC_ORDER; } } for(rowCntr = 0; rowCntr < interVecDim; rowCntr++) { out[coeffCntr + rowCntr * UB_LPC_ORDER] = myVec[rowCntr]; } } return 0; } /****************************************************************************** * WebRtcIsac_AddLarMean() * * This is the inverse of WebRtcIsac_RemoveLarMean() * * Input: * -data : pointer to mean-removed LAR:s. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -data : pointer to LARs. */ int16_t WebRtcIsac_AddLarMean( double* data, int16_t bandwidth) { int16_t coeffCntr; int16_t vecCntr; int16_t numVec; const double* meanLAR; switch(bandwidth) { case isac12kHz: { numVec = UB_LPC_VEC_PER_FRAME; meanLAR = WebRtcIsac_kMeanLarUb12; break; } case isac16kHz: { numVec = UB16_LPC_VEC_PER_FRAME; meanLAR = WebRtcIsac_kMeanLarUb16; break; } default: return -1; } for(vecCntr = 0; vecCntr < numVec; vecCntr++) { for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) { *data++ += meanLAR[coeffCntr]; } } return 0; } /****************************************************************************** * WebRtcIsac_ToLogDomainRemoveMean() * * Transform the LPC gain to log domain then remove the mean value. * * Input: * -lpcGain : pointer to LPC Gain, expecting 6 LPC gains * * Output: * -lpcGain : mean-removed in log domain. */ int16_t WebRtcIsac_ToLogDomainRemoveMean( double* data) { int16_t coeffCntr; for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++) { data[coeffCntr] = log(data[coeffCntr]) - WebRtcIsac_kMeanLpcGain; } return 0; } /****************************************************************************** * WebRtcIsac_DecorrelateLPGain() * * Decorrelate LPC gains. There are 6 LPC Gains per frame. This is like * multiplying gain vector with decorrelating matrix. * * Input: * -data : LPC gain in log-domain with mean removed. * * Output: * -out : decorrelated parameters. */ int16_t WebRtcIsac_DecorrelateLPGain( const double* data, double* out) { int16_t rowCntr; int16_t colCntr; for(colCntr = 0; colCntr < UB_LPC_GAIN_DIM; colCntr++) { *out = 0; for(rowCntr = 0; rowCntr < UB_LPC_GAIN_DIM; rowCntr++) { *out += data[rowCntr] * WebRtcIsac_kLpcGainDecorrMat[rowCntr][colCntr]; } out++; } return 0; } /****************************************************************************** * WebRtcIsac_QuantizeLpcGain() * * Quantize the decorrelated log-domain gains. * * Input: * -lpcGain : uncorrelated LPC gains. * * Output: * -idx : quantization indices * -lpcGain : quantized value of the inpt. */ double WebRtcIsac_QuantizeLpcGain( double* data, int* idx) { int16_t coeffCntr; for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++) { *idx = (int)floor((*data - WebRtcIsac_kLeftRecPointLpcGain[coeffCntr]) / WebRtcIsac_kQSizeLpcGain + 0.5); if(*idx < 0) { *idx = 0; } else if(*idx >= WebRtcIsac_kNumQCellLpcGain[coeffCntr]) { *idx = WebRtcIsac_kNumQCellLpcGain[coeffCntr] - 1; } *data = WebRtcIsac_kLeftRecPointLpcGain[coeffCntr] + *idx * WebRtcIsac_kQSizeLpcGain; data++; idx++; } return 0; } /****************************************************************************** * WebRtcIsac_DequantizeLpcGain() * * Get the quantized values given the quantization indices. * * Input: * -idx : pointer to quantization indices. * * Output: * -lpcGains : quantized values of the given parametes. */ int16_t WebRtcIsac_DequantizeLpcGain( const int* idx, double* out) { int16_t coeffCntr; for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++) { *out = WebRtcIsac_kLeftRecPointLpcGain[coeffCntr] + *idx * WebRtcIsac_kQSizeLpcGain; out++; idx++; } return 0; } /****************************************************************************** * WebRtcIsac_CorrelateLpcGain() * * This is the inverse of WebRtcIsac_DecorrelateLPGain(). * * Input: * -data : decorrelated parameters. * * Output: * -out : correlated parameters. */ int16_t WebRtcIsac_CorrelateLpcGain( const double* data, double* out) { int16_t rowCntr; int16_t colCntr; for(rowCntr = 0; rowCntr < UB_LPC_GAIN_DIM; rowCntr++) { *out = 0; for(colCntr = 0; colCntr < UB_LPC_GAIN_DIM; colCntr++) { *out += WebRtcIsac_kLpcGainDecorrMat[rowCntr][colCntr] * data[colCntr]; } out++; } return 0; } /****************************************************************************** * WebRtcIsac_AddMeanToLinearDomain() * * This is the inverse of WebRtcIsac_ToLogDomainRemoveMean(). * * Input: * -lpcGain : LPC gain in log-domain & mean removed * * Output: * -lpcGain : LPC gain in normal domain. */ int16_t WebRtcIsac_AddMeanToLinearDomain( double* lpcGains) { int16_t coeffCntr; for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++) { lpcGains[coeffCntr] = exp(lpcGains[coeffCntr] + WebRtcIsac_kMeanLpcGain); } return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h0000664000175000017500000002063414475643423031777 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * encode_lpc_swb.h * * This file contains declaration of functions used to * encode LPC parameters (Shape & gain) of the upper band. * */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_ #include "modules/audio_coding/codecs/isac/main/source/settings.h" #include "modules/audio_coding/codecs/isac/main/source/structs.h" /****************************************************************************** * WebRtcIsac_RemoveLarMean() * * Remove the means from LAR coefficients. * * Input: * -lar : pointer to lar vectors. LAR vectors are * concatenated. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -lar : pointer to mean-removed LAR:s. * * */ int16_t WebRtcIsac_RemoveLarMean(double* lar, int16_t bandwidth); /****************************************************************************** * WebRtcIsac_DecorrelateIntraVec() * * Remove the correlation amonge the components of LAR vectors. If LAR vectors * of one frame are put in a matrix where each column is a LAR vector of a * sub-frame, then this is equivalent to multiplying the LAR matrix with * a decorrelting mtrix from left. * * Input: * -inLar : pointer to mean-removed LAR vecrtors. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -out : decorrelated LAR vectors. */ int16_t WebRtcIsac_DecorrelateIntraVec(const double* inLAR, double* out, int16_t bandwidth); /****************************************************************************** * WebRtcIsac_DecorrelateInterVec() * * Remover the correlation among mean-removed LAR vectors. If LAR vectors * of one frame are put in a matrix where each column is a LAR vector of a * sub-frame, then this is equivalent to multiplying the LAR matrix with * a decorrelting mtrix from right. * * Input: * -data : pointer to matrix of LAR vectors. The matrix * is stored column-wise. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -out : decorrelated LAR vectors. */ int16_t WebRtcIsac_DecorrelateInterVec(const double* data, double* out, int16_t bandwidth); /****************************************************************************** * WebRtcIsac_QuantizeUncorrLar() * * Quantize the uncorrelated parameters. * * Input: * -data : uncorrelated LAR vectors. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -data : quantized version of the input. * -idx : pointer to quantization indices. */ double WebRtcIsac_QuantizeUncorrLar(double* data, int* idx, int16_t bandwidth); /****************************************************************************** * WebRtcIsac_CorrelateIntraVec() * * This is the inverse of WebRtcIsac_DecorrelateIntraVec(). * * Input: * -data : uncorrelated parameters. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -out : correlated parametrs. */ int16_t WebRtcIsac_CorrelateIntraVec(const double* data, double* out, int16_t bandwidth); /****************************************************************************** * WebRtcIsac_CorrelateInterVec() * * This is the inverse of WebRtcIsac_DecorrelateInterVec(). * * Input: * -data * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -out : correlated parametrs. */ int16_t WebRtcIsac_CorrelateInterVec(const double* data, double* out, int16_t bandwidth); /****************************************************************************** * WebRtcIsac_AddLarMean() * * This is the inverse of WebRtcIsac_RemoveLarMean() * * Input: * -data : pointer to mean-removed LAR:s. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -data : pointer to LARs. */ int16_t WebRtcIsac_AddLarMean(double* data, int16_t bandwidth); /****************************************************************************** * WebRtcIsac_DequantizeLpcParam() * * Get the quantized value of uncorrelated LARs given the quantization indices. * * Input: * -idx : pointer to quantiztion indices. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -out : pointer to quantized values. */ int16_t WebRtcIsac_DequantizeLpcParam(const int* idx, double* out, int16_t bandwidth); /****************************************************************************** * WebRtcIsac_ToLogDomainRemoveMean() * * Transform the LPC gain to log domain then remove the mean value. * * Input: * -lpcGain : pointer to LPC Gain, expecting 6 LPC gains * * Output: * -lpcGain : mean-removed in log domain. */ int16_t WebRtcIsac_ToLogDomainRemoveMean(double* lpGains); /****************************************************************************** * WebRtcIsac_DecorrelateLPGain() * * Decorrelate LPC gains. There are 6 LPC Gains per frame. This is like * multiplying gain vector with decorrelating matrix. * * Input: * -data : LPC gain in log-domain with mean removed. * * Output: * -out : decorrelated parameters. */ int16_t WebRtcIsac_DecorrelateLPGain(const double* data, double* out); /****************************************************************************** * WebRtcIsac_QuantizeLpcGain() * * Quantize the decorrelated log-domain gains. * * Input: * -lpcGain : uncorrelated LPC gains. * * Output: * -idx : quantization indices * -lpcGain : quantized value of the inpt. */ double WebRtcIsac_QuantizeLpcGain(double* lpGains, int* idx); /****************************************************************************** * WebRtcIsac_DequantizeLpcGain() * * Get the quantized values given the quantization indices. * * Input: * -idx : pointer to quantization indices. * * Output: * -lpcGains : quantized values of the given parametes. */ int16_t WebRtcIsac_DequantizeLpcGain(const int* idx, double* lpGains); /****************************************************************************** * WebRtcIsac_CorrelateLpcGain() * * This is the inverse of WebRtcIsac_DecorrelateLPGain(). * * Input: * -data : decorrelated parameters. * * Output: * -out : correlated parameters. */ int16_t WebRtcIsac_CorrelateLpcGain(const double* data, double* out); /****************************************************************************** * WebRtcIsac_AddMeanToLinearDomain() * * This is the inverse of WebRtcIsac_ToLogDomainRemoveMean(). * * Input: * -lpcGain : LPC gain in log-domain & mean removed * * Output: * -lpcGain : LPC gain in normal domain. */ int16_t WebRtcIsac_AddMeanToLinearDomain(double* lpcGains); #endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/entropy_coding.c0000664000175000017500000017331514475643423032054 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * entropy_coding.c * * This header file defines all of the functions used to arithmetically * encode the iSAC bistream * */ #include "common_audio/signal_processing/include/signal_processing_library.h" #include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h" #include "modules/audio_coding/codecs/isac/main/source/settings.h" #include "modules/audio_coding/codecs/isac/main/source/arith_routines.h" #include "modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h" #include "modules/audio_coding/codecs/isac/main/source/lpc_tables.h" #include "modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h" #include "modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h" #include "modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h" #include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h" #include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h" #include "modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h" #include "modules/audio_coding/codecs/isac/main/source/os_specific_inline.h" #include #include static const uint16_t kLpcVecPerSegmentUb12 = 5; static const uint16_t kLpcVecPerSegmentUb16 = 4; /* CDF array for encoder bandwidth (12 vs 16 kHz) indicator. */ static const uint16_t kOneBitEqualProbCdf[3] = { 0, 32768, 65535 }; /* Pointer to cdf array for encoder bandwidth (12 vs 16 kHz) indicator. */ static const uint16_t* const kOneBitEqualProbCdf_ptr[1] = { kOneBitEqualProbCdf }; /* * Initial cdf index for decoder of encoded bandwidth * (12 vs 16 kHz) indicator. */ static const uint16_t kOneBitEqualProbInitIndex[1] = { 1 }; static const int kIsSWB12 = 1; /* compute correlation from power spectrum */ static void FindCorrelation(int32_t* PSpecQ12, int32_t* CorrQ7) { int32_t summ[FRAMESAMPLES / 8]; int32_t diff[FRAMESAMPLES / 8]; const int16_t* CS_ptrQ9; int32_t sum; int k, n; for (k = 0; k < FRAMESAMPLES / 8; k++) { summ[k] = (PSpecQ12[k] + PSpecQ12[FRAMESAMPLES_QUARTER - 1 - k] + 16) >> 5; diff[k] = (PSpecQ12[k] - PSpecQ12[FRAMESAMPLES_QUARTER - 1 - k] + 16) >> 5; } sum = 2; for (n = 0; n < FRAMESAMPLES / 8; n++) { sum += summ[n]; } CorrQ7[0] = sum; for (k = 0; k < AR_ORDER; k += 2) { sum = 0; CS_ptrQ9 = WebRtcIsac_kCos[k]; for (n = 0; n < FRAMESAMPLES / 8; n++) sum += (CS_ptrQ9[n] * diff[n] + 256) >> 9; CorrQ7[k + 1] = sum; } for (k = 1; k < AR_ORDER; k += 2) { sum = 0; CS_ptrQ9 = WebRtcIsac_kCos[k]; for (n = 0; n < FRAMESAMPLES / 8; n++) sum += (CS_ptrQ9[n] * summ[n] + 256) >> 9; CorrQ7[k + 1] = sum; } } /* compute inverse AR power spectrum */ /* Changed to the function used in iSAC FIX for compatibility reasons */ static void FindInvArSpec(const int16_t* ARCoefQ12, const int32_t gainQ10, int32_t* CurveQ16) { int32_t CorrQ11[AR_ORDER + 1]; int64_t sum, tmpGain; int32_t diffQ16[FRAMESAMPLES / 8]; const int16_t* CS_ptrQ9; int k, n; int16_t round, shftVal = 0, sh; sum = 0; for (n = 0; n < AR_ORDER + 1; n++) { sum += WEBRTC_SPL_MUL(ARCoefQ12[n], ARCoefQ12[n]); /* Q24 */ } sum = ((sum >> 6) * 65 + 32768) >> 16; /* Q8 */ CorrQ11[0] = (sum * gainQ10 + 256) >> 9; /* To avoid overflow, we shift down gainQ10 if it is large. * We will not lose any precision */ if (gainQ10 > 400000) { tmpGain = gainQ10 >> 3; round = 32; shftVal = 6; } else { tmpGain = gainQ10; round = 256; shftVal = 9; } for (k = 1; k < AR_ORDER + 1; k++) { sum = 16384; for (n = k; n < AR_ORDER + 1; n++) sum += WEBRTC_SPL_MUL(ARCoefQ12[n - k], ARCoefQ12[n]); /* Q24 */ sum >>= 15; CorrQ11[k] = (sum * tmpGain + round) >> shftVal; } sum = CorrQ11[0] << 7; for (n = 0; n < FRAMESAMPLES / 8; n++) { CurveQ16[n] = sum; } for (k = 1; k < AR_ORDER; k += 2) { for (n = 0; n < FRAMESAMPLES / 8; n++) { CurveQ16[n] += (WebRtcIsac_kCos[k][n] * CorrQ11[k + 1] + 2) >> 2; } } CS_ptrQ9 = WebRtcIsac_kCos[0]; /* If CorrQ11[1] too large we avoid getting overflow in the * calculation by shifting */ sh = WebRtcSpl_NormW32(CorrQ11[1]); if (CorrQ11[1] == 0) { /* Use next correlation */ sh = WebRtcSpl_NormW32(CorrQ11[2]); } if (sh < 9) { shftVal = 9 - sh; } else { shftVal = 0; } for (n = 0; n < FRAMESAMPLES / 8; n++) { diffQ16[n] = (CS_ptrQ9[n] * (CorrQ11[1] >> shftVal) + 2) >> 2; } for (k = 2; k < AR_ORDER; k += 2) { CS_ptrQ9 = WebRtcIsac_kCos[k]; for (n = 0; n < FRAMESAMPLES / 8; n++) { diffQ16[n] += (CS_ptrQ9[n] * (CorrQ11[k + 1] >> shftVal) + 2) >> 2; } } for (k = 0; k < FRAMESAMPLES / 8; k++) { int32_t diff_q16_shifted = (int32_t)((uint32_t)(diffQ16[k]) << shftVal); CurveQ16[FRAMESAMPLES_QUARTER - 1 - k] = CurveQ16[k] - diff_q16_shifted; CurveQ16[k] += diff_q16_shifted; } } /* Generate array of dither samples in Q7. */ static void GenerateDitherQ7Lb(int16_t* bufQ7, uint32_t seed, int length, int16_t AvgPitchGain_Q12) { int k, shft; int16_t dither1_Q7, dither2_Q7, dither_gain_Q14; /* This threshold should be equal to that in decode_spec(). */ if (AvgPitchGain_Q12 < 614) { for (k = 0; k < length - 2; k += 3) { /* New random unsigned int. */ seed = (seed * 196314165) + 907633515; /* Fixed-point dither sample between -64 and 64 (Q7). */ /* dither = seed * 128 / 4294967295 */ dither1_Q7 = (int16_t)(((int32_t)(seed + 16777216)) >> 25); /* New random unsigned int. */ seed = (seed * 196314165) + 907633515; /* Fixed-point dither sample between -64 and 64. */ dither2_Q7 = (int16_t)(((int32_t)(seed + 16777216)) >> 25); shft = (seed >> 25) & 15; if (shft < 5) { bufQ7[k] = dither1_Q7; bufQ7[k + 1] = dither2_Q7; bufQ7[k + 2] = 0; } else if (shft < 10) { bufQ7[k] = dither1_Q7; bufQ7[k + 1] = 0; bufQ7[k + 2] = dither2_Q7; } else { bufQ7[k] = 0; bufQ7[k + 1] = dither1_Q7; bufQ7[k + 2] = dither2_Q7; } } } else { dither_gain_Q14 = (int16_t)(22528 - 10 * AvgPitchGain_Q12); /* Dither on half of the coefficients. */ for (k = 0; k < length - 1; k += 2) { /* New random unsigned int */ seed = (seed * 196314165) + 907633515; /* Fixed-point dither sample between -64 and 64. */ dither1_Q7 = (int16_t)(((int32_t)(seed + 16777216)) >> 25); /* Dither sample is placed in either even or odd index. */ shft = (seed >> 25) & 1; /* Either 0 or 1 */ bufQ7[k + shft] = (((dither_gain_Q14 * dither1_Q7) + 8192) >> 14); bufQ7[k + 1 - shft] = 0; } } } /****************************************************************************** * GenerateDitherQ7LbUB() * * generate array of dither samples in Q7 There are less zeros in dither * vector compared to GenerateDitherQ7Lb. * * A uniform random number generator with the range of [-64 64] is employed * but the generated dithers are scaled by 0.35, a heuristic scaling. * * Input: * -seed : the initial seed for the random number generator. * -length : the number of dither values to be generated. * * Output: * -bufQ7 : pointer to a buffer where dithers are written to. */ static void GenerateDitherQ7LbUB( int16_t* bufQ7, uint32_t seed, int length) { int k; for (k = 0; k < length; k++) { /* new random unsigned int */ seed = (seed * 196314165) + 907633515; /* Fixed-point dither sample between -64 and 64 (Q7). */ /* bufQ7 = seed * 128 / 4294967295 */ bufQ7[k] = (int16_t)(((int32_t)(seed + 16777216)) >> 25); /* Scale by 0.35. */ bufQ7[k] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(bufQ7[k], 2048, 13); } } /* * Function to decode the complex spectrum from the bit stream * returns the total number of bytes in the stream. */ int WebRtcIsac_DecodeSpec(Bitstr* streamdata, int16_t AvgPitchGain_Q12, enum ISACBand band, double* fr, double* fi) { int16_t DitherQ7[FRAMESAMPLES]; int16_t data[FRAMESAMPLES]; int32_t invARSpec2_Q16[FRAMESAMPLES_QUARTER]; uint16_t invARSpecQ8[FRAMESAMPLES_QUARTER]; int16_t ARCoefQ12[AR_ORDER + 1]; int16_t RCQ15[AR_ORDER]; int16_t gainQ10; int32_t gain2_Q10, res; int32_t in_sqrt; int32_t newRes; int k, len, i; int is_12khz = !kIsSWB12; int num_dft_coeff = FRAMESAMPLES; /* Create dither signal. */ if (band == kIsacLowerBand) { GenerateDitherQ7Lb(DitherQ7, streamdata->W_upper, FRAMESAMPLES, AvgPitchGain_Q12); } else { GenerateDitherQ7LbUB(DitherQ7, streamdata->W_upper, FRAMESAMPLES); if (band == kIsacUpperBand12) { is_12khz = kIsSWB12; num_dft_coeff = FRAMESAMPLES_HALF; } } /* Decode model parameters. */ if (WebRtcIsac_DecodeRc(streamdata, RCQ15) < 0) return -ISAC_RANGE_ERROR_DECODE_SPECTRUM; WebRtcSpl_ReflCoefToLpc(RCQ15, AR_ORDER, ARCoefQ12); if (WebRtcIsac_DecodeGain2(streamdata, &gain2_Q10) < 0) return -ISAC_RANGE_ERROR_DECODE_SPECTRUM; /* Compute inverse AR power spectrum. */ FindInvArSpec(ARCoefQ12, gain2_Q10, invARSpec2_Q16); /* Convert to magnitude spectrum, * by doing square-roots (modified from SPLIB). */ res = 1 << (WebRtcSpl_GetSizeInBits(invARSpec2_Q16[0]) >> 1); for (k = 0; k < FRAMESAMPLES_QUARTER; k++) { in_sqrt = invARSpec2_Q16[k]; i = 10; /* Negative values make no sense for a real sqrt-function. */ if (in_sqrt < 0) in_sqrt = -in_sqrt; newRes = (in_sqrt / res + res) >> 1; do { res = newRes; newRes = (in_sqrt / res + res) >> 1; } while (newRes != res && i-- > 0); invARSpecQ8[k] = (int16_t)newRes; } len = WebRtcIsac_DecLogisticMulti2(data, streamdata, invARSpecQ8, DitherQ7, num_dft_coeff, is_12khz); /* Arithmetic decoding of spectrum. */ if (len < 1) { return -ISAC_RANGE_ERROR_DECODE_SPECTRUM; } switch (band) { case kIsacLowerBand: { /* Scale down spectral samples with low SNR. */ int32_t p1; int32_t p2; if (AvgPitchGain_Q12 <= 614) { p1 = 30 << 10; p2 = 32768 + (33 << 16); } else { p1 = 36 << 10; p2 = 32768 + (40 << 16); } for (k = 0; k < FRAMESAMPLES; k += 4) { gainQ10 = WebRtcSpl_DivW32W16ResW16(p1, (int16_t)( (invARSpec2_Q16[k >> 2] + p2) >> 16)); *fr++ = (double)((data[ k ] * gainQ10 + 512) >> 10) / 128.0; *fi++ = (double)((data[k + 1] * gainQ10 + 512) >> 10) / 128.0; *fr++ = (double)((data[k + 2] * gainQ10 + 512) >> 10) / 128.0; *fi++ = (double)((data[k + 3] * gainQ10 + 512) >> 10) / 128.0; } break; } case kIsacUpperBand12: { for (k = 0, i = 0; k < FRAMESAMPLES_HALF; k += 4) { fr[i] = (double)data[ k ] / 128.0; fi[i] = (double)data[k + 1] / 128.0; i++; fr[i] = (double)data[k + 2] / 128.0; fi[i] = (double)data[k + 3] / 128.0; i++; } /* The second half of real and imaginary coefficients is zero. This is * due to using the old FFT module which requires two signals as input * while in 0-12 kHz mode we only have 8-12 kHz band, and the second * signal is set to zero. */ memset(&fr[FRAMESAMPLES_QUARTER], 0, FRAMESAMPLES_QUARTER * sizeof(double)); memset(&fi[FRAMESAMPLES_QUARTER], 0, FRAMESAMPLES_QUARTER * sizeof(double)); break; } case kIsacUpperBand16: { for (i = 0, k = 0; k < FRAMESAMPLES; k += 4, i++) { fr[i] = (double)data[ k ] / 128.0; fi[i] = (double)data[k + 1] / 128.0; fr[(FRAMESAMPLES_HALF) - 1 - i] = (double)data[k + 2] / 128.0; fi[(FRAMESAMPLES_HALF) - 1 - i] = (double)data[k + 3] / 128.0; } break; } } return len; } int WebRtcIsac_EncodeSpec(const int16_t* fr, const int16_t* fi, int16_t AvgPitchGain_Q12, enum ISACBand band, Bitstr* streamdata) { int16_t ditherQ7[FRAMESAMPLES]; int16_t dataQ7[FRAMESAMPLES]; int32_t PSpec[FRAMESAMPLES_QUARTER]; int32_t invARSpec2_Q16[FRAMESAMPLES_QUARTER]; uint16_t invARSpecQ8[FRAMESAMPLES_QUARTER]; int32_t CorrQ7[AR_ORDER + 1]; int32_t CorrQ7_norm[AR_ORDER + 1]; int16_t RCQ15[AR_ORDER]; int16_t ARCoefQ12[AR_ORDER + 1]; int32_t gain2_Q10; int16_t val; int32_t nrg, res; uint32_t sum; int32_t in_sqrt; int32_t newRes; int16_t err; uint32_t nrg_u32; int shift_var; int k, n, j, i; int is_12khz = !kIsSWB12; int num_dft_coeff = FRAMESAMPLES; /* Create dither signal. */ if (band == kIsacLowerBand) { GenerateDitherQ7Lb(ditherQ7, streamdata->W_upper, FRAMESAMPLES, AvgPitchGain_Q12); } else { GenerateDitherQ7LbUB(ditherQ7, streamdata->W_upper, FRAMESAMPLES); if (band == kIsacUpperBand12) { is_12khz = kIsSWB12; num_dft_coeff = FRAMESAMPLES_HALF; } } /* add dither and quantize, and compute power spectrum */ switch (band) { case kIsacLowerBand: { for (k = 0; k < FRAMESAMPLES; k += 4) { val = ((*fr++ + ditherQ7[k] + 64) & 0xFF80) - ditherQ7[k]; dataQ7[k] = val; sum = val * val; val = ((*fi++ + ditherQ7[k + 1] + 64) & 0xFF80) - ditherQ7[k + 1]; dataQ7[k + 1] = val; sum += val * val; val = ((*fr++ + ditherQ7[k + 2] + 64) & 0xFF80) - ditherQ7[k + 2]; dataQ7[k + 2] = val; sum += val * val; val = ((*fi++ + ditherQ7[k + 3] + 64) & 0xFF80) - ditherQ7[k + 3]; dataQ7[k + 3] = val; sum += val * val; PSpec[k >> 2] = sum >> 2; } break; } case kIsacUpperBand12: { for (k = 0, j = 0; k < FRAMESAMPLES_HALF; k += 4) { val = ((*fr++ + ditherQ7[k] + 64) & 0xFF80) - ditherQ7[k]; dataQ7[k] = val; sum = val * val; val = ((*fi++ + ditherQ7[k + 1] + 64) & 0xFF80) - ditherQ7[k + 1]; dataQ7[k + 1] = val; sum += val * val; PSpec[j++] = sum >> 1; val = ((*fr++ + ditherQ7[k + 2] + 64) & 0xFF80) - ditherQ7[k + 2]; dataQ7[k + 2] = val; sum = val * val; val = ((*fi++ + ditherQ7[k + 3] + 64) & 0xFF80) - ditherQ7[k + 3]; dataQ7[k + 3] = val; sum += val * val; PSpec[j++] = sum >> 1; } break; } case kIsacUpperBand16: { for (j = 0, k = 0; k < FRAMESAMPLES; k += 4, j++) { val = ((fr[j] + ditherQ7[k] + 64) & 0xFF80) - ditherQ7[k]; dataQ7[k] = val; sum = val * val; val = ((fi[j] + ditherQ7[k + 1] + 64) & 0xFF80) - ditherQ7[k + 1]; dataQ7[k + 1] = val; sum += val * val; val = ((fr[(FRAMESAMPLES_HALF) - 1 - j] + ditherQ7[k + 2] + 64) & 0xFF80) - ditherQ7[k + 2]; dataQ7[k + 2] = val; sum += val * val; val = ((fi[(FRAMESAMPLES_HALF) - 1 - j] + ditherQ7[k + 3] + 64) & 0xFF80) - ditherQ7[k + 3]; dataQ7[k + 3] = val; sum += val * val; PSpec[k >> 2] = sum >> 2; } break; } } /* compute correlation from power spectrum */ FindCorrelation(PSpec, CorrQ7); /* Find AR coefficients */ /* Aumber of bit shifts to 14-bit normalize CorrQ7[0] * (leaving room for sign) */ shift_var = WebRtcSpl_NormW32(CorrQ7[0]) - 18; if (shift_var > 0) { for (k = 0; k < AR_ORDER + 1; k++) { CorrQ7_norm[k] = CorrQ7[k] << shift_var; } } else { for (k = 0; k < AR_ORDER + 1; k++) { CorrQ7_norm[k] = CorrQ7[k] >> (-shift_var); } } /* Find RC coefficients. */ WebRtcSpl_AutoCorrToReflCoef(CorrQ7_norm, AR_ORDER, RCQ15); /* Quantize & code RC Coefficient. */ WebRtcIsac_EncodeRc(RCQ15, streamdata); /* RC -> AR coefficients */ WebRtcSpl_ReflCoefToLpc(RCQ15, AR_ORDER, ARCoefQ12); /* Compute ARCoef' * Corr * ARCoef in Q19. */ nrg = 0; for (j = 0; j <= AR_ORDER; j++) { for (n = 0; n <= j; n++) { nrg += (ARCoefQ12[j] * ((CorrQ7_norm[j - n] * ARCoefQ12[n] + 256) >> 9) + 4) >> 3; } for (n = j + 1; n <= AR_ORDER; n++) { nrg += (ARCoefQ12[j] * ((CorrQ7_norm[n - j] * ARCoefQ12[n] + 256) >> 9) + 4) >> 3; } } nrg_u32 = (uint32_t)nrg; if (shift_var > 0) { nrg_u32 = nrg_u32 >> shift_var; } else { nrg_u32 = nrg_u32 << (-shift_var); } if (nrg_u32 > 0x7FFFFFFF) { nrg = 0x7FFFFFFF; } else { nrg = (int32_t)nrg_u32; } /* Also shifts 31 bits to the left! */ gain2_Q10 = WebRtcSpl_DivResultInQ31(FRAMESAMPLES_QUARTER, nrg); /* Quantize & code gain2_Q10. */ if (WebRtcIsac_EncodeGain2(&gain2_Q10, streamdata)) { return -1; } /* Compute inverse AR power spectrum. */ FindInvArSpec(ARCoefQ12, gain2_Q10, invARSpec2_Q16); /* Convert to magnitude spectrum, by doing square-roots * (modified from SPLIB). */ res = 1 << (WebRtcSpl_GetSizeInBits(invARSpec2_Q16[0]) >> 1); for (k = 0; k < FRAMESAMPLES_QUARTER; k++) { in_sqrt = invARSpec2_Q16[k]; i = 10; /* Negative values make no sense for a real sqrt-function. */ if (in_sqrt < 0) { in_sqrt = -in_sqrt; } newRes = (in_sqrt / res + res) >> 1; do { res = newRes; newRes = (in_sqrt / res + res) >> 1; } while (newRes != res && i-- > 0); invARSpecQ8[k] = (int16_t)newRes; } /* arithmetic coding of spectrum */ err = WebRtcIsac_EncLogisticMulti2(streamdata, dataQ7, invARSpecQ8, num_dft_coeff, is_12khz); if (err < 0) { return (err); } return 0; } /* step-up */ void WebRtcIsac_Rc2Poly(double* RC, int N, double* a) { int m, k; double tmp[MAX_AR_MODEL_ORDER]; a[0] = 1.0; tmp[0] = 1.0; for (m = 1; m <= N; m++) { /* copy */ memcpy(&tmp[1], &a[1], (m - 1) * sizeof(double)); a[m] = RC[m - 1]; for (k = 1; k < m; k++) { a[k] += RC[m - 1] * tmp[m - k]; } } return; } /* step-down */ void WebRtcIsac_Poly2Rc(double* a, int N, double* RC) { int m, k; double tmp[MAX_AR_MODEL_ORDER]; double tmp_inv; RC[N - 1] = a[N]; for (m = N - 1; m > 0; m--) { tmp_inv = 1.0 / (1.0 - RC[m] * RC[m]); for (k = 1; k <= m; k++) { tmp[k] = (a[k] - RC[m] * a[m - k + 1]) * tmp_inv; } memcpy(&a[1], &tmp[1], (m - 1) * sizeof(double)); RC[m - 1] = tmp[m]; } return; } #define MAX_ORDER 100 /* Matlab's LAR definition */ void WebRtcIsac_Rc2Lar(const double* refc, double* lar, int order) { int k; for (k = 0; k < order; k++) { lar[k] = log((1 + refc[k]) / (1 - refc[k])); } } void WebRtcIsac_Lar2Rc(const double* lar, double* refc, int order) { int k; double tmp; for (k = 0; k < order; k++) { tmp = exp(lar[k]); refc[k] = (tmp - 1) / (tmp + 1); } } void WebRtcIsac_Poly2Lar(double* lowband, int orderLo, double* hiband, int orderHi, int Nsub, double* lars) { int k; double rc[MAX_ORDER], *inpl, *inph, *outp; inpl = lowband; inph = hiband; outp = lars; for (k = 0; k < Nsub; k++) { /* gains */ outp[0] = inpl[0]; outp[1] = inph[0]; outp += 2; /* Low band */ inpl[0] = 1.0; WebRtcIsac_Poly2Rc(inpl, orderLo, rc); WebRtcIsac_Rc2Lar(rc, outp, orderLo); outp += orderLo; /* High band */ inph[0] = 1.0; WebRtcIsac_Poly2Rc(inph, orderHi, rc); WebRtcIsac_Rc2Lar(rc, outp, orderHi); outp += orderHi; inpl += orderLo + 1; inph += orderHi + 1; } } int16_t WebRtcIsac_Poly2LarUB(double* lpcVecs, int16_t bandwidth) { double poly[MAX_ORDER]; double rc[MAX_ORDER]; double* ptrIO; int16_t vecCntr; int16_t vecSize; int16_t numVec; vecSize = UB_LPC_ORDER; switch (bandwidth) { case isac12kHz: { numVec = UB_LPC_VEC_PER_FRAME; break; } case isac16kHz: { numVec = UB16_LPC_VEC_PER_FRAME; break; } default: return -1; } ptrIO = lpcVecs; poly[0] = 1.0; for (vecCntr = 0; vecCntr < numVec; vecCntr++) { memcpy(&poly[1], ptrIO, sizeof(double) * vecSize); WebRtcIsac_Poly2Rc(poly, vecSize, rc); WebRtcIsac_Rc2Lar(rc, ptrIO, vecSize); ptrIO += vecSize; } return 0; } void WebRtcIsac_Lar2Poly(double* lars, double* lowband, int orderLo, double* hiband, int orderHi, int Nsub) { int k, orderTot; double rc[MAX_ORDER], *outpl, *outph, *inp; orderTot = (orderLo + orderHi + 2); outpl = lowband; outph = hiband; /* First two elements of 'inp' store gains*/ inp = lars; for (k = 0; k < Nsub; k++) { /* Low band */ WebRtcIsac_Lar2Rc(&inp[2], rc, orderLo); WebRtcIsac_Rc2Poly(rc, orderLo, outpl); /* High band */ WebRtcIsac_Lar2Rc(&inp[orderLo + 2], rc, orderHi); WebRtcIsac_Rc2Poly(rc, orderHi, outph); /* gains */ outpl[0] = inp[0]; outph[0] = inp[1]; outpl += orderLo + 1; outph += orderHi + 1; inp += orderTot; } } /* * assumes 2 LAR vectors interpolates to 'numPolyVec' A-polynomials * Note: 'numPolyVecs' includes the first and the last point of the interval */ void WebRtcIsac_Lar2PolyInterpolUB(double* larVecs, double* percepFilterParams, int numPolyVecs) { int polyCntr, coeffCntr; double larInterpol[UB_LPC_ORDER]; double rc[UB_LPC_ORDER]; double delta[UB_LPC_ORDER]; /* calculate the step-size for linear interpolation coefficients */ for (coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) { delta[coeffCntr] = (larVecs[UB_LPC_ORDER + coeffCntr] - larVecs[coeffCntr]) / (numPolyVecs - 1); } for (polyCntr = 0; polyCntr < numPolyVecs; polyCntr++) { for (coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) { larInterpol[coeffCntr] = larVecs[coeffCntr] + delta[coeffCntr] * polyCntr; } WebRtcIsac_Lar2Rc(larInterpol, rc, UB_LPC_ORDER); /* convert to A-polynomial, the following function returns A[0] = 1; * which is written where gains had to be written. Then we write the * gain (outside this function). This way we say a memcpy. */ WebRtcIsac_Rc2Poly(rc, UB_LPC_ORDER, percepFilterParams); percepFilterParams += (UB_LPC_ORDER + 1); } } int WebRtcIsac_DecodeLpc(Bitstr* streamdata, double* LPCCoef_lo, double* LPCCoef_hi) { double lars[KLT_ORDER_GAIN + KLT_ORDER_SHAPE]; int err; err = WebRtcIsac_DecodeLpcCoef(streamdata, lars); if (err < 0) { return -ISAC_RANGE_ERROR_DECODE_LPC; } WebRtcIsac_Lar2Poly(lars, LPCCoef_lo, ORDERLO, LPCCoef_hi, ORDERHI, SUBFRAMES); return 0; } int16_t WebRtcIsac_DecodeInterpolLpcUb(Bitstr* streamdata, double* percepFilterParams, int16_t bandwidth) { double lpcCoeff[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; int err; int interpolCntr; int subframeCntr; int16_t numSegments; int16_t numVecPerSegment; int16_t numGains; double percepFilterGains[SUBFRAMES << 1]; double* ptrOutParam = percepFilterParams; err = WebRtcIsac_DecodeLpcCoefUB(streamdata, lpcCoeff, percepFilterGains, bandwidth); if (err < 0) { return -ISAC_RANGE_ERROR_DECODE_LPC; } switch (bandwidth) { case isac12kHz: { numGains = SUBFRAMES; numSegments = UB_LPC_VEC_PER_FRAME - 1; numVecPerSegment = kLpcVecPerSegmentUb12; break; } case isac16kHz: { numGains = SUBFRAMES << 1; numSegments = UB16_LPC_VEC_PER_FRAME - 1; numVecPerSegment = kLpcVecPerSegmentUb16; break; } default: return -1; } for (interpolCntr = 0; interpolCntr < numSegments; interpolCntr++) { WebRtcIsac_Lar2PolyInterpolUB(&lpcCoeff[interpolCntr * UB_LPC_ORDER], ptrOutParam, numVecPerSegment + 1); ptrOutParam += (numVecPerSegment * (UB_LPC_ORDER + 1)); } ptrOutParam = percepFilterParams; if (bandwidth == isac16kHz) { ptrOutParam += (1 + UB_LPC_ORDER); } for (subframeCntr = 0; subframeCntr < numGains; subframeCntr++) { *ptrOutParam = percepFilterGains[subframeCntr]; ptrOutParam += (1 + UB_LPC_ORDER); } return 0; } /* decode & dequantize LPC Coef */ int WebRtcIsac_DecodeLpcCoef(Bitstr* streamdata, double* LPCCoef) { int j, k, n, pos, pos2, posg, poss, offsg, offss, offs2; int index_g[KLT_ORDER_GAIN], index_s[KLT_ORDER_SHAPE]; double tmpcoeffs_g[KLT_ORDER_GAIN], tmpcoeffs_s[KLT_ORDER_SHAPE]; double tmpcoeffs2_g[KLT_ORDER_GAIN], tmpcoeffs2_s[KLT_ORDER_SHAPE]; double sum; int err; int model = 1; /* entropy decoding of model number */ /* We are keeping this for backward compatibility of bit-streams. */ err = WebRtcIsac_DecHistOneStepMulti(&model, streamdata, WebRtcIsac_kQKltModelCdfPtr, WebRtcIsac_kQKltModelInitIndex, 1); if (err < 0) { return err; } /* Only accepted value of model is 0. It is kept in bit-stream for backward * compatibility. */ if (model != 0) { return -ISAC_DISALLOWED_LPC_MODEL; } /* entropy decoding of quantization indices */ err = WebRtcIsac_DecHistOneStepMulti( index_s, streamdata, WebRtcIsac_kQKltCdfPtrShape, WebRtcIsac_kQKltInitIndexShape, KLT_ORDER_SHAPE); if (err < 0) { return err; } err = WebRtcIsac_DecHistOneStepMulti( index_g, streamdata, WebRtcIsac_kQKltCdfPtrGain, WebRtcIsac_kQKltInitIndexGain, KLT_ORDER_GAIN); if (err < 0) { return err; } /* find quantization levels for coefficients */ for (k = 0; k < KLT_ORDER_SHAPE; k++) { tmpcoeffs_s[k] = WebRtcIsac_kQKltLevelsShape[WebRtcIsac_kQKltOffsetShape[k] + index_s[k]]; } for (k = 0; k < KLT_ORDER_GAIN; k++) { tmpcoeffs_g[k] = WebRtcIsac_kQKltLevelsGain[WebRtcIsac_kQKltOffsetGain[k] + index_g[k]]; } /* Inverse KLT */ /* Left transform, transpose matrix! */ offsg = 0; offss = 0; posg = 0; poss = 0; for (j = 0; j < SUBFRAMES; j++) { offs2 = 0; for (k = 0; k < LPC_GAIN_ORDER; k++) { sum = 0; pos = offsg; pos2 = offs2; for (n = 0; n < LPC_GAIN_ORDER; n++) { sum += tmpcoeffs_g[pos++] * WebRtcIsac_kKltT1Gain[pos2++]; } tmpcoeffs2_g[posg++] = sum; offs2 += LPC_GAIN_ORDER; } offs2 = 0; for (k = 0; k < LPC_SHAPE_ORDER; k++) { sum = 0; pos = offss; pos2 = offs2; for (n = 0; n < LPC_SHAPE_ORDER; n++) { sum += tmpcoeffs_s[pos++] * WebRtcIsac_kKltT1Shape[pos2++]; } tmpcoeffs2_s[poss++] = sum; offs2 += LPC_SHAPE_ORDER; } offsg += LPC_GAIN_ORDER; offss += LPC_SHAPE_ORDER; } /* Right transform, transpose matrix */ offsg = 0; offss = 0; posg = 0; poss = 0; for (j = 0; j < SUBFRAMES; j++) { posg = offsg; for (k = 0; k < LPC_GAIN_ORDER; k++) { sum = 0; pos = k; pos2 = j; for (n = 0; n < SUBFRAMES; n++) { sum += tmpcoeffs2_g[pos] * WebRtcIsac_kKltT2Gain[pos2]; pos += LPC_GAIN_ORDER; pos2 += SUBFRAMES; } tmpcoeffs_g[posg++] = sum; } poss = offss; for (k = 0; k < LPC_SHAPE_ORDER; k++) { sum = 0; pos = k; pos2 = j; for (n = 0; n < SUBFRAMES; n++) { sum += tmpcoeffs2_s[pos] * WebRtcIsac_kKltT2Shape[pos2]; pos += LPC_SHAPE_ORDER; pos2 += SUBFRAMES; } tmpcoeffs_s[poss++] = sum; } offsg += LPC_GAIN_ORDER; offss += LPC_SHAPE_ORDER; } /* scaling, mean addition, and gain restoration */ posg = 0; poss = 0; pos = 0; for (k = 0; k < SUBFRAMES; k++) { /* log gains */ LPCCoef[pos] = tmpcoeffs_g[posg] / LPC_GAIN_SCALE; LPCCoef[pos] += WebRtcIsac_kLpcMeansGain[posg]; LPCCoef[pos] = exp(LPCCoef[pos]); pos++; posg++; LPCCoef[pos] = tmpcoeffs_g[posg] / LPC_GAIN_SCALE; LPCCoef[pos] += WebRtcIsac_kLpcMeansGain[posg]; LPCCoef[pos] = exp(LPCCoef[pos]); pos++; posg++; /* Low-band LAR coefficients. */ for (n = 0; n < LPC_LOBAND_ORDER; n++, pos++, poss++) { LPCCoef[pos] = tmpcoeffs_s[poss] / LPC_LOBAND_SCALE; LPCCoef[pos] += WebRtcIsac_kLpcMeansShape[poss]; } /* High-band LAR coefficients. */ for (n = 0; n < LPC_HIBAND_ORDER; n++, pos++, poss++) { LPCCoef[pos] = tmpcoeffs_s[poss] / LPC_HIBAND_SCALE; LPCCoef[pos] += WebRtcIsac_kLpcMeansShape[poss]; } } return 0; } /* Encode LPC in LAR domain. */ void WebRtcIsac_EncodeLar(double* LPCCoef, Bitstr* streamdata, IsacSaveEncoderData* encData) { int j, k, n, pos, pos2, poss, offss, offs2; int index_s[KLT_ORDER_SHAPE]; int index_ovr_s[KLT_ORDER_SHAPE]; double tmpcoeffs_s[KLT_ORDER_SHAPE]; double tmpcoeffs2_s[KLT_ORDER_SHAPE]; double sum; const int kModel = 0; /* Mean removal and scaling. */ poss = 0; pos = 0; for (k = 0; k < SUBFRAMES; k++) { /* First two element are gains, move over them. */ pos += 2; /* Low-band LAR coefficients. */ for (n = 0; n < LPC_LOBAND_ORDER; n++, poss++, pos++) { tmpcoeffs_s[poss] = LPCCoef[pos] - WebRtcIsac_kLpcMeansShape[poss]; tmpcoeffs_s[poss] *= LPC_LOBAND_SCALE; } /* High-band LAR coefficients. */ for (n = 0; n < LPC_HIBAND_ORDER; n++, poss++, pos++) { tmpcoeffs_s[poss] = LPCCoef[pos] - WebRtcIsac_kLpcMeansShape[poss]; tmpcoeffs_s[poss] *= LPC_HIBAND_SCALE; } } /* KLT */ /* Left transform. */ offss = 0; for (j = 0; j < SUBFRAMES; j++) { poss = offss; for (k = 0; k < LPC_SHAPE_ORDER; k++) { sum = 0; pos = offss; pos2 = k; for (n = 0; n < LPC_SHAPE_ORDER; n++) { sum += tmpcoeffs_s[pos++] * WebRtcIsac_kKltT1Shape[pos2]; pos2 += LPC_SHAPE_ORDER; } tmpcoeffs2_s[poss++] = sum; } offss += LPC_SHAPE_ORDER; } /* Right transform. */ offss = 0; offs2 = 0; for (j = 0; j < SUBFRAMES; j++) { poss = offss; for (k = 0; k < LPC_SHAPE_ORDER; k++) { sum = 0; pos = k; pos2 = offs2; for (n = 0; n < SUBFRAMES; n++) { sum += tmpcoeffs2_s[pos] * WebRtcIsac_kKltT2Shape[pos2++]; pos += LPC_SHAPE_ORDER; } tmpcoeffs_s[poss++] = sum; } offs2 += SUBFRAMES; offss += LPC_SHAPE_ORDER; } /* Quantize coefficients. */ for (k = 0; k < KLT_ORDER_SHAPE; k++) { index_s[k] = (WebRtcIsac_lrint(tmpcoeffs_s[k] / KLT_STEPSIZE)) + WebRtcIsac_kQKltQuantMinShape[k]; if (index_s[k] < 0) { index_s[k] = 0; } else if (index_s[k] > WebRtcIsac_kQKltMaxIndShape[k]) { index_s[k] = WebRtcIsac_kQKltMaxIndShape[k]; } index_ovr_s[k] = WebRtcIsac_kQKltOffsetShape[k] + index_s[k]; } /* Only one model remains in this version of the code, kModel = 0. We * are keeping for bit-streams to be backward compatible. */ /* entropy coding of model number */ WebRtcIsac_EncHistMulti(streamdata, &kModel, WebRtcIsac_kQKltModelCdfPtr, 1); /* Save data for creation of multiple bit streams */ /* Entropy coding of quantization indices - shape only. */ WebRtcIsac_EncHistMulti(streamdata, index_s, WebRtcIsac_kQKltCdfPtrShape, KLT_ORDER_SHAPE); /* Save data for creation of multiple bit streams. */ for (k = 0; k < KLT_ORDER_SHAPE; k++) { encData->LPCindex_s[KLT_ORDER_SHAPE * encData->startIdx + k] = index_s[k]; } /* Find quantization levels for shape coefficients. */ for (k = 0; k < KLT_ORDER_SHAPE; k++) { tmpcoeffs_s[k] = WebRtcIsac_kQKltLevelsShape[index_ovr_s[k]]; } /* Inverse KLT. */ /* Left transform, transpose matrix.! */ offss = 0; poss = 0; for (j = 0; j < SUBFRAMES; j++) { offs2 = 0; for (k = 0; k < LPC_SHAPE_ORDER; k++) { sum = 0; pos = offss; pos2 = offs2; for (n = 0; n < LPC_SHAPE_ORDER; n++) { sum += tmpcoeffs_s[pos++] * WebRtcIsac_kKltT1Shape[pos2++]; } tmpcoeffs2_s[poss++] = sum; offs2 += LPC_SHAPE_ORDER; } offss += LPC_SHAPE_ORDER; } /* Right transform, Transpose matrix */ offss = 0; poss = 0; for (j = 0; j < SUBFRAMES; j++) { poss = offss; for (k = 0; k < LPC_SHAPE_ORDER; k++) { sum = 0; pos = k; pos2 = j; for (n = 0; n < SUBFRAMES; n++) { sum += tmpcoeffs2_s[pos] * WebRtcIsac_kKltT2Shape[pos2]; pos += LPC_SHAPE_ORDER; pos2 += SUBFRAMES; } tmpcoeffs_s[poss++] = sum; } offss += LPC_SHAPE_ORDER; } /* Scaling, mean addition, and gain restoration. */ poss = 0; pos = 0; for (k = 0; k < SUBFRAMES; k++) { /* Ignore gains. */ pos += 2; /* Low band LAR coefficients. */ for (n = 0; n < LPC_LOBAND_ORDER; n++, pos++, poss++) { LPCCoef[pos] = tmpcoeffs_s[poss] / LPC_LOBAND_SCALE; LPCCoef[pos] += WebRtcIsac_kLpcMeansShape[poss]; } /* High band LAR coefficients. */ for (n = 0; n < LPC_HIBAND_ORDER; n++, pos++, poss++) { LPCCoef[pos] = tmpcoeffs_s[poss] / LPC_HIBAND_SCALE; LPCCoef[pos] += WebRtcIsac_kLpcMeansShape[poss]; } } } void WebRtcIsac_EncodeLpcLb(double* LPCCoef_lo, double* LPCCoef_hi, Bitstr* streamdata, IsacSaveEncoderData* encData) { double lars[KLT_ORDER_GAIN + KLT_ORDER_SHAPE]; int k; WebRtcIsac_Poly2Lar(LPCCoef_lo, ORDERLO, LPCCoef_hi, ORDERHI, SUBFRAMES, lars); WebRtcIsac_EncodeLar(lars, streamdata, encData); WebRtcIsac_Lar2Poly(lars, LPCCoef_lo, ORDERLO, LPCCoef_hi, ORDERHI, SUBFRAMES); /* Save data for creation of multiple bit streams (and transcoding). */ for (k = 0; k < (ORDERLO + 1)*SUBFRAMES; k++) { encData->LPCcoeffs_lo[(ORDERLO + 1)*SUBFRAMES * encData->startIdx + k] = LPCCoef_lo[k]; } for (k = 0; k < (ORDERHI + 1)*SUBFRAMES; k++) { encData->LPCcoeffs_hi[(ORDERHI + 1)*SUBFRAMES * encData->startIdx + k] = LPCCoef_hi[k]; } } int16_t WebRtcIsac_EncodeLpcUB(double* lpcVecs, Bitstr* streamdata, double* interpolLPCCoeff, int16_t bandwidth, ISACUBSaveEncDataStruct* encData) { double U[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; int idx[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; int interpolCntr; WebRtcIsac_Poly2LarUB(lpcVecs, bandwidth); WebRtcIsac_RemoveLarMean(lpcVecs, bandwidth); WebRtcIsac_DecorrelateIntraVec(lpcVecs, U, bandwidth); WebRtcIsac_DecorrelateInterVec(U, lpcVecs, bandwidth); WebRtcIsac_QuantizeUncorrLar(lpcVecs, idx, bandwidth); WebRtcIsac_CorrelateInterVec(lpcVecs, U, bandwidth); WebRtcIsac_CorrelateIntraVec(U, lpcVecs, bandwidth); WebRtcIsac_AddLarMean(lpcVecs, bandwidth); switch (bandwidth) { case isac12kHz: { /* Store the indices to be used for multiple encoding. */ memcpy(encData->indexLPCShape, idx, UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME * sizeof(int)); WebRtcIsac_EncHistMulti(streamdata, idx, WebRtcIsac_kLpcShapeCdfMatUb12, UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME); for (interpolCntr = 0; interpolCntr < UB_INTERPOL_SEGMENTS; interpolCntr++) { WebRtcIsac_Lar2PolyInterpolUB(lpcVecs, interpolLPCCoeff, kLpcVecPerSegmentUb12 + 1); lpcVecs += UB_LPC_ORDER; interpolLPCCoeff += (kLpcVecPerSegmentUb12 * (UB_LPC_ORDER + 1)); } break; } case isac16kHz: { /* Store the indices to be used for multiple encoding. */ memcpy(encData->indexLPCShape, idx, UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME * sizeof(int)); WebRtcIsac_EncHistMulti(streamdata, idx, WebRtcIsac_kLpcShapeCdfMatUb16, UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME); for (interpolCntr = 0; interpolCntr < UB16_INTERPOL_SEGMENTS; interpolCntr++) { WebRtcIsac_Lar2PolyInterpolUB(lpcVecs, interpolLPCCoeff, kLpcVecPerSegmentUb16 + 1); lpcVecs += UB_LPC_ORDER; interpolLPCCoeff += (kLpcVecPerSegmentUb16 * (UB_LPC_ORDER + 1)); } break; } default: return -1; } return 0; } void WebRtcIsac_EncodeLpcGainLb(double* LPCCoef_lo, double* LPCCoef_hi, Bitstr* streamdata, IsacSaveEncoderData* encData) { int j, k, n, pos, pos2, posg, offsg, offs2; int index_g[KLT_ORDER_GAIN]; int index_ovr_g[KLT_ORDER_GAIN]; double tmpcoeffs_g[KLT_ORDER_GAIN]; double tmpcoeffs2_g[KLT_ORDER_GAIN]; double sum; /* log gains, mean removal and scaling */ posg = 0; for (k = 0; k < SUBFRAMES; k++) { tmpcoeffs_g[posg] = log(LPCCoef_lo[(LPC_LOBAND_ORDER + 1) * k]); tmpcoeffs_g[posg] -= WebRtcIsac_kLpcMeansGain[posg]; tmpcoeffs_g[posg] *= LPC_GAIN_SCALE; posg++; tmpcoeffs_g[posg] = log(LPCCoef_hi[(LPC_HIBAND_ORDER + 1) * k]); tmpcoeffs_g[posg] -= WebRtcIsac_kLpcMeansGain[posg]; tmpcoeffs_g[posg] *= LPC_GAIN_SCALE; posg++; } /* KLT */ /* Left transform. */ offsg = 0; for (j = 0; j < SUBFRAMES; j++) { posg = offsg; for (k = 0; k < LPC_GAIN_ORDER; k++) { sum = 0; pos = offsg; pos2 = k; for (n = 0; n < LPC_GAIN_ORDER; n++) { sum += tmpcoeffs_g[pos++] * WebRtcIsac_kKltT1Gain[pos2]; pos2 += LPC_GAIN_ORDER; } tmpcoeffs2_g[posg++] = sum; } offsg += LPC_GAIN_ORDER; } /* Right transform. */ offsg = 0; offs2 = 0; for (j = 0; j < SUBFRAMES; j++) { posg = offsg; for (k = 0; k < LPC_GAIN_ORDER; k++) { sum = 0; pos = k; pos2 = offs2; for (n = 0; n < SUBFRAMES; n++) { sum += tmpcoeffs2_g[pos] * WebRtcIsac_kKltT2Gain[pos2++]; pos += LPC_GAIN_ORDER; } tmpcoeffs_g[posg++] = sum; } offs2 += SUBFRAMES; offsg += LPC_GAIN_ORDER; } /* Quantize coefficients. */ for (k = 0; k < KLT_ORDER_GAIN; k++) { /* Get index. */ pos2 = WebRtcIsac_lrint(tmpcoeffs_g[k] / KLT_STEPSIZE); index_g[k] = (pos2) + WebRtcIsac_kQKltQuantMinGain[k]; if (index_g[k] < 0) { index_g[k] = 0; } else if (index_g[k] > WebRtcIsac_kQKltMaxIndGain[k]) { index_g[k] = WebRtcIsac_kQKltMaxIndGain[k]; } index_ovr_g[k] = WebRtcIsac_kQKltOffsetGain[k] + index_g[k]; /* Find quantization levels for coefficients. */ tmpcoeffs_g[k] = WebRtcIsac_kQKltLevelsGain[index_ovr_g[k]]; /* Save data for creation of multiple bit streams. */ encData->LPCindex_g[KLT_ORDER_GAIN * encData->startIdx + k] = index_g[k]; } /* Entropy coding of quantization indices - gain. */ WebRtcIsac_EncHistMulti(streamdata, index_g, WebRtcIsac_kQKltCdfPtrGain, KLT_ORDER_GAIN); /* Find quantization levels for coefficients. */ /* Left transform. */ offsg = 0; posg = 0; for (j = 0; j < SUBFRAMES; j++) { offs2 = 0; for (k = 0; k < LPC_GAIN_ORDER; k++) { sum = 0; pos = offsg; pos2 = offs2; for (n = 0; n < LPC_GAIN_ORDER; n++) sum += tmpcoeffs_g[pos++] * WebRtcIsac_kKltT1Gain[pos2++]; tmpcoeffs2_g[posg++] = sum; offs2 += LPC_GAIN_ORDER; } offsg += LPC_GAIN_ORDER; } /* Right transform, transpose matrix. */ offsg = 0; posg = 0; for (j = 0; j < SUBFRAMES; j++) { posg = offsg; for (k = 0; k < LPC_GAIN_ORDER; k++) { sum = 0; pos = k; pos2 = j; for (n = 0; n < SUBFRAMES; n++) { sum += tmpcoeffs2_g[pos] * WebRtcIsac_kKltT2Gain[pos2]; pos += LPC_GAIN_ORDER; pos2 += SUBFRAMES; } tmpcoeffs_g[posg++] = sum; } offsg += LPC_GAIN_ORDER; } /* Scaling, mean addition, and gain restoration. */ posg = 0; for (k = 0; k < SUBFRAMES; k++) { sum = tmpcoeffs_g[posg] / LPC_GAIN_SCALE; sum += WebRtcIsac_kLpcMeansGain[posg]; LPCCoef_lo[k * (LPC_LOBAND_ORDER + 1)] = exp(sum); pos++; posg++; sum = tmpcoeffs_g[posg] / LPC_GAIN_SCALE; sum += WebRtcIsac_kLpcMeansGain[posg]; LPCCoef_hi[k * (LPC_HIBAND_ORDER + 1)] = exp(sum); pos++; posg++; } } void WebRtcIsac_EncodeLpcGainUb(double* lpGains, Bitstr* streamdata, int* lpcGainIndex) { double U[UB_LPC_GAIN_DIM]; int idx[UB_LPC_GAIN_DIM]; WebRtcIsac_ToLogDomainRemoveMean(lpGains); WebRtcIsac_DecorrelateLPGain(lpGains, U); WebRtcIsac_QuantizeLpcGain(U, idx); /* Store the index for re-encoding for FEC. */ memcpy(lpcGainIndex, idx, UB_LPC_GAIN_DIM * sizeof(int)); WebRtcIsac_CorrelateLpcGain(U, lpGains); WebRtcIsac_AddMeanToLinearDomain(lpGains); WebRtcIsac_EncHistMulti(streamdata, idx, WebRtcIsac_kLpcGainCdfMat, UB_LPC_GAIN_DIM); } void WebRtcIsac_StoreLpcGainUb(double* lpGains, Bitstr* streamdata) { double U[UB_LPC_GAIN_DIM]; int idx[UB_LPC_GAIN_DIM]; WebRtcIsac_ToLogDomainRemoveMean(lpGains); WebRtcIsac_DecorrelateLPGain(lpGains, U); WebRtcIsac_QuantizeLpcGain(U, idx); WebRtcIsac_EncHistMulti(streamdata, idx, WebRtcIsac_kLpcGainCdfMat, UB_LPC_GAIN_DIM); } int16_t WebRtcIsac_DecodeLpcGainUb(double* lpGains, Bitstr* streamdata) { double U[UB_LPC_GAIN_DIM]; int idx[UB_LPC_GAIN_DIM]; int err; err = WebRtcIsac_DecHistOneStepMulti(idx, streamdata, WebRtcIsac_kLpcGainCdfMat, WebRtcIsac_kLpcGainEntropySearch, UB_LPC_GAIN_DIM); if (err < 0) { return -1; } WebRtcIsac_DequantizeLpcGain(idx, U); WebRtcIsac_CorrelateLpcGain(U, lpGains); WebRtcIsac_AddMeanToLinearDomain(lpGains); return 0; } /* decode & dequantize RC */ int WebRtcIsac_DecodeRc(Bitstr* streamdata, int16_t* RCQ15) { int k, err; int index[AR_ORDER]; /* entropy decoding of quantization indices */ err = WebRtcIsac_DecHistOneStepMulti(index, streamdata, WebRtcIsac_kQArRcCdfPtr, WebRtcIsac_kQArRcInitIndex, AR_ORDER); if (err < 0) return err; /* find quantization levels for reflection coefficients */ for (k = 0; k < AR_ORDER; k++) { RCQ15[k] = *(WebRtcIsac_kQArRcLevelsPtr[k] + index[k]); } return 0; } /* quantize & code RC */ void WebRtcIsac_EncodeRc(int16_t* RCQ15, Bitstr* streamdata) { int k; int index[AR_ORDER]; /* quantize reflection coefficients (add noise feedback?) */ for (k = 0; k < AR_ORDER; k++) { index[k] = WebRtcIsac_kQArRcInitIndex[k]; // The safe-guards in following while conditions are to suppress gcc 4.8.3 // warnings, Issue 2888. Otherwise, first and last elements of // |WebRtcIsac_kQArBoundaryLevels| are such that the following search // *never* cause an out-of-boundary read. if (RCQ15[k] > WebRtcIsac_kQArBoundaryLevels[index[k]]) { while (index[k] + 1 < NUM_AR_RC_QUANT_BAUNDARY && RCQ15[k] > WebRtcIsac_kQArBoundaryLevels[index[k] + 1]) { index[k]++; } } else { while (index[k] > 0 && RCQ15[k] < WebRtcIsac_kQArBoundaryLevels[--index[k]]) ; } RCQ15[k] = *(WebRtcIsac_kQArRcLevelsPtr[k] + index[k]); } /* entropy coding of quantization indices */ WebRtcIsac_EncHistMulti(streamdata, index, WebRtcIsac_kQArRcCdfPtr, AR_ORDER); } /* decode & dequantize squared Gain */ int WebRtcIsac_DecodeGain2(Bitstr* streamdata, int32_t* gainQ10) { int index, err; /* entropy decoding of quantization index */ err = WebRtcIsac_DecHistOneStepMulti(&index, streamdata, WebRtcIsac_kQGainCdf_ptr, WebRtcIsac_kQGainInitIndex, 1); if (err < 0) { return err; } /* find quantization level */ *gainQ10 = WebRtcIsac_kQGain2Levels[index]; return 0; } /* quantize & code squared Gain */ int WebRtcIsac_EncodeGain2(int32_t* gainQ10, Bitstr* streamdata) { int index; /* find quantization index */ index = WebRtcIsac_kQGainInitIndex[0]; if (*gainQ10 > WebRtcIsac_kQGain2BoundaryLevels[index]) { while (*gainQ10 > WebRtcIsac_kQGain2BoundaryLevels[index + 1]) { index++; } } else { while (*gainQ10 < WebRtcIsac_kQGain2BoundaryLevels[--index]) ; } /* De-quantize */ *gainQ10 = WebRtcIsac_kQGain2Levels[index]; /* entropy coding of quantization index */ WebRtcIsac_EncHistMulti(streamdata, &index, WebRtcIsac_kQGainCdf_ptr, 1); return 0; } /* code and decode Pitch Gains and Lags functions */ /* decode & dequantize Pitch Gains */ int WebRtcIsac_DecodePitchGain(Bitstr* streamdata, int16_t* PitchGains_Q12) { int index_comb, err; const uint16_t* WebRtcIsac_kQPitchGainCdf_ptr[1]; /* Entropy decoding of quantization indices */ *WebRtcIsac_kQPitchGainCdf_ptr = WebRtcIsac_kQPitchGainCdf; err = WebRtcIsac_DecHistBisectMulti(&index_comb, streamdata, WebRtcIsac_kQPitchGainCdf_ptr, WebRtcIsac_kQCdfTableSizeGain, 1); /* Error check, Q_mean_Gain.. tables are of size 144 */ if ((err < 0) || (index_comb < 0) || (index_comb >= 144)) { return -ISAC_RANGE_ERROR_DECODE_PITCH_GAIN; } /* De-quantize back to pitch gains by table look-up. */ PitchGains_Q12[0] = WebRtcIsac_kQMeanGain1Q12[index_comb]; PitchGains_Q12[1] = WebRtcIsac_kQMeanGain2Q12[index_comb]; PitchGains_Q12[2] = WebRtcIsac_kQMeanGain3Q12[index_comb]; PitchGains_Q12[3] = WebRtcIsac_kQMeanGain4Q12[index_comb]; return 0; } /* Quantize & code Pitch Gains. */ void WebRtcIsac_EncodePitchGain(int16_t* PitchGains_Q12, Bitstr* streamdata, IsacSaveEncoderData* encData) { int k, j; double C; double S[PITCH_SUBFRAMES]; int index[3]; int index_comb; const uint16_t* WebRtcIsac_kQPitchGainCdf_ptr[1]; double PitchGains[PITCH_SUBFRAMES] = {0, 0, 0, 0}; /* Take the asin. */ for (k = 0; k < PITCH_SUBFRAMES; k++) { PitchGains[k] = ((float)PitchGains_Q12[k]) / 4096; S[k] = asin(PitchGains[k]); } /* Find quantization index; only for the first three * transform coefficients. */ for (k = 0; k < 3; k++) { /* transform */ C = 0.0; for (j = 0; j < PITCH_SUBFRAMES; j++) { C += WebRtcIsac_kTransform[k][j] * S[j]; } /* Quantize */ index[k] = WebRtcIsac_lrint(C / PITCH_GAIN_STEPSIZE); /* Check that the index is not outside the boundaries of the table. */ if (index[k] < WebRtcIsac_kIndexLowerLimitGain[k]) { index[k] = WebRtcIsac_kIndexLowerLimitGain[k]; } else if (index[k] > WebRtcIsac_kIndexUpperLimitGain[k]) { index[k] = WebRtcIsac_kIndexUpperLimitGain[k]; } index[k] -= WebRtcIsac_kIndexLowerLimitGain[k]; } /* Calculate unique overall index. */ index_comb = WebRtcIsac_kIndexMultsGain[0] * index[0] + WebRtcIsac_kIndexMultsGain[1] * index[1] + index[2]; /* unquantize back to pitch gains by table look-up */ PitchGains_Q12[0] = WebRtcIsac_kQMeanGain1Q12[index_comb]; PitchGains_Q12[1] = WebRtcIsac_kQMeanGain2Q12[index_comb]; PitchGains_Q12[2] = WebRtcIsac_kQMeanGain3Q12[index_comb]; PitchGains_Q12[3] = WebRtcIsac_kQMeanGain4Q12[index_comb]; /* entropy coding of quantization pitch gains */ *WebRtcIsac_kQPitchGainCdf_ptr = WebRtcIsac_kQPitchGainCdf; WebRtcIsac_EncHistMulti(streamdata, &index_comb, WebRtcIsac_kQPitchGainCdf_ptr, 1); encData->pitchGain_index[encData->startIdx] = index_comb; } /* Pitch LAG */ /* Decode & de-quantize Pitch Lags. */ int WebRtcIsac_DecodePitchLag(Bitstr* streamdata, int16_t* PitchGain_Q12, double* PitchLags) { int k, err; double StepSize; double C; int index[PITCH_SUBFRAMES]; double mean_gain; const double* mean_val2, *mean_val3, *mean_val4; const int16_t* lower_limit; const uint16_t* init_index; const uint16_t* cdf_size; const uint16_t** cdf; double PitchGain[4] = {0, 0, 0, 0}; /* compute mean pitch gain */ mean_gain = 0.0; for (k = 0; k < 4; k++) { PitchGain[k] = ((float)PitchGain_Q12[k]) / 4096; mean_gain += PitchGain[k]; } mean_gain /= 4.0; /* voicing classification. */ if (mean_gain < 0.2) { StepSize = WebRtcIsac_kQPitchLagStepsizeLo; cdf = WebRtcIsac_kQPitchLagCdfPtrLo; cdf_size = WebRtcIsac_kQPitchLagCdfSizeLo; mean_val2 = WebRtcIsac_kQMeanLag2Lo; mean_val3 = WebRtcIsac_kQMeanLag3Lo; mean_val4 = WebRtcIsac_kQMeanLag4Lo; lower_limit = WebRtcIsac_kQIndexLowerLimitLagLo; init_index = WebRtcIsac_kQInitIndexLagLo; } else if (mean_gain < 0.4) { StepSize = WebRtcIsac_kQPitchLagStepsizeMid; cdf = WebRtcIsac_kQPitchLagCdfPtrMid; cdf_size = WebRtcIsac_kQPitchLagCdfSizeMid; mean_val2 = WebRtcIsac_kQMeanLag2Mid; mean_val3 = WebRtcIsac_kQMeanLag3Mid; mean_val4 = WebRtcIsac_kQMeanLag4Mid; lower_limit = WebRtcIsac_kQIndexLowerLimitLagMid; init_index = WebRtcIsac_kQInitIndexLagMid; } else { StepSize = WebRtcIsac_kQPitchLagStepsizeHi; cdf = WebRtcIsac_kQPitchLagCdfPtrHi; cdf_size = WebRtcIsac_kQPitchLagCdfSizeHi; mean_val2 = WebRtcIsac_kQMeanLag2Hi; mean_val3 = WebRtcIsac_kQMeanLag3Hi; mean_val4 = WebRtcIsac_kQMeanLag4Hi; lower_limit = WebRtcIsac_kQindexLowerLimitLagHi; init_index = WebRtcIsac_kQInitIndexLagHi; } /* Entropy decoding of quantization indices. */ err = WebRtcIsac_DecHistBisectMulti(index, streamdata, cdf, cdf_size, 1); if ((err < 0) || (index[0] < 0)) { return -ISAC_RANGE_ERROR_DECODE_PITCH_LAG; } err = WebRtcIsac_DecHistOneStepMulti(index + 1, streamdata, cdf + 1, init_index, 3); if (err < 0) { return -ISAC_RANGE_ERROR_DECODE_PITCH_LAG; } /* Unquantize back to transform coefficients and do the inverse transform: * S = T'*C. */ C = (index[0] + lower_limit[0]) * StepSize; for (k = 0; k < PITCH_SUBFRAMES; k++) { PitchLags[k] = WebRtcIsac_kTransformTranspose[k][0] * C; } C = mean_val2[index[1]]; for (k = 0; k < PITCH_SUBFRAMES; k++) { PitchLags[k] += WebRtcIsac_kTransformTranspose[k][1] * C; } C = mean_val3[index[2]]; for (k = 0; k < PITCH_SUBFRAMES; k++) { PitchLags[k] += WebRtcIsac_kTransformTranspose[k][2] * C; } C = mean_val4[index[3]]; for (k = 0; k < PITCH_SUBFRAMES; k++) { PitchLags[k] += WebRtcIsac_kTransformTranspose[k][3] * C; } return 0; } /* Quantize & code pitch lags. */ void WebRtcIsac_EncodePitchLag(double* PitchLags, int16_t* PitchGain_Q12, Bitstr* streamdata, IsacSaveEncoderData* encData) { int k, j; double StepSize; double C; int index[PITCH_SUBFRAMES]; double mean_gain; const double* mean_val2, *mean_val3, *mean_val4; const int16_t* lower_limit, *upper_limit; const uint16_t** cdf; double PitchGain[4] = {0, 0, 0, 0}; /* compute mean pitch gain */ mean_gain = 0.0; for (k = 0; k < 4; k++) { PitchGain[k] = ((float)PitchGain_Q12[k]) / 4096; mean_gain += PitchGain[k]; } mean_gain /= 4.0; /* Save data for creation of multiple bit streams */ encData->meanGain[encData->startIdx] = mean_gain; /* Voicing classification. */ if (mean_gain < 0.2) { StepSize = WebRtcIsac_kQPitchLagStepsizeLo; cdf = WebRtcIsac_kQPitchLagCdfPtrLo; mean_val2 = WebRtcIsac_kQMeanLag2Lo; mean_val3 = WebRtcIsac_kQMeanLag3Lo; mean_val4 = WebRtcIsac_kQMeanLag4Lo; lower_limit = WebRtcIsac_kQIndexLowerLimitLagLo; upper_limit = WebRtcIsac_kQIndexUpperLimitLagLo; } else if (mean_gain < 0.4) { StepSize = WebRtcIsac_kQPitchLagStepsizeMid; cdf = WebRtcIsac_kQPitchLagCdfPtrMid; mean_val2 = WebRtcIsac_kQMeanLag2Mid; mean_val3 = WebRtcIsac_kQMeanLag3Mid; mean_val4 = WebRtcIsac_kQMeanLag4Mid; lower_limit = WebRtcIsac_kQIndexLowerLimitLagMid; upper_limit = WebRtcIsac_kQIndexUpperLimitLagMid; } else { StepSize = WebRtcIsac_kQPitchLagStepsizeHi; cdf = WebRtcIsac_kQPitchLagCdfPtrHi; mean_val2 = WebRtcIsac_kQMeanLag2Hi; mean_val3 = WebRtcIsac_kQMeanLag3Hi; mean_val4 = WebRtcIsac_kQMeanLag4Hi; lower_limit = WebRtcIsac_kQindexLowerLimitLagHi; upper_limit = WebRtcIsac_kQindexUpperLimitLagHi; } /* find quantization index */ for (k = 0; k < 4; k++) { /* transform */ C = 0.0; for (j = 0; j < PITCH_SUBFRAMES; j++) { C += WebRtcIsac_kTransform[k][j] * PitchLags[j]; } /* quantize */ index[k] = WebRtcIsac_lrint(C / StepSize); /* check that the index is not outside the boundaries of the table */ if (index[k] < lower_limit[k]) { index[k] = lower_limit[k]; } else if (index[k] > upper_limit[k]) index[k] = upper_limit[k]; { index[k] -= lower_limit[k]; } /* Save data for creation of multiple bit streams */ encData->pitchIndex[PITCH_SUBFRAMES * encData->startIdx + k] = index[k]; } /* Un-quantize back to transform coefficients and do the inverse transform: * S = T'*C */ C = (index[0] + lower_limit[0]) * StepSize; for (k = 0; k < PITCH_SUBFRAMES; k++) { PitchLags[k] = WebRtcIsac_kTransformTranspose[k][0] * C; } C = mean_val2[index[1]]; for (k = 0; k < PITCH_SUBFRAMES; k++) { PitchLags[k] += WebRtcIsac_kTransformTranspose[k][1] * C; } C = mean_val3[index[2]]; for (k = 0; k < PITCH_SUBFRAMES; k++) { PitchLags[k] += WebRtcIsac_kTransformTranspose[k][2] * C; } C = mean_val4[index[3]]; for (k = 0; k < PITCH_SUBFRAMES; k++) { PitchLags[k] += WebRtcIsac_kTransformTranspose[k][3] * C; } /* entropy coding of quantization pitch lags */ WebRtcIsac_EncHistMulti(streamdata, index, cdf, PITCH_SUBFRAMES); } /* Routines for in-band signaling of bandwidth estimation */ /* Histograms based on uniform distribution of indices */ /* Move global variables later! */ /* cdf array for frame length indicator */ const uint16_t WebRtcIsac_kFrameLengthCdf[4] = { 0, 21845, 43690, 65535 }; /* pointer to cdf array for frame length indicator */ const uint16_t* WebRtcIsac_kFrameLengthCdf_ptr[1] = { WebRtcIsac_kFrameLengthCdf }; /* initial cdf index for decoder of frame length indicator */ const uint16_t WebRtcIsac_kFrameLengthInitIndex[1] = { 1 }; int WebRtcIsac_DecodeFrameLen(Bitstr* streamdata, int16_t* framesamples) { int frame_mode, err; err = 0; /* entropy decoding of frame length [1:30ms,2:60ms] */ err = WebRtcIsac_DecHistOneStepMulti(&frame_mode, streamdata, WebRtcIsac_kFrameLengthCdf_ptr, WebRtcIsac_kFrameLengthInitIndex, 1); if (err < 0) return -ISAC_RANGE_ERROR_DECODE_FRAME_LENGTH; switch (frame_mode) { case 1: *framesamples = 480; /* 30ms */ break; case 2: *framesamples = 960; /* 60ms */ break; default: err = -ISAC_DISALLOWED_FRAME_MODE_DECODER; } return err; } int WebRtcIsac_EncodeFrameLen(int16_t framesamples, Bitstr* streamdata) { int frame_mode, status; status = 0; frame_mode = 0; /* entropy coding of frame length [1:480 samples,2:960 samples] */ switch (framesamples) { case 480: frame_mode = 1; break; case 960: frame_mode = 2; break; default: status = - ISAC_DISALLOWED_FRAME_MODE_ENCODER; } if (status < 0) return status; WebRtcIsac_EncHistMulti(streamdata, &frame_mode, WebRtcIsac_kFrameLengthCdf_ptr, 1); return status; } /* cdf array for estimated bandwidth */ static const uint16_t kBwCdf[25] = { 0, 2731, 5461, 8192, 10923, 13653, 16384, 19114, 21845, 24576, 27306, 30037, 32768, 35498, 38229, 40959, 43690, 46421, 49151, 51882, 54613, 57343, 60074, 62804, 65535 }; /* pointer to cdf array for estimated bandwidth */ static const uint16_t* const kBwCdfPtr[1] = { kBwCdf }; /* initial cdf index for decoder of estimated bandwidth*/ static const uint16_t kBwInitIndex[1] = { 7 }; int WebRtcIsac_DecodeSendBW(Bitstr* streamdata, int16_t* BWno) { int BWno32, err; /* entropy decoding of sender's BW estimation [0..23] */ err = WebRtcIsac_DecHistOneStepMulti(&BWno32, streamdata, kBwCdfPtr, kBwInitIndex, 1); if (err < 0) { return -ISAC_RANGE_ERROR_DECODE_BANDWIDTH; } *BWno = (int16_t)BWno32; return err; } void WebRtcIsac_EncodeReceiveBw(int* BWno, Bitstr* streamdata) { /* entropy encoding of receiver's BW estimation [0..23] */ WebRtcIsac_EncHistMulti(streamdata, BWno, kBwCdfPtr, 1); } /* estimate code length of LPC Coef */ void WebRtcIsac_TranscodeLPCCoef(double* LPCCoef_lo, double* LPCCoef_hi, int* index_g) { int j, k, n, pos, pos2, posg, offsg, offs2; int index_ovr_g[KLT_ORDER_GAIN]; double tmpcoeffs_g[KLT_ORDER_GAIN]; double tmpcoeffs2_g[KLT_ORDER_GAIN]; double sum; /* log gains, mean removal and scaling */ posg = 0; for (k = 0; k < SUBFRAMES; k++) { tmpcoeffs_g[posg] = log(LPCCoef_lo[(LPC_LOBAND_ORDER + 1) * k]); tmpcoeffs_g[posg] -= WebRtcIsac_kLpcMeansGain[posg]; tmpcoeffs_g[posg] *= LPC_GAIN_SCALE; posg++; tmpcoeffs_g[posg] = log(LPCCoef_hi[(LPC_HIBAND_ORDER + 1) * k]); tmpcoeffs_g[posg] -= WebRtcIsac_kLpcMeansGain[posg]; tmpcoeffs_g[posg] *= LPC_GAIN_SCALE; posg++; } /* KLT */ /* Left transform. */ offsg = 0; for (j = 0; j < SUBFRAMES; j++) { posg = offsg; for (k = 0; k < LPC_GAIN_ORDER; k++) { sum = 0; pos = offsg; pos2 = k; for (n = 0; n < LPC_GAIN_ORDER; n++) { sum += tmpcoeffs_g[pos++] * WebRtcIsac_kKltT1Gain[pos2]; pos2 += LPC_GAIN_ORDER; } tmpcoeffs2_g[posg++] = sum; } offsg += LPC_GAIN_ORDER; } /* Right transform. */ offsg = 0; offs2 = 0; for (j = 0; j < SUBFRAMES; j++) { posg = offsg; for (k = 0; k < LPC_GAIN_ORDER; k++) { sum = 0; pos = k; pos2 = offs2; for (n = 0; n < SUBFRAMES; n++) { sum += tmpcoeffs2_g[pos] * WebRtcIsac_kKltT2Gain[pos2++]; pos += LPC_GAIN_ORDER; } tmpcoeffs_g[posg++] = sum; } offs2 += SUBFRAMES; offsg += LPC_GAIN_ORDER; } /* quantize coefficients */ for (k = 0; k < KLT_ORDER_GAIN; k++) { /* Get index. */ pos2 = WebRtcIsac_lrint(tmpcoeffs_g[k] / KLT_STEPSIZE); index_g[k] = (pos2) + WebRtcIsac_kQKltQuantMinGain[k]; if (index_g[k] < 0) { index_g[k] = 0; } else if (index_g[k] > WebRtcIsac_kQKltMaxIndGain[k]) { index_g[k] = WebRtcIsac_kQKltMaxIndGain[k]; } index_ovr_g[k] = WebRtcIsac_kQKltOffsetGain[k] + index_g[k]; /* find quantization levels for coefficients */ tmpcoeffs_g[k] = WebRtcIsac_kQKltLevelsGain[index_ovr_g[k]]; } } /* Decode & de-quantize LPC Coefficients. */ int WebRtcIsac_DecodeLpcCoefUB(Bitstr* streamdata, double* lpcVecs, double* percepFilterGains, int16_t bandwidth) { int index_s[KLT_ORDER_SHAPE]; double U[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; int err; /* Entropy decoding of quantization indices. */ switch (bandwidth) { case isac12kHz: { err = WebRtcIsac_DecHistOneStepMulti( index_s, streamdata, WebRtcIsac_kLpcShapeCdfMatUb12, WebRtcIsac_kLpcShapeEntropySearchUb12, UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME); break; } case isac16kHz: { err = WebRtcIsac_DecHistOneStepMulti( index_s, streamdata, WebRtcIsac_kLpcShapeCdfMatUb16, WebRtcIsac_kLpcShapeEntropySearchUb16, UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME); break; } default: return -1; } if (err < 0) { return err; } WebRtcIsac_DequantizeLpcParam(index_s, lpcVecs, bandwidth); WebRtcIsac_CorrelateInterVec(lpcVecs, U, bandwidth); WebRtcIsac_CorrelateIntraVec(U, lpcVecs, bandwidth); WebRtcIsac_AddLarMean(lpcVecs, bandwidth); WebRtcIsac_DecodeLpcGainUb(percepFilterGains, streamdata); if (bandwidth == isac16kHz) { /* Decode another set of Gains. */ WebRtcIsac_DecodeLpcGainUb(&percepFilterGains[SUBFRAMES], streamdata); } return 0; } int16_t WebRtcIsac_EncodeBandwidth(enum ISACBandwidth bandwidth, Bitstr* streamData) { int bandwidthMode; switch (bandwidth) { case isac12kHz: { bandwidthMode = 0; break; } case isac16kHz: { bandwidthMode = 1; break; } default: return -ISAC_DISALLOWED_ENCODER_BANDWIDTH; } WebRtcIsac_EncHistMulti(streamData, &bandwidthMode, kOneBitEqualProbCdf_ptr, 1); return 0; } int16_t WebRtcIsac_DecodeBandwidth(Bitstr* streamData, enum ISACBandwidth* bandwidth) { int bandwidthMode; if (WebRtcIsac_DecHistOneStepMulti(&bandwidthMode, streamData, kOneBitEqualProbCdf_ptr, kOneBitEqualProbInitIndex, 1) < 0) { return -ISAC_RANGE_ERROR_DECODE_BANDWITH; } switch (bandwidthMode) { case 0: { *bandwidth = isac12kHz; break; } case 1: { *bandwidth = isac16kHz; break; } default: return -ISAC_DISALLOWED_BANDWIDTH_MODE_DECODER; } return 0; } int16_t WebRtcIsac_EncodeJitterInfo(int32_t jitterIndex, Bitstr* streamData) { /* This is to avoid LINUX warning until we change 'int' to 'Word32'. */ int intVar; if ((jitterIndex < 0) || (jitterIndex > 1)) { return -1; } intVar = (int)(jitterIndex); /* Use the same CDF table as for bandwidth * both take two values with equal probability.*/ WebRtcIsac_EncHistMulti(streamData, &intVar, kOneBitEqualProbCdf_ptr, 1); return 0; } int16_t WebRtcIsac_DecodeJitterInfo(Bitstr* streamData, int32_t* jitterInfo) { int intVar; /* Use the same CDF table as for bandwidth * both take two values with equal probability. */ if (WebRtcIsac_DecHistOneStepMulti(&intVar, streamData, kOneBitEqualProbCdf_ptr, kOneBitEqualProbInitIndex, 1) < 0) { return -ISAC_RANGE_ERROR_DECODE_BANDWITH; } *jitterInfo = (int16_t)(intVar); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/entropy_coding.h0000664000175000017500000003450414475643423032055 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * entropy_coding.h * * This header file declares all of the functions used to arithmetically * encode the iSAC bistream * */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_ #include "modules/audio_coding/codecs/isac/main/source/settings.h" #include "modules/audio_coding/codecs/isac/main/source/structs.h" /****************************************************************************** * WebRtcIsac_DecodeSpec() * Decode real and imaginary part of the DFT coefficients, given a bit-stream. * The decoded DFT coefficient can be transformed to time domain by * WebRtcIsac_Time2Spec(). * * Input: * - streamdata : pointer to a stucture containg the encoded * data and theparameters needed for entropy * coding. * - AvgPitchGain_Q12 : average pitch-gain of the frame. This is only * relevant for 0-4 kHz band, and the input value is * not used in other bands. * - band : specifies which band's DFT should be decoded. * * Output: * - *fr : pointer to a buffer where the real part of DFT * coefficients are written to. * - *fi : pointer to a buffer where the imaginary part * of DFT coefficients are written to. * * Return value : < 0 if an error occures * 0 if succeeded. */ int WebRtcIsac_DecodeSpec(Bitstr* streamdata, int16_t AvgPitchGain_Q12, enum ISACBand band, double* fr, double* fi); /****************************************************************************** * WebRtcIsac_EncodeSpec() * Encode real and imaginary part of the DFT coefficients into the given * bit-stream. * * Input: * - *fr : pointer to a buffer where the real part of DFT * coefficients are written to. * - *fi : pointer to a buffer where the imaginary part * of DFT coefficients are written to. * - AvgPitchGain_Q12 : average pitch-gain of the frame. This is only * relevant for 0-4 kHz band, and the input value is * not used in other bands. * - band : specifies which band's DFT should be decoded. * * Output: * - streamdata : pointer to a stucture containg the encoded * data and theparameters needed for entropy * coding. * * Return value : < 0 if an error occures * 0 if succeeded. */ int WebRtcIsac_EncodeSpec(const int16_t* fr, const int16_t* fi, int16_t AvgPitchGain_Q12, enum ISACBand band, Bitstr* streamdata); /* decode & dequantize LPC Coef */ int WebRtcIsac_DecodeLpcCoef(Bitstr* streamdata, double* LPCCoef); int WebRtcIsac_DecodeLpcCoefUB(Bitstr* streamdata, double* lpcVecs, double* percepFilterGains, int16_t bandwidth); int WebRtcIsac_DecodeLpc(Bitstr* streamdata, double* LPCCoef_lo, double* LPCCoef_hi); /* quantize & code LPC Coef */ void WebRtcIsac_EncodeLpcLb(double* LPCCoef_lo, double* LPCCoef_hi, Bitstr* streamdata, IsacSaveEncoderData* encData); void WebRtcIsac_EncodeLpcGainLb(double* LPCCoef_lo, double* LPCCoef_hi, Bitstr* streamdata, IsacSaveEncoderData* encData); /****************************************************************************** * WebRtcIsac_EncodeLpcUB() * Encode LPC parameters, given as A-polynomial, of upper-band. The encoding * is performed in LAR domain. * For the upper-band, we compute and encode LPC of some sub-frames, LPC of * other sub-frames are computed by linear interpolation, in LAR domain. This * function performs the interpolation and returns the LPC of all sub-frames. * * Inputs: * - lpcCoef : a buffer containing A-polynomials of sub-frames * (excluding first coefficient that is 1). * - bandwidth : specifies if the codec is operating at 0-12 kHz * or 0-16 kHz mode. * * Input/output: * - streamdata : pointer to a structure containing the encoded * data and the parameters needed for entropy * coding. * * Output: * - interpolLPCCoeff : Decoded and interpolated LPC (A-polynomial) * of all sub-frames. * If LP analysis is of order K, and there are N * sub-frames then this is a buffer of size * (k + 1) * N, each vector starts with the LPC gain * of the corresponding sub-frame. The LPC gains * are encoded and inserted after this function is * called. The first A-coefficient which is 1 is not * included. * * Return value : 0 if encoding is successful, * <0 if failed to encode. */ int16_t WebRtcIsac_EncodeLpcUB(double* lpcCoeff, Bitstr* streamdata, double* interpolLPCCoeff, int16_t bandwidth, ISACUBSaveEncDataStruct* encData); /****************************************************************************** * WebRtcIsac_DecodeInterpolLpcUb() * Decode LPC coefficients and interpolate to get the coefficients fo all * sub-frmaes. * * Inputs: * - bandwidth : spepecifies if the codec is in 0-12 kHz or * 0-16 kHz mode. * * Input/output: * - streamdata : pointer to a stucture containg the encoded * data and theparameters needed for entropy * coding. * * Output: * - percepFilterParam : Decoded and interpolated LPC (A-polynomial) of * all sub-frames. * If LP analysis is of order K, and there are N * sub-frames then this is a buffer of size * (k + 1) * N, each vector starts with the LPC gain * of the corresponding sub-frame. The LPC gains * are encoded and inserted after this function is * called. The first A-coefficient which is 1 is not * included. * * Return value : 0 if encoding is successful, * <0 if failed to encode. */ int16_t WebRtcIsac_DecodeInterpolLpcUb(Bitstr* streamdata, double* percepFilterParam, int16_t bandwidth); /* Decode & dequantize RC */ int WebRtcIsac_DecodeRc(Bitstr* streamdata, int16_t* RCQ15); /* Quantize & code RC */ void WebRtcIsac_EncodeRc(int16_t* RCQ15, Bitstr* streamdata); /* Decode & dequantize squared Gain */ int WebRtcIsac_DecodeGain2(Bitstr* streamdata, int32_t* Gain2); /* Quantize & code squared Gain (input is squared gain) */ int WebRtcIsac_EncodeGain2(int32_t* gain2, Bitstr* streamdata); void WebRtcIsac_EncodePitchGain(int16_t* PitchGains_Q12, Bitstr* streamdata, IsacSaveEncoderData* encData); void WebRtcIsac_EncodePitchLag(double* PitchLags, int16_t* PitchGain_Q12, Bitstr* streamdata, IsacSaveEncoderData* encData); int WebRtcIsac_DecodePitchGain(Bitstr* streamdata, int16_t* PitchGain_Q12); int WebRtcIsac_DecodePitchLag(Bitstr* streamdata, int16_t* PitchGain_Q12, double* PitchLag); int WebRtcIsac_DecodeFrameLen(Bitstr* streamdata, int16_t* framelength); int WebRtcIsac_EncodeFrameLen(int16_t framelength, Bitstr* streamdata); int WebRtcIsac_DecodeSendBW(Bitstr* streamdata, int16_t* BWno); void WebRtcIsac_EncodeReceiveBw(int* BWno, Bitstr* streamdata); /* Step-down */ void WebRtcIsac_Poly2Rc(double* a, int N, double* RC); /* Step-up */ void WebRtcIsac_Rc2Poly(double* RC, int N, double* a); void WebRtcIsac_TranscodeLPCCoef(double* LPCCoef_lo, double* LPCCoef_hi, int* index_g); /****************************************************************************** * WebRtcIsac_EncodeLpcGainUb() * Encode LPC gains of sub-Frames. * * Input/outputs: * - lpGains : a buffer which contains 'SUBFRAME' number of * LP gains to be encoded. The input values are * overwritten by the quantized values. * - streamdata : pointer to a stucture containg the encoded * data and theparameters needed for entropy * coding. * * Output: * - lpcGainIndex : quantization indices for lpc gains, these will * be stored to be used for FEC. */ void WebRtcIsac_EncodeLpcGainUb(double* lpGains, Bitstr* streamdata, int* lpcGainIndex); /****************************************************************************** * WebRtcIsac_EncodeLpcGainUb() * Store LPC gains of sub-Frames in 'streamdata'. * * Input: * - lpGains : a buffer which contains 'SUBFRAME' number of * LP gains to be encoded. * Input/outputs: * - streamdata : pointer to a stucture containg the encoded * data and theparameters needed for entropy * coding. * */ void WebRtcIsac_StoreLpcGainUb(double* lpGains, Bitstr* streamdata); /****************************************************************************** * WebRtcIsac_DecodeLpcGainUb() * Decode the LPC gain of sub-frames. * * Input/output: * - streamdata : pointer to a stucture containg the encoded * data and theparameters needed for entropy * coding. * * Output: * - lpGains : a buffer where decoded LPC gians will be stored. * * Return value : 0 if succeeded. * <0 if failed. */ int16_t WebRtcIsac_DecodeLpcGainUb(double* lpGains, Bitstr* streamdata); /****************************************************************************** * WebRtcIsac_EncodeBandwidth() * Encode if the bandwidth of encoded audio is 0-12 kHz or 0-16 kHz. * * Input: * - bandwidth : an enumerator specifying if the codec in is * 0-12 kHz or 0-16 kHz mode. * * Input/output: * - streamdata : pointer to a stucture containg the encoded * data and theparameters needed for entropy * coding. * * Return value : 0 if succeeded. * <0 if failed. */ int16_t WebRtcIsac_EncodeBandwidth(enum ISACBandwidth bandwidth, Bitstr* streamData); /****************************************************************************** * WebRtcIsac_DecodeBandwidth() * Decode the bandwidth of the encoded audio, i.e. if the bandwidth is 0-12 kHz * or 0-16 kHz. * * Input/output: * - streamdata : pointer to a stucture containg the encoded * data and theparameters needed for entropy * coding. * * Output: * - bandwidth : an enumerator specifying if the codec is in * 0-12 kHz or 0-16 kHz mode. * * Return value : 0 if succeeded. * <0 if failed. */ int16_t WebRtcIsac_DecodeBandwidth(Bitstr* streamData, enum ISACBandwidth* bandwidth); /****************************************************************************** * WebRtcIsac_EncodeJitterInfo() * Decode the jitter information. * * Input/output: * - streamdata : pointer to a stucture containg the encoded * data and theparameters needed for entropy * coding. * * Input: * - jitterInfo : one bit of info specifying if the channel is * in high/low jitter. Zero indicates low jitter * and one indicates high jitter. * * Return value : 0 if succeeded. * <0 if failed. */ int16_t WebRtcIsac_EncodeJitterInfo(int32_t jitterIndex, Bitstr* streamData); /****************************************************************************** * WebRtcIsac_DecodeJitterInfo() * Decode the jitter information. * * Input/output: * - streamdata : pointer to a stucture containg the encoded * data and theparameters needed for entropy * coding. * * Output: * - jitterInfo : one bit of info specifying if the channel is * in high/low jitter. Zero indicates low jitter * and one indicates high jitter. * * Return value : 0 if succeeded. * <0 if failed. */ int16_t WebRtcIsac_DecodeJitterInfo(Bitstr* streamData, int32_t* jitterInfo); #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/filter_functions.c0000664000175000017500000001314714475643423032402 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include #include #ifdef WEBRTC_ANDROID #include #endif #include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h" #include "modules/audio_coding/codecs/isac/main/source/isac_vad.h" static void WebRtcIsac_AllPoleFilter(double* InOut, double* Coef, size_t lengthInOut, int orderCoef) { /* the state of filter is assumed to be in InOut[-1] to InOut[-orderCoef] */ double scal; double sum; size_t n; int k; //if (fabs(Coef[0]-1.0)<0.001) { if ( (Coef[0] > 0.9999) && (Coef[0] < 1.0001) ) { for(n = 0; n < lengthInOut; n++) { sum = Coef[1] * InOut[-1]; for(k = 2; k <= orderCoef; k++){ sum += Coef[k] * InOut[-k]; } *InOut++ -= sum; } } else { scal = 1.0 / Coef[0]; for(n=0;nbuffer, sizeof(double) * PITCH_WLPCBUFLEN); memcpy(tmpbuffer+PITCH_WLPCBUFLEN, in, sizeof(double) * PITCH_FRAME_LEN); memcpy(wfdata->buffer, tmpbuffer+PITCH_FRAME_LEN, sizeof(double) * PITCH_WLPCBUFLEN); dp=weoutbuf; dp2=whoutbuf; for (k=0;kweostate[k]; *dp2++ = wfdata->whostate[k]; opol[k]=0.0; } opol[0]=1.0; opol[PITCH_WLPCORDER]=0.0; weo=dp; who=dp2; endpos=PITCH_WLPCBUFLEN + PITCH_SUBFRAME_LEN; inp=tmpbuffer + PITCH_WLPCBUFLEN; for (n=0; nwindow[k]*tmpbuffer[start+k]; } /* Get LPC polynomial */ WebRtcIsac_AutoCorr(corr, ext, PITCH_WLPCWINLEN, PITCH_WLPCORDER); corr[0]=1.01*corr[0]+1.0; /* White noise correction */ WebRtcIsac_LevDurb(apol, rc, corr, PITCH_WLPCORDER); WebRtcIsac_BwExpand(apolr, apol, rho, PITCH_WLPCORDER+1); /* Filtering */ WebRtcIsac_ZeroPoleFilter(inp, apol, apolr, PITCH_SUBFRAME_LEN, PITCH_WLPCORDER, weo); WebRtcIsac_ZeroPoleFilter(inp, apolr, opol, PITCH_SUBFRAME_LEN, PITCH_WLPCORDER, who); inp+=PITCH_SUBFRAME_LEN; endpos+=PITCH_SUBFRAME_LEN; weo+=PITCH_SUBFRAME_LEN; who+=PITCH_SUBFRAME_LEN; } /* Export filter states */ for (k=0;kweostate[k]=weoutbuf[PITCH_FRAME_LEN+k]; wfdata->whostate[k]=whoutbuf[PITCH_FRAME_LEN+k]; } /* Export output data */ memcpy(weiout, weoutbuf+PITCH_WLPCORDER, sizeof(double) * PITCH_FRAME_LEN); memcpy(whiout, whoutbuf+PITCH_WLPCORDER, sizeof(double) * PITCH_FRAME_LEN); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/filter_functions.h0000664000175000017500000000173214475643423032404 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTER_FUNCTIONS_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTER_FUNCTIONS_H_ #include "modules/audio_coding/codecs/isac/main/source/structs.h" void WebRtcIsac_AutoCorr(double* r, const double* x, size_t N, size_t order); void WebRtcIsac_WeightingFilter(const double* in, double* weiout, double* whiout, WeightFiltstr* wfdata); #endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTER_FUNCTIONS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/filterbanks.c0000664000175000017500000001130514475643423031323 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * filterbanks.c * * This file contains function WebRtcIsac_AllPassFilter2Float, * WebRtcIsac_SplitAndFilter, and WebRtcIsac_FilterAndCombine * which implement filterbanks that produce decimated lowpass and * highpass versions of a signal, and performs reconstruction. * */ #include "modules/audio_coding/codecs/isac/main/source/settings.h" #include "modules/audio_coding/codecs/isac/main/source/codec.h" #include "modules/audio_coding/codecs/isac/main/source/isac_vad.h" /* Combining */ /* HPstcoeff_out_1 = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; */ static const float kHpStCoefOut1Float[4] = {-1.99701049409000f, 0.99714204490000f, 0.01701049409000f, -0.01704204490000f}; /* HPstcoeff_out_2 = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; */ static const float kHpStCoefOut2Float[4] = {-1.98645294509837f, 0.98672435560000f, 0.00645294509837f, -0.00662435560000f}; /* Function WebRtcIsac_FilterAndCombine */ /* This is a decoder function that takes the decimated length FRAMESAMPLES_HALF input low-pass and high-pass signals and creates a reconstructed fullband output signal of length FRAMESAMPLES. WebRtcIsac_FilterAndCombine is the sibling function of WebRtcIsac_SplitAndFilter */ /* INPUTS: inLP: a length FRAMESAMPLES_HALF array of input low-pass samples. inHP: a length FRAMESAMPLES_HALF array of input high-pass samples. postfiltdata: input data structure containing the filterbank states from the previous decoding iteration. OUTPUTS: Out: a length FRAMESAMPLES array of output reconstructed samples (fullband) based on the input low-pass and high-pass signals. postfiltdata: the input data structure containing the filterbank states is updated for the next decoding iteration */ void WebRtcIsac_FilterAndCombineFloat(float *InLP, float *InHP, float *Out, PostFiltBankstr *postfiltdata) { int k; float tempin_ch1[FRAMESAMPLES+MAX_AR_MODEL_ORDER]; float tempin_ch2[FRAMESAMPLES+MAX_AR_MODEL_ORDER]; float ftmp, ftmp2; /* Form the polyphase signals*/ for (k=0;kSTATE_0_UPPER_float); /* Now, all-pass filter the new lower channel signal. But since all-pass filter factors at the decoder are swapped from the ones at the encoder, the 'upper' channel all-pass filter factors (WebRtcIsac_kUpperApFactorsFloat) are used to filter this new lower channel signal */ WebRtcIsac_AllPassFilter2Float(tempin_ch2, WebRtcIsac_kUpperApFactorsFloat, FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS,postfiltdata->STATE_0_LOWER_float); /* Merge outputs to form the full length output signal.*/ for (k=0;kHPstates1_float[0] + kHpStCoefOut1Float[3] * postfiltdata->HPstates1_float[1]; ftmp = Out[k] - kHpStCoefOut1Float[0] * postfiltdata->HPstates1_float[0] - kHpStCoefOut1Float[1] * postfiltdata->HPstates1_float[1]; postfiltdata->HPstates1_float[1] = postfiltdata->HPstates1_float[0]; postfiltdata->HPstates1_float[0] = ftmp; Out[k] = ftmp2; } for (k=0;kHPstates2_float[0] + kHpStCoefOut2Float[3] * postfiltdata->HPstates2_float[1]; ftmp = Out[k] - kHpStCoefOut2Float[0] * postfiltdata->HPstates2_float[0] - kHpStCoefOut2Float[1] * postfiltdata->HPstates2_float[1]; postfiltdata->HPstates2_float[1] = postfiltdata->HPstates2_float[0]; postfiltdata->HPstates2_float[0] = ftmp; Out[k] = ftmp2; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/intialize.c0000664000175000017500000000373414475643423031016 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* encode.c - Encoding function for the iSAC coder */ #include #include "modules/audio_coding/codecs/isac/main/source/structs.h" #include "modules/audio_coding/codecs/isac/main/source/codec.h" #include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h" void WebRtcIsac_InitMasking(MaskFiltstr *maskdata) { int k; for (k = 0; k < WINLEN; k++) { maskdata->DataBufferLo[k] = 0.0; maskdata->DataBufferHi[k] = 0.0; } for (k = 0; k < ORDERLO+1; k++) { maskdata->CorrBufLo[k] = 0.0; maskdata->PreStateLoF[k] = 0.0; maskdata->PreStateLoG[k] = 0.0; maskdata->PostStateLoF[k] = 0.0; maskdata->PostStateLoG[k] = 0.0; } for (k = 0; k < ORDERHI+1; k++) { maskdata->CorrBufHi[k] = 0.0; maskdata->PreStateHiF[k] = 0.0; maskdata->PreStateHiG[k] = 0.0; maskdata->PostStateHiF[k] = 0.0; maskdata->PostStateHiG[k] = 0.0; } maskdata->OldEnergy = 10.0; return; } void WebRtcIsac_InitPostFilterbank(PostFiltBankstr *postfiltdata) { int k; for (k = 0; k < 2*POSTQORDER; k++) { postfiltdata->STATE_0_LOWER[k] = 0; postfiltdata->STATE_0_UPPER[k] = 0; postfiltdata->STATE_0_LOWER_float[k] = 0; postfiltdata->STATE_0_UPPER_float[k] = 0; } /* High pass filter states */ postfiltdata->HPstates1[0] = 0.0; postfiltdata->HPstates1[1] = 0.0; postfiltdata->HPstates2[0] = 0.0; postfiltdata->HPstates2[1] = 0.0; postfiltdata->HPstates1_float[0] = 0.0f; postfiltdata->HPstates1_float[1] = 0.0f; postfiltdata->HPstates2_float[0] = 0.0f; postfiltdata->HPstates2_float[1] = 0.0f; return; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/isac.c0000664000175000017500000023607314475643423027751 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * isac.c * * This C file contains the functions for the ISAC API * */ #include "modules/audio_coding/codecs/isac/main/include/isac.h" #include #include #include #include #include "rtc_base/checks.h" #include "common_audio/signal_processing/include/signal_processing_library.h" #include "modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h" #include "modules/audio_coding/codecs/isac/main/source/codec.h" #include "modules/audio_coding/codecs/isac/main/source/crc.h" #include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h" #include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h" #include "modules/audio_coding/codecs/isac/main/source/os_specific_inline.h" #include "modules/audio_coding/codecs/isac/main/source/structs.h" #include "modules/audio_coding/codecs/isac/main/source/isac_vad.h" #include "rtc_base/system/arch.h" #define BIT_MASK_DEC_INIT 0x0001 #define BIT_MASK_ENC_INIT 0x0002 #define LEN_CHECK_SUM_WORD8 4 #define MAX_NUM_LAYERS 10 /**************************************************************************** * UpdatePayloadSizeLimit(...) * * Call this function to update the limit on the payload size. The limit on * payload size might change i) if a user ''directly changes the limit by * calling xxx_setMaxPayloadSize() or xxx_setMaxRate(), or ii) indirectly * when bandwidth is changing. The latter might be the result of bandwidth * adaptation, or direct change of the bottleneck in instantaneous mode. * * This function takes the current overall limit on payload, and translates it * to the limits on lower and upper-band. If the codec is in wideband mode, * then the overall limit and the limit on the lower-band is the same. * Otherwise, a fraction of the limit should be allocated to lower-band * leaving some room for the upper-band bit-stream. That is why an update * of limit is required every time that the bandwidth is changing. * */ static void UpdatePayloadSizeLimit(ISACMainStruct* instISAC) { int16_t lim30MsPayloadBytes = WEBRTC_SPL_MIN( (instISAC->maxPayloadSizeBytes), (instISAC->maxRateBytesPer30Ms)); int16_t lim60MsPayloadBytes = WEBRTC_SPL_MIN( (instISAC->maxPayloadSizeBytes), (instISAC->maxRateBytesPer30Ms << 1)); /* The only time that iSAC will have 60 ms * frame-size is when operating in wideband, so * there is no upper-band bit-stream. */ if (instISAC->bandwidthKHz == isac8kHz) { /* At 8 kHz there is no upper-band bit-stream, * therefore, the lower-band limit is the overall limit. */ instISAC->instLB.ISACencLB_obj.payloadLimitBytes60 = lim60MsPayloadBytes; instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 = lim30MsPayloadBytes; } else { /* When in super-wideband, we only have 30 ms frames. * Do a rate allocation for the given limit. */ if (lim30MsPayloadBytes > 250) { /* 4/5 to lower-band the rest for upper-band. */ instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 = (lim30MsPayloadBytes << 2) / 5; } else if (lim30MsPayloadBytes > 200) { /* For the interval of 200 to 250 the share of * upper-band linearly grows from 20 to 50. */ instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 = (lim30MsPayloadBytes << 1) / 5 + 100; } else { /* Allocate only 20 for upper-band. */ instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 = lim30MsPayloadBytes - 20; } instISAC->instUB.ISACencUB_obj.maxPayloadSizeBytes = lim30MsPayloadBytes; } } /**************************************************************************** * UpdateBottleneck(...) * * This function updates the bottleneck only if the codec is operating in * channel-adaptive mode. Furthermore, as the update of bottleneck might * result in an update of bandwidth, therefore, the bottlenech should be * updated just right before the first 10ms of a frame is pushed into encoder. * */ static void UpdateBottleneck(ISACMainStruct* instISAC) { /* Read the bottleneck from bandwidth estimator for the * first 10 ms audio. This way, if there is a change * in bandwidth, upper and lower-band will be in sync. */ if ((instISAC->codingMode == 0) && (instISAC->instLB.ISACencLB_obj.buffer_index == 0) && (instISAC->instLB.ISACencLB_obj.frame_nb == 0)) { int32_t bottleneck = WebRtcIsac_GetUplinkBandwidth(&instISAC->bwestimator_obj); /* Adding hysteresis when increasing signal bandwidth. */ if ((instISAC->bandwidthKHz == isac8kHz) && (bottleneck > 37000) && (bottleneck < 41000)) { bottleneck = 37000; } /* Switching from 12 kHz to 16 kHz is not allowed at this revision. * If we let this happen, we have to take care of buffer_index and * the last LPC vector. */ if ((instISAC->bandwidthKHz != isac16kHz) && (bottleneck > 46000)) { bottleneck = 46000; } /* We might need a rate allocation. */ if (instISAC->encoderSamplingRateKHz == kIsacWideband) { /* Wideband is the only choice we have here. */ instISAC->instLB.ISACencLB_obj.bottleneck = (bottleneck > 32000) ? 32000 : bottleneck; instISAC->bandwidthKHz = isac8kHz; } else { /* Do the rate-allocation and get the new bandwidth. */ enum ISACBandwidth bandwidth; WebRtcIsac_RateAllocation(bottleneck, &(instISAC->instLB.ISACencLB_obj.bottleneck), &(instISAC->instUB.ISACencUB_obj.bottleneck), &bandwidth); if (bandwidth != isac8kHz) { instISAC->instLB.ISACencLB_obj.new_framelength = 480; } if (bandwidth != instISAC->bandwidthKHz) { /* Bandwidth is changing. */ instISAC->bandwidthKHz = bandwidth; UpdatePayloadSizeLimit(instISAC); if (bandwidth == isac12kHz) { instISAC->instLB.ISACencLB_obj.buffer_index = 0; } /* Currently we don't let the bandwidth to switch to 16 kHz * if in adaptive mode. If we let this happen, we have to take * care of buffer_index and the last LPC vector. */ } } } } /**************************************************************************** * GetSendBandwidthInfo(...) * * This is called to get the bandwidth info. This info is the bandwidth and * the jitter of 'there-to-here' channel, estimated 'here.' These info * is signaled in an in-band fashion to the other side. * * The call to the bandwidth estimator triggers a recursive averaging which * has to be synchronized between encoder & decoder, therefore, the call to * BWE should be once per packet. As the BWE info is inserted into bit-stream * We need a valid info right before the encodeLB function is going to * generate a bit-stream. That is when lower-band buffer has already 20ms * of audio, and the 3rd block of 10ms is going to be injected into encoder. * * Inputs: * - instISAC : iSAC instance. * * Outputs: * - bandwidthIndex : an index which has to be encoded in * lower-band bit-stream, indicating the * bandwidth of there-to-here channel. * - jitterInfo : this indicates if the jitter is high * or low and it is encoded in upper-band * bit-stream. * */ static void GetSendBandwidthInfo(ISACMainStruct* instISAC, int16_t* bandwidthIndex, int16_t* jitterInfo) { if ((instISAC->instLB.ISACencLB_obj.buffer_index == (FRAMESAMPLES_10ms << 1)) && (instISAC->instLB.ISACencLB_obj.frame_nb == 0)) { /* Bandwidth estimation and coding. */ WebRtcIsac_GetDownlinkBwJitIndexImpl(&(instISAC->bwestimator_obj), bandwidthIndex, jitterInfo, instISAC->decoderSamplingRateKHz); } } /**************************************************************************** * WebRtcIsac_Create(...) * * This function creates an ISAC instance, which will contain the state * information for one coding/decoding channel. * * Input: * - ISAC_main_inst : address of the pointer to the coder instance. * * Return value : 0 - Ok * -1 - Error */ int16_t WebRtcIsac_Create(ISACStruct** ISAC_main_inst) { ISACMainStruct* instISAC; if (ISAC_main_inst != NULL) { instISAC = (ISACMainStruct*)malloc(sizeof(ISACMainStruct)); *ISAC_main_inst = (ISACStruct*)instISAC; if (*ISAC_main_inst != NULL) { instISAC->errorCode = 0; instISAC->initFlag = 0; /* Default is wideband. */ instISAC->bandwidthKHz = isac8kHz; instISAC->encoderSamplingRateKHz = kIsacWideband; instISAC->decoderSamplingRateKHz = kIsacWideband; instISAC->in_sample_rate_hz = 16000; WebRtcIsac_InitTransform(&instISAC->transform_tables); return 0; } else { return -1; } } else { return -1; } } /**************************************************************************** * WebRtcIsac_Free(...) * * This function frees the ISAC instance created at the beginning. * * Input: * - ISAC_main_inst : a ISAC instance. * * Return value : 0 - Ok * -1 - Error */ int16_t WebRtcIsac_Free(ISACStruct* ISAC_main_inst) { ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; free(instISAC); return 0; } /**************************************************************************** * EncoderInitLb(...) - internal function for initialization of * Lower Band * EncoderInitUb(...) - internal function for initialization of * Upper Band * WebRtcIsac_EncoderInit(...) - API function * * This function initializes a ISAC instance prior to the encoder calls. * * Input: * - ISAC_main_inst : ISAC instance. * - CodingMode : 0 -> Bit rate and frame length are automatically * adjusted to available bandwidth on * transmission channel, applicable just to * wideband mode. * 1 -> User sets a frame length and a target bit * rate which is taken as the maximum * short-term average bit rate. * * Return value : 0 - Ok * -1 - Error */ static int16_t EncoderInitLb(ISACLBStruct* instLB, int16_t codingMode, enum IsacSamplingRate sampRate) { int16_t statusInit = 0; int k; /* Init stream vector to zero */ for (k = 0; k < STREAM_SIZE_MAX_60; k++) { instLB->ISACencLB_obj.bitstr_obj.stream[k] = 0; } if ((codingMode == 1) || (sampRate == kIsacSuperWideband)) { /* 30 ms frame-size if either in super-wideband or * instantaneous mode (I-mode). */ instLB->ISACencLB_obj.new_framelength = 480; } else { instLB->ISACencLB_obj.new_framelength = INITIAL_FRAMESAMPLES; } WebRtcIsac_InitMasking(&instLB->ISACencLB_obj.maskfiltstr_obj); WebRtcIsac_InitPreFilterbank(&instLB->ISACencLB_obj.prefiltbankstr_obj); WebRtcIsac_InitPitchFilter(&instLB->ISACencLB_obj.pitchfiltstr_obj); WebRtcIsac_InitPitchAnalysis( &instLB->ISACencLB_obj.pitchanalysisstr_obj); instLB->ISACencLB_obj.buffer_index = 0; instLB->ISACencLB_obj.frame_nb = 0; /* Default for I-mode. */ instLB->ISACencLB_obj.bottleneck = 32000; instLB->ISACencLB_obj.current_framesamples = 0; instLB->ISACencLB_obj.s2nr = 0; instLB->ISACencLB_obj.payloadLimitBytes30 = STREAM_SIZE_MAX_30; instLB->ISACencLB_obj.payloadLimitBytes60 = STREAM_SIZE_MAX_60; instLB->ISACencLB_obj.maxPayloadBytes = STREAM_SIZE_MAX_60; instLB->ISACencLB_obj.maxRateInBytes = STREAM_SIZE_MAX_30; instLB->ISACencLB_obj.enforceFrameSize = 0; /* Invalid value prevents getRedPayload to run before encoder is called. */ instLB->ISACencLB_obj.lastBWIdx = -1; return statusInit; } static int16_t EncoderInitUb(ISACUBStruct* instUB, int16_t bandwidth) { int16_t statusInit = 0; int k; /* Init stream vector to zero. */ for (k = 0; k < STREAM_SIZE_MAX_60; k++) { instUB->ISACencUB_obj.bitstr_obj.stream[k] = 0; } WebRtcIsac_InitMasking(&instUB->ISACencUB_obj.maskfiltstr_obj); WebRtcIsac_InitPreFilterbank(&instUB->ISACencUB_obj.prefiltbankstr_obj); if (bandwidth == isac16kHz) { instUB->ISACencUB_obj.buffer_index = LB_TOTAL_DELAY_SAMPLES; } else { instUB->ISACencUB_obj.buffer_index = 0; } /* Default for I-mode. */ instUB->ISACencUB_obj.bottleneck = 32000; /* These store the limits for the wideband + super-wideband bit-stream. */ instUB->ISACencUB_obj.maxPayloadSizeBytes = STREAM_SIZE_MAX_30 << 1; /* This has to be updated after each lower-band encoding to guarantee * a correct payload-limitation. */ instUB->ISACencUB_obj.numBytesUsed = 0; memset(instUB->ISACencUB_obj.data_buffer_float, 0, (MAX_FRAMESAMPLES + LB_TOTAL_DELAY_SAMPLES) * sizeof(float)); memcpy(&(instUB->ISACencUB_obj.lastLPCVec), WebRtcIsac_kMeanLarUb16, sizeof(double) * UB_LPC_ORDER); return statusInit; } int16_t WebRtcIsac_EncoderInit(ISACStruct* ISAC_main_inst, int16_t codingMode) { ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; int16_t status; if ((codingMode != 0) && (codingMode != 1)) { instISAC->errorCode = ISAC_DISALLOWED_CODING_MODE; return -1; } /* Default bottleneck. */ instISAC->bottleneck = MAX_ISAC_BW; if (instISAC->encoderSamplingRateKHz == kIsacWideband) { instISAC->bandwidthKHz = isac8kHz; instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX_60; instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX_30; } else { instISAC->bandwidthKHz = isac16kHz; instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX; instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX; } /* Channel-adaptive = 0; Instantaneous (Channel-independent) = 1. */ instISAC->codingMode = codingMode; WebRtcIsac_InitBandwidthEstimator(&instISAC->bwestimator_obj, instISAC->encoderSamplingRateKHz, instISAC->decoderSamplingRateKHz); WebRtcIsac_InitRateModel(&instISAC->rate_data_obj); /* Default for I-mode. */ instISAC->MaxDelay = 10.0; status = EncoderInitLb(&instISAC->instLB, codingMode, instISAC->encoderSamplingRateKHz); if (status < 0) { instISAC->errorCode = -status; return -1; } if (instISAC->encoderSamplingRateKHz == kIsacSuperWideband) { /* Initialize encoder filter-bank. */ memset(instISAC->analysisFBState1, 0, FB_STATE_SIZE_WORD32 * sizeof(int32_t)); memset(instISAC->analysisFBState2, 0, FB_STATE_SIZE_WORD32 * sizeof(int32_t)); status = EncoderInitUb(&(instISAC->instUB), instISAC->bandwidthKHz); if (status < 0) { instISAC->errorCode = -status; return -1; } } /* Initialization is successful, set the flag. */ instISAC->initFlag |= BIT_MASK_ENC_INIT; return 0; } /**************************************************************************** * WebRtcIsac_Encode(...) * * This function encodes 10ms frame(s) and inserts it into a package. * Input speech length has to be 160 samples (10ms). The encoder buffers those * 10ms frames until it reaches the chosen Framesize (480 or 960 samples * corresponding to 30 or 60 ms frames), and then proceeds to the encoding. * * Input: * - ISAC_main_inst : ISAC instance. * - speechIn : input speech vector. * * Output: * - encoded : the encoded data vector * * Return value: * : >0 - Length (in bytes) of coded data * : 0 - The buffer didn't reach the chosen * frameSize so it keeps buffering speech * samples. * : -1 - Error */ int WebRtcIsac_Encode(ISACStruct* ISAC_main_inst, const int16_t* speechIn, uint8_t* encoded) { float inFrame[FRAMESAMPLES_10ms]; int16_t speechInLB[FRAMESAMPLES_10ms]; int16_t speechInUB[FRAMESAMPLES_10ms]; int streamLenLB = 0; int streamLenUB = 0; int streamLen = 0; size_t k = 0; uint8_t garbageLen = 0; int32_t bottleneck = 0; int16_t bottleneckIdx = 0; int16_t jitterInfo = 0; ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; ISACLBStruct* instLB = &(instISAC->instLB); ISACUBStruct* instUB = &(instISAC->instUB); /* Check if encoder initiated. */ if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; return -1; } if (instISAC->encoderSamplingRateKHz == kIsacSuperWideband) { WebRtcSpl_AnalysisQMF(speechIn, SWBFRAMESAMPLES_10ms, speechInLB, speechInUB, instISAC->analysisFBState1, instISAC->analysisFBState2); /* Convert from fixed to floating point. */ for (k = 0; k < FRAMESAMPLES_10ms; k++) { inFrame[k] = (float)speechInLB[k]; } } else { for (k = 0; k < FRAMESAMPLES_10ms; k++) { inFrame[k] = (float) speechIn[k]; } } /* Add some noise to avoid denormal numbers. */ inFrame[0] += (float)1.23455334e-3; inFrame[1] -= (float)2.04324239e-3; inFrame[2] += (float)1.90854954e-3; inFrame[9] += (float)1.84854878e-3; /* This function will update the bottleneck if required. */ UpdateBottleneck(instISAC); /* Get the bandwith information which has to be sent to the other side. */ GetSendBandwidthInfo(instISAC, &bottleneckIdx, &jitterInfo); /* Encode lower-band. */ streamLenLB = WebRtcIsac_EncodeLb(&instISAC->transform_tables, inFrame, &instLB->ISACencLB_obj, instISAC->codingMode, bottleneckIdx); if (streamLenLB < 0) { return -1; } if (instISAC->encoderSamplingRateKHz == kIsacSuperWideband) { instUB = &(instISAC->instUB); /* Convert to float. */ for (k = 0; k < FRAMESAMPLES_10ms; k++) { inFrame[k] = (float) speechInUB[k]; } /* Add some noise to avoid denormal numbers. */ inFrame[0] += (float)1.23455334e-3; inFrame[1] -= (float)2.04324239e-3; inFrame[2] += (float)1.90854954e-3; inFrame[9] += (float)1.84854878e-3; /* Tell to upper-band the number of bytes used so far. * This is for payload limitation. */ instUB->ISACencUB_obj.numBytesUsed = (int16_t)(streamLenLB + 1 + LEN_CHECK_SUM_WORD8); /* Encode upper-band. */ switch (instISAC->bandwidthKHz) { case isac12kHz: { streamLenUB = WebRtcIsac_EncodeUb12(&instISAC->transform_tables, inFrame, &instUB->ISACencUB_obj, jitterInfo); break; } case isac16kHz: { streamLenUB = WebRtcIsac_EncodeUb16(&instISAC->transform_tables, inFrame, &instUB->ISACencUB_obj, jitterInfo); break; } case isac8kHz: { streamLenUB = 0; break; } } if ((streamLenUB < 0) && (streamLenUB != -ISAC_PAYLOAD_LARGER_THAN_LIMIT)) { /* An error has happened but this is not the error due to a * bit-stream larger than the limit. */ return -1; } if (streamLenLB == 0) { return 0; } /* One byte is allocated for the length. According to older decoders so the length bit-stream plus one byte for size and LEN_CHECK_SUM_WORD8 for the checksum should be less than or equal to 255. */ if ((streamLenUB > (255 - (LEN_CHECK_SUM_WORD8 + 1))) || (streamLenUB == -ISAC_PAYLOAD_LARGER_THAN_LIMIT)) { /* We have got a too long bit-stream we skip the upper-band * bit-stream for this frame. */ streamLenUB = 0; } memcpy(encoded, instLB->ISACencLB_obj.bitstr_obj.stream, streamLenLB); streamLen = streamLenLB; if (streamLenUB > 0) { encoded[streamLenLB] = (uint8_t)(streamLenUB + 1 + LEN_CHECK_SUM_WORD8); memcpy(&encoded[streamLenLB + 1], instUB->ISACencUB_obj.bitstr_obj.stream, streamLenUB); streamLen += encoded[streamLenLB]; } else { encoded[streamLenLB] = 0; } } else { if (streamLenLB == 0) { return 0; } memcpy(encoded, instLB->ISACencLB_obj.bitstr_obj.stream, streamLenLB); streamLenUB = 0; streamLen = streamLenLB; } /* Add Garbage if required. */ bottleneck = WebRtcIsac_GetUplinkBandwidth(&instISAC->bwestimator_obj); if (instISAC->codingMode == 0) { int minBytes; int limit; uint8_t* ptrGarbage; instISAC->MaxDelay = (double)WebRtcIsac_GetUplinkMaxDelay( &instISAC->bwestimator_obj); /* Update rate model and get minimum number of bytes in this packet. */ minBytes = WebRtcIsac_GetMinBytes( &(instISAC->rate_data_obj), streamLen, instISAC->instLB.ISACencLB_obj.current_framesamples, bottleneck, instISAC->MaxDelay, instISAC->bandwidthKHz); /* Make sure MinBytes does not exceed packet size limit. */ if (instISAC->bandwidthKHz == isac8kHz) { if (instLB->ISACencLB_obj.current_framesamples == FRAMESAMPLES) { limit = instLB->ISACencLB_obj.payloadLimitBytes30; } else { limit = instLB->ISACencLB_obj.payloadLimitBytes60; } } else { limit = instUB->ISACencUB_obj.maxPayloadSizeBytes; } minBytes = (minBytes > limit) ? limit : minBytes; /* Make sure we don't allow more than 255 bytes of garbage data. * We store the length of the garbage data in 8 bits in the bitstream, * 255 is the max garbage length we can signal using 8 bits. */ if ((instISAC->bandwidthKHz == isac8kHz) || (streamLenUB == 0)) { ptrGarbage = &encoded[streamLenLB]; limit = streamLen + 255; } else { ptrGarbage = &encoded[streamLenLB + 1 + streamLenUB]; limit = streamLen + (255 - encoded[streamLenLB]); } minBytes = (minBytes > limit) ? limit : minBytes; garbageLen = (minBytes > streamLen) ? (uint8_t)(minBytes - streamLen) : 0; /* Save data for creation of multiple bit-streams. */ /* If bit-stream too short then add garbage at the end. */ if (garbageLen > 0) { /* Overwrite the garbage area to avoid leaking possibly sensitive data over the network. This also makes the output deterministic. */ memset(ptrGarbage, 0, garbageLen); /* For a correct length of the upper-band bit-stream together * with the garbage. Garbage is embeded in upper-band bit-stream. * That is the only way to preserve backward compatibility. */ if ((instISAC->bandwidthKHz == isac8kHz) || (streamLenUB == 0)) { encoded[streamLenLB] = garbageLen; } else { encoded[streamLenLB] += garbageLen; /* Write the length of the garbage at the end of the upper-band * bit-stream, if exists. This helps for sanity check. */ encoded[streamLenLB + 1 + streamLenUB] = garbageLen; } streamLen += garbageLen; } } else { /* update rate model */ WebRtcIsac_UpdateRateModel( &instISAC->rate_data_obj, streamLen, instISAC->instLB.ISACencLB_obj.current_framesamples, bottleneck); garbageLen = 0; } /* Generate CRC if required. */ if ((instISAC->bandwidthKHz != isac8kHz) && (streamLenUB > 0)) { uint32_t crc; WebRtcIsac_GetCrc((int16_t*)(&(encoded[streamLenLB + 1])), streamLenUB + garbageLen, &crc); #ifndef WEBRTC_ARCH_BIG_ENDIAN for (k = 0; k < LEN_CHECK_SUM_WORD8; k++) { encoded[streamLen - LEN_CHECK_SUM_WORD8 + k] = (uint8_t)(crc >> (24 - k * 8)); } #else memcpy(&encoded[streamLenLB + streamLenUB + 1], &crc, LEN_CHECK_SUM_WORD8); #endif } return streamLen; } /****************************************************************************** * WebRtcIsac_GetNewBitStream(...) * * This function returns encoded data, with the recieved bwe-index in the * stream. If the rate is set to a value less than bottleneck of codec * the new bistream will be re-encoded with the given target rate. * It should always return a complete packet, i.e. only called once * even for 60 msec frames. * * NOTE 1! This function does not write in the ISACStruct, it is not allowed. * NOTE 2! Rates larger than the bottleneck of the codec will be limited * to the current bottleneck. * * Input: * - ISAC_main_inst : ISAC instance. * - bweIndex : Index of bandwidth estimate to put in new * bitstream * - rate : target rate of the transcoder is bits/sec. * Valid values are the accepted rate in iSAC, * i.e. 10000 to 56000. * * Output: * - encoded : The encoded data vector * * Return value : >0 - Length (in bytes) of coded data * -1 - Error or called in SWB mode * NOTE! No error code is written to * the struct since it is only allowed to read * the struct. */ int16_t WebRtcIsac_GetNewBitStream(ISACStruct* ISAC_main_inst, int16_t bweIndex, int16_t jitterInfo, int32_t rate, uint8_t* encoded, int16_t isRCU) { Bitstr iSACBitStreamInst; /* Local struct for bitstream handling */ int16_t streamLenLB; int16_t streamLenUB; int16_t totalStreamLen; double gain2; double gain1; float scale; enum ISACBandwidth bandwidthKHz; double rateLB; double rateUB; int32_t currentBN; uint32_t crc; #ifndef WEBRTC_ARCH_BIG_ENDIAN int16_t k; #endif ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { return -1; } /* Get the bottleneck of this iSAC and limit the * given rate to the current bottleneck. */ WebRtcIsac_GetUplinkBw(ISAC_main_inst, ¤tBN); if (rate > currentBN) { rate = currentBN; } if (WebRtcIsac_RateAllocation(rate, &rateLB, &rateUB, &bandwidthKHz) < 0) { return -1; } /* Cannot transcode from 16 kHz to 12 kHz. */ if ((bandwidthKHz == isac12kHz) && (instISAC->bandwidthKHz == isac16kHz)) { return -1; } /* A gain [dB] for the given rate. */ gain1 = WebRtcIsac_GetSnr( rateLB, instISAC->instLB.ISACencLB_obj.current_framesamples); /* The gain [dB] of this iSAC. */ gain2 = WebRtcIsac_GetSnr( instISAC->instLB.ISACencLB_obj.bottleneck, instISAC->instLB.ISACencLB_obj.current_framesamples); /* Scale is the ratio of two gains in normal domain. */ scale = (float)pow(10, (gain1 - gain2) / 20.0); /* Change the scale if this is a RCU bit-stream. */ scale = (isRCU) ? (scale * RCU_TRANSCODING_SCALE) : scale; streamLenLB = WebRtcIsac_EncodeStoredDataLb( &instISAC->instLB.ISACencLB_obj.SaveEnc_obj, &iSACBitStreamInst, bweIndex, scale); if (streamLenLB < 0) { return -1; } /* Convert from bytes to int16_t. */ memcpy(encoded, iSACBitStreamInst.stream, streamLenLB); if (bandwidthKHz == isac8kHz) { return streamLenLB; } totalStreamLen = streamLenLB; /* super-wideband is always at 30ms. * These gains are in dB. * Gain for the given rate. */ gain1 = WebRtcIsac_GetSnr(rateUB, FRAMESAMPLES); /* Gain of this iSAC */ gain2 = WebRtcIsac_GetSnr(instISAC->instUB.ISACencUB_obj.bottleneck, FRAMESAMPLES); /* Scale is the ratio of two gains in normal domain. */ scale = (float)pow(10, (gain1 - gain2) / 20.0); /* Change the scale if this is a RCU bit-stream. */ scale = (isRCU)? (scale * RCU_TRANSCODING_SCALE_UB) : scale; streamLenUB = WebRtcIsac_EncodeStoredDataUb( &(instISAC->instUB.ISACencUB_obj.SaveEnc_obj), &iSACBitStreamInst, jitterInfo, scale, instISAC->bandwidthKHz); if (streamLenUB < 0) { return -1; } if (streamLenUB + 1 + LEN_CHECK_SUM_WORD8 > 255) { return streamLenLB; } totalStreamLen = streamLenLB + streamLenUB + 1 + LEN_CHECK_SUM_WORD8; encoded[streamLenLB] = streamLenUB + 1 + LEN_CHECK_SUM_WORD8; memcpy(&encoded[streamLenLB + 1], iSACBitStreamInst.stream, streamLenUB); WebRtcIsac_GetCrc((int16_t*)(&(encoded[streamLenLB + 1])), streamLenUB, &crc); #ifndef WEBRTC_ARCH_BIG_ENDIAN for (k = 0; k < LEN_CHECK_SUM_WORD8; k++) { encoded[totalStreamLen - LEN_CHECK_SUM_WORD8 + k] = (uint8_t)((crc >> (24 - k * 8)) & 0xFF); } #else memcpy(&encoded[streamLenLB + streamLenUB + 1], &crc, LEN_CHECK_SUM_WORD8); #endif return totalStreamLen; } /**************************************************************************** * DecoderInitLb(...) - internal function for initialization of * Lower Band * DecoderInitUb(...) - internal function for initialization of * Upper Band * WebRtcIsac_DecoderInit(...) - API function * * This function initializes a ISAC instance prior to the decoder calls. * * Input: * - ISAC_main_inst : ISAC instance. */ static void DecoderInitLb(ISACLBStruct* instISAC) { int i; /* Initialize stream vector to zero. */ for (i = 0; i < STREAM_SIZE_MAX_60; i++) { instISAC->ISACdecLB_obj.bitstr_obj.stream[i] = 0; } WebRtcIsac_InitMasking(&instISAC->ISACdecLB_obj.maskfiltstr_obj); WebRtcIsac_InitPostFilterbank( &instISAC->ISACdecLB_obj.postfiltbankstr_obj); WebRtcIsac_InitPitchFilter(&instISAC->ISACdecLB_obj.pitchfiltstr_obj); } static void DecoderInitUb(ISACUBStruct* instISAC) { int i; /* Init stream vector to zero */ for (i = 0; i < STREAM_SIZE_MAX_60; i++) { instISAC->ISACdecUB_obj.bitstr_obj.stream[i] = 0; } WebRtcIsac_InitMasking(&instISAC->ISACdecUB_obj.maskfiltstr_obj); WebRtcIsac_InitPostFilterbank( &instISAC->ISACdecUB_obj.postfiltbankstr_obj); } void WebRtcIsac_DecoderInit(ISACStruct* ISAC_main_inst) { ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; DecoderInitLb(&instISAC->instLB); if (instISAC->decoderSamplingRateKHz == kIsacSuperWideband) { memset(instISAC->synthesisFBState1, 0, FB_STATE_SIZE_WORD32 * sizeof(int32_t)); memset(instISAC->synthesisFBState2, 0, FB_STATE_SIZE_WORD32 * sizeof(int32_t)); DecoderInitUb(&(instISAC->instUB)); } if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { WebRtcIsac_InitBandwidthEstimator(&instISAC->bwestimator_obj, instISAC->encoderSamplingRateKHz, instISAC->decoderSamplingRateKHz); } instISAC->initFlag |= BIT_MASK_DEC_INIT; instISAC->resetFlag_8kHz = 0; } /**************************************************************************** * WebRtcIsac_UpdateBwEstimate(...) * * This function updates the estimate of the bandwidth. * * NOTE: * The estimates of bandwidth is not valid if the sample rate of the far-end * encoder is set to 48 kHz and send timestamps are increamented according to * 48 kHz sampling rate. * * Input: * - ISAC_main_inst : ISAC instance. * - encoded : encoded ISAC frame(s). * - packet_size : size of the packet. * - rtp_seq_number : the RTP number of the packet. * - arr_ts : the arrival time of the packet (from NetEq) * in samples. * * Return value : 0 - Ok * -1 - Error */ int16_t WebRtcIsac_UpdateBwEstimate(ISACStruct* ISAC_main_inst, const uint8_t* encoded, size_t packet_size, uint16_t rtp_seq_number, uint32_t send_ts, uint32_t arr_ts) { ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; Bitstr streamdata; #ifndef WEBRTC_ARCH_BIG_ENDIAN int k; #endif int16_t err; /* Check if decoder initiated. */ if ((instISAC->initFlag & BIT_MASK_DEC_INIT) != BIT_MASK_DEC_INIT) { instISAC->errorCode = ISAC_DECODER_NOT_INITIATED; return -1; } /* Check that the size of the packet is valid, and if not return without * updating the bandwidth estimate. A valid size is at least 10 bytes. */ if (packet_size < 10) { /* Return error code if the packet length is null. */ instISAC->errorCode = ISAC_EMPTY_PACKET; return -1; } WebRtcIsac_ResetBitstream(&(streamdata)); #ifndef WEBRTC_ARCH_BIG_ENDIAN for (k = 0; k < 10; k++) { uint16_t ek = ((const uint16_t*)encoded)[k >> 1]; streamdata.stream[k] = (uint8_t)((ek >> ((k & 1) << 3)) & 0xff); } #else memcpy(streamdata.stream, encoded, 10); #endif err = WebRtcIsac_EstimateBandwidth(&instISAC->bwestimator_obj, &streamdata, packet_size, rtp_seq_number, send_ts, arr_ts, instISAC->encoderSamplingRateKHz, instISAC->decoderSamplingRateKHz); if (err < 0) { /* Return error code if something went wrong. */ instISAC->errorCode = -err; return -1; } return 0; } static int Decode(ISACStruct* ISAC_main_inst, const uint8_t* encoded, size_t lenEncodedBytes, int16_t* decoded, int16_t* speechType, int16_t isRCUPayload) { /* Number of samples (480 or 960), output from decoder that were actually used in the encoder/decoder (determined on the fly). */ int16_t numSamplesLB; int16_t numSamplesUB; int16_t speechIdx; float outFrame[MAX_FRAMESAMPLES]; int16_t outFrameLB[MAX_FRAMESAMPLES]; int16_t outFrameUB[MAX_FRAMESAMPLES]; int numDecodedBytesLBint; size_t numDecodedBytesLB; int numDecodedBytesUB; size_t lenEncodedLBBytes; int16_t validChecksum = 1; int16_t k; uint16_t numLayer; size_t totSizeBytes; int16_t err; ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; ISACUBDecStruct* decInstUB = &(instISAC->instUB.ISACdecUB_obj); ISACLBDecStruct* decInstLB = &(instISAC->instLB.ISACdecLB_obj); /* Check if decoder initiated. */ if ((instISAC->initFlag & BIT_MASK_DEC_INIT) != BIT_MASK_DEC_INIT) { instISAC->errorCode = ISAC_DECODER_NOT_INITIATED; return -1; } if (lenEncodedBytes == 0) { /* return error code if the packet length is null. */ instISAC->errorCode = ISAC_EMPTY_PACKET; return -1; } /* The size of the encoded lower-band is bounded by * STREAM_SIZE_MAX. If a payload with the size larger than STREAM_SIZE_MAX * is received, it is not considered erroneous. */ lenEncodedLBBytes = (lenEncodedBytes > STREAM_SIZE_MAX) ? STREAM_SIZE_MAX : lenEncodedBytes; /* Copy to lower-band bit-stream structure. */ memcpy(instISAC->instLB.ISACdecLB_obj.bitstr_obj.stream, encoded, lenEncodedLBBytes); /* We need to initialize numSamplesLB to something; otherwise, in the test for whether we should return -1 below, the compiler might generate code that fools Memcheck (Valgrind) into thinking that the control flow depends on the uninitialized value in numSamplesLB (since WebRtcIsac_DecodeLb will not fill it in if it fails and returns -1). */ numSamplesLB = 0; /* Regardless of that the current codec is setup to work in * wideband or super-wideband, the decoding of the lower-band * has to be performed. */ numDecodedBytesLBint = WebRtcIsac_DecodeLb(&instISAC->transform_tables, outFrame, decInstLB, &numSamplesLB, isRCUPayload); numDecodedBytesLB = (size_t)numDecodedBytesLBint; if ((numDecodedBytesLBint < 0) || (numDecodedBytesLB > lenEncodedLBBytes) || (numSamplesLB > MAX_FRAMESAMPLES)) { instISAC->errorCode = ISAC_LENGTH_MISMATCH; return -1; } /* Error Check, we accept multi-layer bit-stream This will limit number * of iterations of the while loop. Even without this the number * of iterations is limited. */ numLayer = 1; totSizeBytes = numDecodedBytesLB; while (totSizeBytes != lenEncodedBytes) { if ((totSizeBytes > lenEncodedBytes) || (encoded[totSizeBytes] == 0) || (numLayer > MAX_NUM_LAYERS)) { instISAC->errorCode = ISAC_LENGTH_MISMATCH; return -1; } totSizeBytes += encoded[totSizeBytes]; numLayer++; } if (instISAC->decoderSamplingRateKHz == kIsacWideband) { for (k = 0; k < numSamplesLB; k++) { if (outFrame[k] > 32767) { decoded[k] = 32767; } else if (outFrame[k] < -32768) { decoded[k] = -32768; } else { decoded[k] = (int16_t)WebRtcIsac_lrint(outFrame[k]); } } numSamplesUB = 0; } else { uint32_t crc; /* We don't accept larger than 30ms (480 samples at lower-band) * frame-size. */ for (k = 0; k < numSamplesLB; k++) { if (outFrame[k] > 32767) { outFrameLB[k] = 32767; } else if (outFrame[k] < -32768) { outFrameLB[k] = -32768; } else { outFrameLB[k] = (int16_t)WebRtcIsac_lrint(outFrame[k]); } } /* Check for possible error, and if upper-band stream exists. */ if (numDecodedBytesLB == lenEncodedBytes) { /* Decoding was successful. No super-wideband bit-stream exists. */ numSamplesUB = numSamplesLB; memset(outFrameUB, 0, sizeof(int16_t) * numSamplesUB); /* Prepare for the potential increase of signal bandwidth. */ instISAC->resetFlag_8kHz = 2; } else { /* This includes the checksum and the bytes that stores the length. */ int16_t lenNextStream = encoded[numDecodedBytesLB]; /* Is this garbage or valid super-wideband bit-stream? * Check if checksum is valid. */ if (lenNextStream <= (LEN_CHECK_SUM_WORD8 + 1)) { /* Such a small second layer cannot be super-wideband layer. * It must be a short garbage. */ validChecksum = 0; } else { /* Run CRC to see if the checksum match. */ WebRtcIsac_GetCrc((int16_t*)(&encoded[numDecodedBytesLB + 1]), lenNextStream - LEN_CHECK_SUM_WORD8 - 1, &crc); validChecksum = 1; for (k = 0; k < LEN_CHECK_SUM_WORD8; k++) { validChecksum &= (((crc >> (24 - k * 8)) & 0xFF) == encoded[numDecodedBytesLB + lenNextStream - LEN_CHECK_SUM_WORD8 + k]); } } if (!validChecksum) { /* This is a garbage, we have received a wideband * bit-stream with garbage. */ numSamplesUB = numSamplesLB; memset(outFrameUB, 0, sizeof(int16_t) * numSamplesUB); } else { /* A valid super-wideband biststream exists. */ enum ISACBandwidth bandwidthKHz; int32_t maxDelayBit; /* If we have super-wideband bit-stream, we cannot * have 60 ms frame-size. */ if (numSamplesLB > FRAMESAMPLES) { instISAC->errorCode = ISAC_LENGTH_MISMATCH; return -1; } /* The rest of the bit-stream contains the upper-band * bit-stream curently this is the only thing there, * however, we might add more layers. */ /* Have to exclude one byte where the length is stored * and last 'LEN_CHECK_SUM_WORD8' bytes where the * checksum is stored. */ lenNextStream -= (LEN_CHECK_SUM_WORD8 + 1); memcpy(decInstUB->bitstr_obj.stream, &encoded[numDecodedBytesLB + 1], lenNextStream); /* Reset bit-stream object, this is the first decoding. */ WebRtcIsac_ResetBitstream(&(decInstUB->bitstr_obj)); /* Decode jitter information. */ err = WebRtcIsac_DecodeJitterInfo(&decInstUB->bitstr_obj, &maxDelayBit); if (err < 0) { instISAC->errorCode = -err; return -1; } /* Update jitter info which is in the upper-band bit-stream * only if the encoder is in super-wideband. Otherwise, * the jitter info is already embedded in bandwidth index * and has been updated. */ if (instISAC->encoderSamplingRateKHz == kIsacSuperWideband) { err = WebRtcIsac_UpdateUplinkJitter( &(instISAC->bwestimator_obj), maxDelayBit); if (err < 0) { instISAC->errorCode = -err; return -1; } } /* Decode bandwidth information. */ err = WebRtcIsac_DecodeBandwidth(&decInstUB->bitstr_obj, &bandwidthKHz); if (err < 0) { instISAC->errorCode = -err; return -1; } switch (bandwidthKHz) { case isac12kHz: { numDecodedBytesUB = WebRtcIsac_DecodeUb12( &instISAC->transform_tables, outFrame, decInstUB, isRCUPayload); /* Hang-over for transient alleviation - * wait two frames to add the upper band going up from 8 kHz. */ if (instISAC->resetFlag_8kHz > 0) { if (instISAC->resetFlag_8kHz == 2) { /* Silence first and a half frame. */ memset(outFrame, 0, MAX_FRAMESAMPLES * sizeof(float)); } else { const float rampStep = 2.0f / MAX_FRAMESAMPLES; float rampVal = 0; memset(outFrame, 0, (MAX_FRAMESAMPLES >> 1) * sizeof(float)); /* Ramp up second half of second frame. */ for (k = MAX_FRAMESAMPLES / 2; k < MAX_FRAMESAMPLES; k++) { outFrame[k] *= rampVal; rampVal += rampStep; } } instISAC->resetFlag_8kHz -= 1; } break; } case isac16kHz: { numDecodedBytesUB = WebRtcIsac_DecodeUb16( &instISAC->transform_tables, outFrame, decInstUB, isRCUPayload); break; } default: return -1; } if (numDecodedBytesUB < 0) { instISAC->errorCode = numDecodedBytesUB; return -1; } if (numDecodedBytesLB + numDecodedBytesUB > lenEncodedBytes) { // We have supposedly decoded more bytes than we were given. Likely // caused by bad input data. instISAC->errorCode = ISAC_LENGTH_MISMATCH; return -1; } /* It might be less due to garbage. */ if ((numDecodedBytesUB != lenNextStream) && (numDecodedBytesLB + 1 + numDecodedBytesUB >= lenEncodedBytes || numDecodedBytesUB != (lenNextStream - encoded[numDecodedBytesLB + 1 + numDecodedBytesUB]))) { instISAC->errorCode = ISAC_LENGTH_MISMATCH; return -1; } /* If there is no error Upper-band always decodes * 30 ms (480 samples). */ numSamplesUB = FRAMESAMPLES; /* Convert to W16. */ for (k = 0; k < numSamplesUB; k++) { if (outFrame[k] > 32767) { outFrameUB[k] = 32767; } else if (outFrame[k] < -32768) { outFrameUB[k] = -32768; } else { outFrameUB[k] = (int16_t)WebRtcIsac_lrint( outFrame[k]); } } } } speechIdx = 0; while (speechIdx < numSamplesLB) { WebRtcSpl_SynthesisQMF(&outFrameLB[speechIdx], &outFrameUB[speechIdx], FRAMESAMPLES_10ms, &decoded[(speechIdx << 1)], instISAC->synthesisFBState1, instISAC->synthesisFBState2); speechIdx += FRAMESAMPLES_10ms; } } *speechType = 0; return (numSamplesLB + numSamplesUB); } /**************************************************************************** * WebRtcIsac_Decode(...) * * This function decodes a ISAC frame. Output speech length * will be a multiple of 480 samples: 480 or 960 samples, * depending on the frameSize (30 or 60 ms). * * Input: * - ISAC_main_inst : ISAC instance. * - encoded : encoded ISAC frame(s) * - len : bytes in encoded vector * * Output: * - decoded : The decoded vector * * Return value : >0 - number of samples in decoded vector * -1 - Error */ int WebRtcIsac_Decode(ISACStruct* ISAC_main_inst, const uint8_t* encoded, size_t lenEncodedBytes, int16_t* decoded, int16_t* speechType) { int16_t isRCUPayload = 0; return Decode(ISAC_main_inst, encoded, lenEncodedBytes, decoded, speechType, isRCUPayload); } /**************************************************************************** * WebRtcIsac_DecodeRcu(...) * * This function decodes a redundant (RCU) iSAC frame. Function is called in * NetEq with a stored RCU payload in case of packet loss. Output speech length * will be a multiple of 480 samples: 480 or 960 samples, * depending on the framesize (30 or 60 ms). * * Input: * - ISAC_main_inst : ISAC instance. * - encoded : encoded ISAC RCU frame(s) * - len : bytes in encoded vector * * Output: * - decoded : The decoded vector * * Return value : >0 - number of samples in decoded vector * -1 - Error */ int WebRtcIsac_DecodeRcu(ISACStruct* ISAC_main_inst, const uint8_t* encoded, size_t lenEncodedBytes, int16_t* decoded, int16_t* speechType) { int16_t isRCUPayload = 1; return Decode(ISAC_main_inst, encoded, lenEncodedBytes, decoded, speechType, isRCUPayload); } /**************************************************************************** * WebRtcIsac_DecodePlc(...) * * This function conducts PLC for ISAC frame(s). Output speech length * will be a multiple of 480 samples: 480 or 960 samples, * depending on the frameSize (30 or 60 ms). * * Input: * - ISAC_main_inst : ISAC instance. * - noOfLostFrames : Number of PLC frames to produce * * Output: * - decoded : The decoded vector * * Return value : Number of samples in decoded PLC vector */ size_t WebRtcIsac_DecodePlc(ISACStruct* ISAC_main_inst, int16_t* decoded, size_t noOfLostFrames) { size_t numSamples = 0; ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; /* Limit number of frames to two = 60 millisecond. * Otherwise we exceed data vectors. */ if (noOfLostFrames > 2) { noOfLostFrames = 2; } /* Get the number of samples per frame */ switch (instISAC->decoderSamplingRateKHz) { case kIsacWideband: { numSamples = 480 * noOfLostFrames; break; } case kIsacSuperWideband: { numSamples = 960 * noOfLostFrames; break; } } /* Set output samples to zero. */ memset(decoded, 0, numSamples * sizeof(int16_t)); return numSamples; } /**************************************************************************** * ControlLb(...) - Internal function for controlling Lower Band * ControlUb(...) - Internal function for controlling Upper Band * WebRtcIsac_Control(...) - API function * * This function sets the limit on the short-term average bit rate and the * frame length. Should be used only in Instantaneous mode. * * Input: * - ISAC_main_inst : ISAC instance. * - rate : limit on the short-term average bit rate, * in bits/second (between 10000 and 32000) * - frameSize : number of milliseconds per frame (30 or 60) * * Return value : 0 - ok * -1 - Error */ static int16_t ControlLb(ISACLBStruct* instISAC, double rate, int16_t frameSize) { if ((rate >= 10000) && (rate <= 32000)) { instISAC->ISACencLB_obj.bottleneck = rate; } else { return -ISAC_DISALLOWED_BOTTLENECK; } if ((frameSize == 30) || (frameSize == 60)) { instISAC->ISACencLB_obj.new_framelength = (FS / 1000) * frameSize; } else { return -ISAC_DISALLOWED_FRAME_LENGTH; } return 0; } static int16_t ControlUb(ISACUBStruct* instISAC, double rate) { if ((rate >= 10000) && (rate <= 32000)) { instISAC->ISACencUB_obj.bottleneck = rate; } else { return -ISAC_DISALLOWED_BOTTLENECK; } return 0; } int16_t WebRtcIsac_Control(ISACStruct* ISAC_main_inst, int32_t bottleneckBPS, int frameSize) { ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; int16_t status; double rateLB; double rateUB; enum ISACBandwidth bandwidthKHz; if (instISAC->codingMode == 0) { /* In adaptive mode. */ instISAC->errorCode = ISAC_MODE_MISMATCH; return -1; } /* Check if encoder initiated */ if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; return -1; } if (instISAC->encoderSamplingRateKHz == kIsacWideband) { /* If the sampling rate is 16kHz then bandwith should be 8kHz, * regardless of bottleneck. */ bandwidthKHz = isac8kHz; rateLB = (bottleneckBPS > 32000) ? 32000 : bottleneckBPS; rateUB = 0; } else { if (WebRtcIsac_RateAllocation(bottleneckBPS, &rateLB, &rateUB, &bandwidthKHz) < 0) { return -1; } } if ((instISAC->encoderSamplingRateKHz == kIsacSuperWideband) && (frameSize != 30) && (bandwidthKHz != isac8kHz)) { /* Cannot have 60 ms in super-wideband. */ instISAC->errorCode = ISAC_DISALLOWED_FRAME_LENGTH; return -1; } status = ControlLb(&instISAC->instLB, rateLB, (int16_t)frameSize); if (status < 0) { instISAC->errorCode = -status; return -1; } if (bandwidthKHz != isac8kHz) { status = ControlUb(&(instISAC->instUB), rateUB); if (status < 0) { instISAC->errorCode = -status; return -1; } } /* Check if bandwidth is changing from wideband to super-wideband * then we have to synch data buffer of lower & upper-band. Also * clean up the upper-band data buffer. */ if ((instISAC->bandwidthKHz == isac8kHz) && (bandwidthKHz != isac8kHz)) { memset(instISAC->instUB.ISACencUB_obj.data_buffer_float, 0, sizeof(float) * (MAX_FRAMESAMPLES + LB_TOTAL_DELAY_SAMPLES)); if (bandwidthKHz == isac12kHz) { instISAC->instUB.ISACencUB_obj.buffer_index = instISAC->instLB.ISACencLB_obj.buffer_index; } else { instISAC->instUB.ISACencUB_obj.buffer_index = LB_TOTAL_DELAY_SAMPLES + instISAC->instLB.ISACencLB_obj.buffer_index; memcpy(&(instISAC->instUB.ISACencUB_obj.lastLPCVec), WebRtcIsac_kMeanLarUb16, sizeof(double) * UB_LPC_ORDER); } } /* Update the payload limit if the bandwidth is changing. */ if (instISAC->bandwidthKHz != bandwidthKHz) { instISAC->bandwidthKHz = bandwidthKHz; UpdatePayloadSizeLimit(instISAC); } instISAC->bottleneck = bottleneckBPS; return 0; } void WebRtcIsac_SetInitialBweBottleneck(ISACStruct* ISAC_main_inst, int bottleneck_bits_per_second) { ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; RTC_DCHECK_GE(bottleneck_bits_per_second, 10000); RTC_DCHECK_LE(bottleneck_bits_per_second, 32000); instISAC->bwestimator_obj.send_bw_avg = (float)bottleneck_bits_per_second; } /**************************************************************************** * WebRtcIsac_ControlBwe(...) * * This function sets the initial values of bottleneck and frame-size if * iSAC is used in channel-adaptive mode. Through this API, users can * enforce a frame-size for all values of bottleneck. Then iSAC will not * automatically change the frame-size. * * * Input: * - ISAC_main_inst : ISAC instance. * - rateBPS : initial value of bottleneck in bits/second * 10000 <= rateBPS <= 32000 is accepted * For default bottleneck set rateBPS = 0 * - frameSizeMs : number of milliseconds per frame (30 or 60) * - enforceFrameSize : 1 to enforce the given frame-size through out * the adaptation process, 0 to let iSAC change * the frame-size if required. * * Return value : 0 - ok * -1 - Error */ int16_t WebRtcIsac_ControlBwe(ISACStruct* ISAC_main_inst, int32_t bottleneckBPS, int frameSizeMs, int16_t enforceFrameSize) { ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; enum ISACBandwidth bandwidth; /* Check if encoder initiated */ if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; return -1; } /* Check that we are in channel-adaptive mode, otherwise, return (-1) */ if (instISAC->codingMode != 0) { instISAC->errorCode = ISAC_MODE_MISMATCH; return -1; } if ((frameSizeMs != 30) && (instISAC->encoderSamplingRateKHz == kIsacSuperWideband)) { return -1; } /* Set structure variable if enforceFrameSize is set. ISAC will then * keep the chosen frame size. */ if (enforceFrameSize != 0) { instISAC->instLB.ISACencLB_obj.enforceFrameSize = 1; } else { instISAC->instLB.ISACencLB_obj.enforceFrameSize = 0; } /* Set the initial rate. If the input value is zero then the default intial * rate is used. Otehrwise, values between 10 to 32 kbps are accepted. */ if (bottleneckBPS != 0) { double rateLB; double rateUB; if (WebRtcIsac_RateAllocation(bottleneckBPS, &rateLB, &rateUB, &bandwidth) < 0) { return -1; } instISAC->bwestimator_obj.send_bw_avg = (float)bottleneckBPS; instISAC->bandwidthKHz = bandwidth; } /* Set the initial frame-size. If 'enforceFrameSize' is set, the frame-size * will not change */ if (frameSizeMs != 0) { if ((frameSizeMs == 30) || (frameSizeMs == 60)) { instISAC->instLB.ISACencLB_obj.new_framelength = (int16_t)((FS / 1000) * frameSizeMs); } else { instISAC->errorCode = ISAC_DISALLOWED_FRAME_LENGTH; return -1; } } return 0; } /**************************************************************************** * WebRtcIsac_GetDownLinkBwIndex(...) * * This function returns index representing the Bandwidth estimate from * the other side to this side. * * Input: * - ISAC_main_inst : iSAC structure * * Output: * - bweIndex : Bandwidth estimate to transmit to other side. * */ int16_t WebRtcIsac_GetDownLinkBwIndex(ISACStruct* ISAC_main_inst, int16_t* bweIndex, int16_t* jitterInfo) { ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; /* Check if encoder initialized. */ if ((instISAC->initFlag & BIT_MASK_DEC_INIT) != BIT_MASK_DEC_INIT) { instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; return -1; } /* Call function to get Bandwidth Estimate. */ WebRtcIsac_GetDownlinkBwJitIndexImpl(&(instISAC->bwestimator_obj), bweIndex, jitterInfo, instISAC->decoderSamplingRateKHz); return 0; } /**************************************************************************** * WebRtcIsac_UpdateUplinkBw(...) * * This function takes an index representing the Bandwidth estimate from * this side to other side and updates BWE. * * Input: * - ISAC_main_inst : iSAC structure * - rateIndex : Bandwidth estimate from other side. * * Return value : 0 - ok * -1 - index out of range */ int16_t WebRtcIsac_UpdateUplinkBw(ISACStruct* ISAC_main_inst, int16_t bweIndex) { ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; int16_t returnVal; /* Check if encoder initiated. */ if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; return -1; } /* Call function to get Bandwidth Estimate. */ returnVal = WebRtcIsac_UpdateUplinkBwImpl( &(instISAC->bwestimator_obj), bweIndex, instISAC->encoderSamplingRateKHz); if (returnVal < 0) { instISAC->errorCode = -returnVal; return -1; } else { return 0; } } /**************************************************************************** * WebRtcIsac_ReadBwIndex(...) * * This function returns the index of the Bandwidth estimate from the * bit-stream. * * Input: * - encoded : Encoded bit-stream * * Output: * - frameLength : Length of frame in packet (in samples) * - bweIndex : Bandwidth estimate in bit-stream * */ int16_t WebRtcIsac_ReadBwIndex(const uint8_t* encoded, int16_t* bweIndex) { Bitstr streamdata; #ifndef WEBRTC_ARCH_BIG_ENDIAN int k; #endif int16_t err; WebRtcIsac_ResetBitstream(&(streamdata)); #ifndef WEBRTC_ARCH_BIG_ENDIAN for (k = 0; k < 10; k++) { int16_t ek2 = ((const int16_t*)encoded)[k >> 1]; streamdata.stream[k] = (uint8_t)((ek2 >> ((k & 1) << 3)) & 0xff); } #else memcpy(streamdata.stream, encoded, 10); #endif /* Decode frame length. */ err = WebRtcIsac_DecodeFrameLen(&streamdata, bweIndex); if (err < 0) { return err; } /* Decode BW estimation. */ err = WebRtcIsac_DecodeSendBW(&streamdata, bweIndex); if (err < 0) { return err; } return 0; } /**************************************************************************** * WebRtcIsac_ReadFrameLen(...) * * This function returns the number of samples the decoder will generate if * the given payload is decoded. * * Input: * - encoded : Encoded bitstream * * Output: * - frameLength : Length of frame in packet (in samples) * */ int16_t WebRtcIsac_ReadFrameLen(const ISACStruct* ISAC_main_inst, const uint8_t* encoded, int16_t* frameLength) { Bitstr streamdata; #ifndef WEBRTC_ARCH_BIG_ENDIAN int k; #endif int16_t err; ISACMainStruct* instISAC; WebRtcIsac_ResetBitstream(&(streamdata)); #ifndef WEBRTC_ARCH_BIG_ENDIAN for (k = 0; k < 10; k++) { int16_t ek2 = ((const int16_t*)encoded)[k >> 1]; streamdata.stream[k] = (uint8_t)((ek2 >> ((k & 1) << 3)) & 0xff); } #else memcpy(streamdata.stream, encoded, 10); #endif /* Decode frame length. */ err = WebRtcIsac_DecodeFrameLen(&streamdata, frameLength); if (err < 0) { return -1; } instISAC = (ISACMainStruct*)ISAC_main_inst; if (instISAC->decoderSamplingRateKHz == kIsacSuperWideband) { /* The decoded frame length indicates the number of samples in * lower-band in this case, multiply by 2 to get the total number * of samples. */ *frameLength <<= 1; } return 0; } /******************************************************************************* * WebRtcIsac_GetNewFrameLen(...) * * This function returns the frame length (in samples) of the next packet. * In the case of channel-adaptive mode, iSAC decides on its frame length based * on the estimated bottleneck, this AOI allows a user to prepare for the next * packet (at the encoder). * * The primary usage is in CE to make the iSAC works in channel-adaptive mode * * Input: * - ISAC_main_inst : iSAC struct * * Return Value : frame lenght in samples * */ int16_t WebRtcIsac_GetNewFrameLen(ISACStruct* ISAC_main_inst) { ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; /* Return new frame length. */ if (instISAC->in_sample_rate_hz == 16000) return (instISAC->instLB.ISACencLB_obj.new_framelength); else /* 32000 Hz */ return ((instISAC->instLB.ISACencLB_obj.new_framelength) * 2); } /**************************************************************************** * WebRtcIsac_GetErrorCode(...) * * This function can be used to check the error code of an iSAC instance. * When a function returns -1 an error code will be set for that instance. * The function below extracts the code of the last error that occurred in * the specified instance. * * Input: * - ISAC_main_inst : ISAC instance * * Return value : Error code */ int16_t WebRtcIsac_GetErrorCode(ISACStruct* ISAC_main_inst) { return ((ISACMainStruct*)ISAC_main_inst)->errorCode; } /**************************************************************************** * WebRtcIsac_GetUplinkBw(...) * * This function outputs the target bottleneck of the codec. In * channel-adaptive mode, the target bottleneck is specified through an in-band * signalling retrieved by bandwidth estimator. * In channel-independent, also called instantaneous mode, the target * bottleneck is provided to the encoder by calling xxx_control(...) (if * xxx_control is never called, the default values are used.). * Note that the output is the iSAC internal operating bottleneck which might * differ slightly from the one provided through xxx_control(). * * Input: * - ISAC_main_inst : iSAC instance * * Output: * - *bottleneck : bottleneck in bits/sec * * Return value : -1 if error happens * 0 bit-rates computed correctly. */ int16_t WebRtcIsac_GetUplinkBw(ISACStruct* ISAC_main_inst, int32_t* bottleneck) { ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; if (instISAC->codingMode == 0) { /* We are in adaptive mode then get the bottleneck from BWE. */ *bottleneck = (int32_t)instISAC->bwestimator_obj.send_bw_avg; } else { *bottleneck = instISAC->bottleneck; } if ((*bottleneck > 32000) && (*bottleneck < 38000)) { *bottleneck = 32000; } else if ((*bottleneck > 45000) && (*bottleneck < 50000)) { *bottleneck = 45000; } else if (*bottleneck > 56000) { *bottleneck = 56000; } return 0; } /****************************************************************************** * WebRtcIsac_SetMaxPayloadSize(...) * * This function sets a limit for the maximum payload size of iSAC. The same * value is used both for 30 and 60 ms packets. If the encoder sampling rate * is 16 kHz the maximum payload size is between 120 and 400 bytes. If the * encoder sampling rate is 32 kHz the maximum payload size is between 120 * and 600 bytes. * * --------------- * IMPORTANT NOTES * --------------- * The size of a packet is limited to the minimum of 'max-payload-size' and * 'max-rate.' For instance, let's assume the max-payload-size is set to * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms * frame-size. Then a packet with a frame-size of 30 ms is limited to 150, * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to * 170 bytes, i.e. min(170, 300). * * Input: * - ISAC_main_inst : iSAC instance * - maxPayloadBytes : maximum size of the payload in bytes * valid values are between 100 and 400 bytes * if encoder sampling rate is 16 kHz. For * 32 kHz encoder sampling rate valid values * are between 100 and 600 bytes. * * Return value : 0 if successful * -1 if error happens */ int16_t WebRtcIsac_SetMaxPayloadSize(ISACStruct* ISAC_main_inst, int16_t maxPayloadBytes) { ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; int16_t status = 0; /* Check if encoder initiated */ if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; return -1; } if (instISAC->encoderSamplingRateKHz == kIsacSuperWideband) { /* Sanity check. */ if (maxPayloadBytes < 120) { /* 'maxRate' is out of valid range * set to the acceptable value and return -1. */ maxPayloadBytes = 120; status = -1; } /* sanity check */ if (maxPayloadBytes > STREAM_SIZE_MAX) { /* maxRate is out of valid range, * set to the acceptable value and return -1. */ maxPayloadBytes = STREAM_SIZE_MAX; status = -1; } } else { if (maxPayloadBytes < 120) { /* Max payload-size is out of valid range * set to the acceptable value and return -1. */ maxPayloadBytes = 120; status = -1; } if (maxPayloadBytes > STREAM_SIZE_MAX_60) { /* Max payload-size is out of valid range * set to the acceptable value and return -1. */ maxPayloadBytes = STREAM_SIZE_MAX_60; status = -1; } } instISAC->maxPayloadSizeBytes = maxPayloadBytes; UpdatePayloadSizeLimit(instISAC); return status; } /****************************************************************************** * WebRtcIsac_SetMaxRate(...) * * This function sets the maximum rate which the codec may not exceed for * any signal packet. The maximum rate is defined and payload-size per * frame-size in bits per second. * * The codec has a maximum rate of 53400 bits per second (200 bytes per 30 * ms) if the encoder sampling rate is 16kHz, and 160 kbps (600 bytes/30 ms) * if the encoder sampling rate is 32 kHz. * * It is possible to set a maximum rate between 32000 and 53400 bits/sec * in wideband mode, and 32000 to 160000 bits/sec in super-wideband mode. * * --------------- * IMPORTANT NOTES * --------------- * The size of a packet is limited to the minimum of 'max-payload-size' and * 'max-rate.' For instance, let's assume the max-payload-size is set to * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms * frame-size. Then a packet with a frame-size of 30 ms is limited to 150, * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to * 170 bytes, min(170, 300). * * Input: * - ISAC_main_inst : iSAC instance * - maxRate : maximum rate in bits per second, * valid values are 32000 to 53400 bits/sec in * wideband mode, and 32000 to 160000 bits/sec in * super-wideband mode. * * Return value : 0 if successful * -1 if error happens */ int16_t WebRtcIsac_SetMaxRate(ISACStruct* ISAC_main_inst, int32_t maxRate) { ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; int16_t maxRateInBytesPer30Ms; int16_t status = 0; /* check if encoder initiated */ if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; return -1; } /* Calculate maximum number of bytes per 30 msec packets for the given maximum rate. Multiply with 30/1000 to get number of bits per 30 ms, divide by 8 to get number of bytes per 30 ms: maxRateInBytes = floor((maxRate * 30/1000) / 8); */ maxRateInBytesPer30Ms = (int16_t)(maxRate * 3 / 800); if (instISAC->encoderSamplingRateKHz == kIsacWideband) { if (maxRate < 32000) { /* 'maxRate' is out of valid range. * Set to the acceptable value and return -1. */ maxRateInBytesPer30Ms = 120; status = -1; } if (maxRate > 53400) { /* 'maxRate' is out of valid range. * Set to the acceptable value and return -1. */ maxRateInBytesPer30Ms = 200; status = -1; } } else { if (maxRateInBytesPer30Ms < 120) { /* 'maxRate' is out of valid range * Set to the acceptable value and return -1. */ maxRateInBytesPer30Ms = 120; status = -1; } if (maxRateInBytesPer30Ms > STREAM_SIZE_MAX) { /* 'maxRate' is out of valid range. * Set to the acceptable value and return -1. */ maxRateInBytesPer30Ms = STREAM_SIZE_MAX; status = -1; } } instISAC->maxRateBytesPer30Ms = maxRateInBytesPer30Ms; UpdatePayloadSizeLimit(instISAC); return status; } /**************************************************************************** * WebRtcIsac_GetRedPayload(...) * * This function populates "encoded" with the redundant payload of the recently * encodedframe. This function has to be called once that WebRtcIsac_Encode(...) * returns a positive value. Regardless of the frame-size this function will * be called only once after encoding is completed. The bit-stream is * targeted for 16000 bit/sec. * * Input: * - ISAC_main_inst : iSAC struct * * Output: * - encoded : the encoded data vector * * * Return value : >0 - Length (in bytes) of coded data * : -1 - Error */ int16_t WebRtcIsac_GetRedPayload(ISACStruct* ISAC_main_inst, uint8_t* encoded) { Bitstr iSACBitStreamInst; int16_t streamLenLB; int16_t streamLenUB; int16_t streamLen; int16_t totalLenUB; ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; #ifndef WEBRTC_ARCH_BIG_ENDIAN int k; #endif if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; } WebRtcIsac_ResetBitstream(&(iSACBitStreamInst)); streamLenLB = WebRtcIsac_EncodeStoredDataLb( &instISAC->instLB.ISACencLB_obj.SaveEnc_obj, &iSACBitStreamInst, instISAC->instLB.ISACencLB_obj.lastBWIdx, RCU_TRANSCODING_SCALE); if (streamLenLB < 0) { return -1; } /* convert from bytes to int16_t. */ memcpy(encoded, iSACBitStreamInst.stream, streamLenLB); streamLen = streamLenLB; if (instISAC->bandwidthKHz == isac8kHz) { return streamLenLB; } streamLenUB = WebRtcIsac_GetRedPayloadUb( &instISAC->instUB.ISACencUB_obj.SaveEnc_obj, &iSACBitStreamInst, instISAC->bandwidthKHz); if (streamLenUB < 0) { /* An error has happened but this is not the error due to a * bit-stream larger than the limit. */ return -1; } /* We have one byte to write the total length of the upper-band. * The length includes the bit-stream length, check-sum and the * single byte where the length is written to. This is according to * iSAC wideband and how the "garbage" is dealt. */ totalLenUB = streamLenUB + 1 + LEN_CHECK_SUM_WORD8; if (totalLenUB > 255) { streamLenUB = 0; } /* Generate CRC if required. */ if ((instISAC->bandwidthKHz != isac8kHz) && (streamLenUB > 0)) { uint32_t crc; streamLen += totalLenUB; encoded[streamLenLB] = (uint8_t)totalLenUB; memcpy(&encoded[streamLenLB + 1], iSACBitStreamInst.stream, streamLenUB); WebRtcIsac_GetCrc((int16_t*)(&(encoded[streamLenLB + 1])), streamLenUB, &crc); #ifndef WEBRTC_ARCH_BIG_ENDIAN for (k = 0; k < LEN_CHECK_SUM_WORD8; k++) { encoded[streamLen - LEN_CHECK_SUM_WORD8 + k] = (uint8_t)((crc >> (24 - k * 8)) & 0xFF); } #else memcpy(&encoded[streamLenLB + streamLenUB + 1], &crc, LEN_CHECK_SUM_WORD8); #endif } return streamLen; } /**************************************************************************** * WebRtcIsac_version(...) * * This function returns the version number. * * Output: * - version : Pointer to character string * */ void WebRtcIsac_version(char* version) { strcpy(version, "4.3.0"); } /****************************************************************************** * WebRtcIsac_SetEncSampRate() * This function sets the sampling rate of the encoder. Initialization of the * encoder WILL NOT overwrite the sampling rate of the encoder. The default * value is 16 kHz which is set when the instance is created. The encoding-mode * and the bottleneck remain unchanged by this call, however, the maximum rate * and maximum payload-size will be reset to their default values. * * Input: * - ISAC_main_inst : iSAC instance * - sample_rate_hz : sampling rate in Hertz, valid values are 16000 * and 32000. * * Return value : 0 if successful * -1 if failed. */ int16_t WebRtcIsac_SetEncSampRate(ISACStruct* ISAC_main_inst, uint16_t sample_rate_hz) { ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; enum IsacSamplingRate encoder_operational_rate; if ((sample_rate_hz != 16000) && (sample_rate_hz != 32000)) { /* Sampling Frequency is not supported. */ instISAC->errorCode = ISAC_UNSUPPORTED_SAMPLING_FREQUENCY; return -1; } if (sample_rate_hz == 16000) { encoder_operational_rate = kIsacWideband; } else { encoder_operational_rate = kIsacSuperWideband; } if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { if (encoder_operational_rate == kIsacWideband) { instISAC->bandwidthKHz = isac8kHz; } else { instISAC->bandwidthKHz = isac16kHz; } } else { ISACUBStruct* instUB = &(instISAC->instUB); ISACLBStruct* instLB = &(instISAC->instLB); int32_t bottleneck = instISAC->bottleneck; int16_t codingMode = instISAC->codingMode; int16_t frameSizeMs = instLB->ISACencLB_obj.new_framelength / (FS / 1000); if ((encoder_operational_rate == kIsacWideband) && (instISAC->encoderSamplingRateKHz == kIsacSuperWideband)) { /* Changing from super-wideband to wideband. * we don't need to re-initialize the encoder of the lower-band. */ instISAC->bandwidthKHz = isac8kHz; if (codingMode == 1) { ControlLb(instLB, (bottleneck > 32000) ? 32000 : bottleneck, FRAMESIZE); } instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX_60; instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX_30; } else if ((encoder_operational_rate == kIsacSuperWideband) && (instISAC->encoderSamplingRateKHz == kIsacWideband)) { double bottleneckLB = 0; double bottleneckUB = 0; if (codingMode == 1) { WebRtcIsac_RateAllocation(bottleneck, &bottleneckLB, &bottleneckUB, &(instISAC->bandwidthKHz)); } instISAC->bandwidthKHz = isac16kHz; instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX; instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX; EncoderInitLb(instLB, codingMode, encoder_operational_rate); EncoderInitUb(instUB, instISAC->bandwidthKHz); memset(instISAC->analysisFBState1, 0, FB_STATE_SIZE_WORD32 * sizeof(int32_t)); memset(instISAC->analysisFBState2, 0, FB_STATE_SIZE_WORD32 * sizeof(int32_t)); if (codingMode == 1) { instISAC->bottleneck = bottleneck; ControlLb(instLB, bottleneckLB, (instISAC->bandwidthKHz == isac8kHz) ? frameSizeMs:FRAMESIZE); if (instISAC->bandwidthKHz > isac8kHz) { ControlUb(instUB, bottleneckUB); } } else { instLB->ISACencLB_obj.enforceFrameSize = 0; instLB->ISACencLB_obj.new_framelength = FRAMESAMPLES; } } } instISAC->encoderSamplingRateKHz = encoder_operational_rate; instISAC->in_sample_rate_hz = sample_rate_hz; return 0; } /****************************************************************************** * WebRtcIsac_SetDecSampRate() * This function sets the sampling rate of the decoder. Initialization of the * decoder WILL NOT overwrite the sampling rate of the encoder. The default * value is 16 kHz which is set when the instance is created. * * Input: * - ISAC_main_inst : iSAC instance * - sample_rate_hz : sampling rate in Hertz, valid values are 16000 * and 32000. * * Return value : 0 if successful * -1 if failed. */ int16_t WebRtcIsac_SetDecSampRate(ISACStruct* ISAC_main_inst, uint16_t sample_rate_hz) { ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; enum IsacSamplingRate decoder_operational_rate; if (sample_rate_hz == 16000) { decoder_operational_rate = kIsacWideband; } else if (sample_rate_hz == 32000) { decoder_operational_rate = kIsacSuperWideband; } else { /* Sampling Frequency is not supported. */ instISAC->errorCode = ISAC_UNSUPPORTED_SAMPLING_FREQUENCY; return -1; } if ((instISAC->decoderSamplingRateKHz == kIsacWideband) && (decoder_operational_rate == kIsacSuperWideband)) { /* Switching from wideband to super-wideband at the decoder * we need to reset the filter-bank and initialize upper-band decoder. */ memset(instISAC->synthesisFBState1, 0, FB_STATE_SIZE_WORD32 * sizeof(int32_t)); memset(instISAC->synthesisFBState2, 0, FB_STATE_SIZE_WORD32 * sizeof(int32_t)); DecoderInitUb(&instISAC->instUB); } instISAC->decoderSamplingRateKHz = decoder_operational_rate; return 0; } /****************************************************************************** * WebRtcIsac_EncSampRate() * * Input: * - ISAC_main_inst : iSAC instance * * Return value : sampling rate in Hertz. The input to encoder * is expected to be sampled in this rate. * */ uint16_t WebRtcIsac_EncSampRate(ISACStruct* ISAC_main_inst) { ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; return instISAC->in_sample_rate_hz; } /****************************************************************************** * WebRtcIsac_DecSampRate() * Return the sampling rate of the decoded audio. * * Input: * - ISAC_main_inst : iSAC instance * * Return value : sampling rate in Hertz. Decoder output is * sampled at this rate. * */ uint16_t WebRtcIsac_DecSampRate(ISACStruct* ISAC_main_inst) { ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; return instISAC->decoderSamplingRateKHz == kIsacWideband ? 16000 : 32000; } void WebRtcIsac_SetEncSampRateInDecoder(ISACStruct* inst, int sample_rate_hz) { ISACMainStruct* instISAC = (ISACMainStruct*)inst; RTC_DCHECK_NE(0, instISAC->initFlag & BIT_MASK_DEC_INIT); RTC_DCHECK(!(instISAC->initFlag & BIT_MASK_ENC_INIT)); RTC_DCHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000); instISAC->encoderSamplingRateKHz = sample_rate_hz / 1000; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/isac_float_type.h0000664000175000017500000000776414475643423032207 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_FLOAT_TYPE_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_FLOAT_TYPE_H_ #include "modules/audio_coding/codecs/isac/main/include/isac.h" namespace webrtc { struct IsacFloat { using instance_type = ISACStruct; static const bool has_swb = true; static inline int16_t Control(instance_type* inst, int32_t rate, int framesize) { return WebRtcIsac_Control(inst, rate, framesize); } static inline int16_t ControlBwe(instance_type* inst, int32_t rate_bps, int frame_size_ms, int16_t enforce_frame_size) { return WebRtcIsac_ControlBwe(inst, rate_bps, frame_size_ms, enforce_frame_size); } static inline int16_t Create(instance_type** inst) { return WebRtcIsac_Create(inst); } static inline int DecodeInternal(instance_type* inst, const uint8_t* encoded, size_t len, int16_t* decoded, int16_t* speech_type) { return WebRtcIsac_Decode(inst, encoded, len, decoded, speech_type); } static inline size_t DecodePlc(instance_type* inst, int16_t* decoded, size_t num_lost_frames) { return WebRtcIsac_DecodePlc(inst, decoded, num_lost_frames); } static inline void DecoderInit(instance_type* inst) { WebRtcIsac_DecoderInit(inst); } static inline int Encode(instance_type* inst, const int16_t* speech_in, uint8_t* encoded) { return WebRtcIsac_Encode(inst, speech_in, encoded); } static inline int16_t EncoderInit(instance_type* inst, int16_t coding_mode) { return WebRtcIsac_EncoderInit(inst, coding_mode); } static inline uint16_t EncSampRate(instance_type* inst) { return WebRtcIsac_EncSampRate(inst); } static inline int16_t Free(instance_type* inst) { return WebRtcIsac_Free(inst); } static inline int16_t GetErrorCode(instance_type* inst) { return WebRtcIsac_GetErrorCode(inst); } static inline int16_t GetNewFrameLen(instance_type* inst) { return WebRtcIsac_GetNewFrameLen(inst); } static inline int16_t SetDecSampRate(instance_type* inst, uint16_t sample_rate_hz) { return WebRtcIsac_SetDecSampRate(inst, sample_rate_hz); } static inline int16_t SetEncSampRate(instance_type* inst, uint16_t sample_rate_hz) { return WebRtcIsac_SetEncSampRate(inst, sample_rate_hz); } static inline void SetEncSampRateInDecoder(instance_type* inst, uint16_t sample_rate_hz) { WebRtcIsac_SetEncSampRateInDecoder(inst, sample_rate_hz); } static inline void SetInitialBweBottleneck(instance_type* inst, int bottleneck_bits_per_second) { WebRtcIsac_SetInitialBweBottleneck(inst, bottleneck_bits_per_second); } static inline int16_t SetMaxPayloadSize(instance_type* inst, int16_t max_payload_size_bytes) { return WebRtcIsac_SetMaxPayloadSize(inst, max_payload_size_bytes); } static inline int16_t SetMaxRate(instance_type* inst, int32_t max_bit_rate) { return WebRtcIsac_SetMaxRate(inst, max_bit_rate); } }; } // namespace webrtc #endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_FLOAT_TYPE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/isac_vad.c0000664000175000017500000003612414475643423030576 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_coding/codecs/isac/main/source/isac_vad.h" #include void WebRtcIsac_InitPitchFilter(PitchFiltstr* pitchfiltdata) { int k; for (k = 0; k < PITCH_BUFFSIZE; k++) { pitchfiltdata->ubuf[k] = 0.0; } pitchfiltdata->ystate[0] = 0.0; for (k = 1; k < (PITCH_DAMPORDER); k++) { pitchfiltdata->ystate[k] = 0.0; } pitchfiltdata->oldlagp[0] = 50.0; pitchfiltdata->oldgainp[0] = 0.0; } static void WebRtcIsac_InitWeightingFilter(WeightFiltstr* wfdata) { int k; double t, dtmp, dtmp2, denum, denum2; for (k = 0; k < PITCH_WLPCBUFLEN; k++) wfdata->buffer[k] = 0.0; for (k = 0; k < PITCH_WLPCORDER; k++) { wfdata->istate[k] = 0.0; wfdata->weostate[k] = 0.0; wfdata->whostate[k] = 0.0; } /* next part should be in Matlab, writing to a global table */ t = 0.5; denum = 1.0 / ((double)PITCH_WLPCWINLEN); denum2 = denum * denum; for (k = 0; k < PITCH_WLPCWINLEN; k++) { dtmp = PITCH_WLPCASYM * t * denum + (1 - PITCH_WLPCASYM) * t * t * denum2; dtmp *= 3.14159265; dtmp2 = sin(dtmp); wfdata->window[k] = dtmp2 * dtmp2; t++; } } void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct* State) { int k; for (k = 0; k < PITCH_CORR_LEN2 + PITCH_CORR_STEP2 + PITCH_MAX_LAG / 2 - PITCH_FRAME_LEN / 2 + 2; k++) State->dec_buffer[k] = 0.0; for (k = 0; k < 2 * ALLPASSSECTIONS + 1; k++) State->decimator_state[k] = 0.0; for (k = 0; k < 2; k++) State->hp_state[k] = 0.0; for (k = 0; k < QLOOKAHEAD; k++) State->whitened_buf[k] = 0.0; for (k = 0; k < QLOOKAHEAD; k++) State->inbuf[k] = 0.0; WebRtcIsac_InitPitchFilter(&(State->PFstr_wght)); WebRtcIsac_InitPitchFilter(&(State->PFstr)); WebRtcIsac_InitWeightingFilter(&(State->Wghtstr)); } void WebRtcIsac_InitPreFilterbank(PreFiltBankstr* prefiltdata) { int k; for (k = 0; k < QLOOKAHEAD; k++) { prefiltdata->INLABUF1[k] = 0; prefiltdata->INLABUF2[k] = 0; prefiltdata->INLABUF1_float[k] = 0; prefiltdata->INLABUF2_float[k] = 0; } for (k = 0; k < 2 * (QORDER - 1); k++) { prefiltdata->INSTAT1[k] = 0; prefiltdata->INSTAT2[k] = 0; prefiltdata->INSTATLA1[k] = 0; prefiltdata->INSTATLA2[k] = 0; prefiltdata->INSTAT1_float[k] = 0; prefiltdata->INSTAT2_float[k] = 0; prefiltdata->INSTATLA1_float[k] = 0; prefiltdata->INSTATLA2_float[k] = 0; } /* High pass filter states */ prefiltdata->HPstates[0] = 0.0; prefiltdata->HPstates[1] = 0.0; prefiltdata->HPstates_float[0] = 0.0f; prefiltdata->HPstates_float[1] = 0.0f; return; } double WebRtcIsac_LevDurb(double* a, double* k, double* r, size_t order) { const double LEVINSON_EPS = 1.0e-10; double sum, alpha; size_t m, m_h, i; alpha = 0; // warning -DH a[0] = 1.0; if (r[0] < LEVINSON_EPS) { /* if r[0] <= 0, set LPC coeff. to zero */ for (i = 0; i < order; i++) { k[i] = 0; a[i + 1] = 0; } } else { a[1] = k[0] = -r[1] / r[0]; alpha = r[0] + r[1] * k[0]; for (m = 1; m < order; m++) { sum = r[m + 1]; for (i = 0; i < m; i++) { sum += a[i + 1] * r[m - i]; } k[m] = -sum / alpha; alpha += k[m] * sum; m_h = (m + 1) >> 1; for (i = 0; i < m_h; i++) { sum = a[i + 1] + k[m] * a[m - i]; a[m - i] += k[m] * a[i + 1]; a[i + 1] = sum; } a[m + 1] = k[m]; } } return alpha; } /* The upper channel all-pass filter factors */ const float WebRtcIsac_kUpperApFactorsFloat[2] = {0.03470000000000f, 0.38260000000000f}; /* The lower channel all-pass filter factors */ const float WebRtcIsac_kLowerApFactorsFloat[2] = {0.15440000000000f, 0.74400000000000f}; /* This function performs all-pass filtering--a series of first order all-pass * sections are used to filter the input in a cascade manner. * The input is overwritten!! */ void WebRtcIsac_AllPassFilter2Float(float* InOut, const float* APSectionFactors, int lengthInOut, int NumberOfSections, float* FilterState) { int n, j; float temp; for (j = 0; j < NumberOfSections; j++) { for (n = 0; n < lengthInOut; n++) { temp = FilterState[j] + APSectionFactors[j] * InOut[n]; FilterState[j] = -APSectionFactors[j] * temp + InOut[n]; InOut[n] = temp; } } } /* The number of composite all-pass filter factors */ #define NUMBEROFCOMPOSITEAPSECTIONS 4 /* Function WebRtcIsac_SplitAndFilter * This function creates low-pass and high-pass decimated versions of part of the input signal, and part of the signal in the input 'lookahead buffer'. INPUTS: in: a length FRAMESAMPLES array of input samples prefiltdata: input data structure containing the filterbank states and lookahead samples from the previous encoding iteration. OUTPUTS: LP: a FRAMESAMPLES_HALF array of low-pass filtered samples that have been phase equalized. The first QLOOKAHEAD samples are based on the samples in the two prefiltdata->INLABUFx arrays each of length QLOOKAHEAD. The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input array in[]. HP: a FRAMESAMPLES_HALF array of high-pass filtered samples that have been phase equalized. The first QLOOKAHEAD samples are based on the samples in the two prefiltdata->INLABUFx arrays each of length QLOOKAHEAD. The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input array in[]. LP_la: a FRAMESAMPLES_HALF array of low-pass filtered samples. These samples are not phase equalized. They are computed from the samples in the in[] array. HP_la: a FRAMESAMPLES_HALF array of high-pass filtered samples that are not phase equalized. They are computed from the in[] vector. prefiltdata: this input data structure's filterbank state and lookahead sample buffers are updated for the next encoding iteration. */ void WebRtcIsac_SplitAndFilterFloat(float* pin, float* LP, float* HP, double* LP_la, double* HP_la, PreFiltBankstr* prefiltdata) { int k, n; float CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS]; float ForTransform_CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS]; float ForTransform_CompositeAPFilterState2[NUMBEROFCOMPOSITEAPSECTIONS]; float tempinoutvec[FRAMESAMPLES + MAX_AR_MODEL_ORDER]; float tempin_ch1[FRAMESAMPLES + MAX_AR_MODEL_ORDER]; float tempin_ch2[FRAMESAMPLES + MAX_AR_MODEL_ORDER]; float in[FRAMESAMPLES]; float ftmp; /* HPstcoeff_in = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; */ static const float kHpStCoefInFloat[4] = { -1.94895953203325f, 0.94984516000000f, -0.05101826139794f, 0.05015484000000f}; /* The composite all-pass filter factors */ static const float WebRtcIsac_kCompositeApFactorsFloat[4] = { 0.03470000000000f, 0.15440000000000f, 0.38260000000000f, 0.74400000000000f}; // The matrix for transforming the backward composite state to upper channel // state. static const float WebRtcIsac_kTransform1Float[8] = { -0.00158678506084f, 0.00127157815343f, -0.00104805672709f, 0.00084837248079f, 0.00134467983258f, -0.00107756549387f, 0.00088814793277f, -0.00071893072525f}; // The matrix for transforming the backward composite state to lower channel // state. static const float WebRtcIsac_kTransform2Float[8] = { -0.00170686041697f, 0.00136780109829f, -0.00112736532350f, 0.00091257055385f, 0.00103094281812f, -0.00082615076557f, 0.00068092756088f, -0.00055119165484f}; /* High pass filter */ for (k = 0; k < FRAMESAMPLES; k++) { in[k] = pin[k] + kHpStCoefInFloat[2] * prefiltdata->HPstates_float[0] + kHpStCoefInFloat[3] * prefiltdata->HPstates_float[1]; ftmp = pin[k] - kHpStCoefInFloat[0] * prefiltdata->HPstates_float[0] - kHpStCoefInFloat[1] * prefiltdata->HPstates_float[1]; prefiltdata->HPstates_float[1] = prefiltdata->HPstates_float[0]; prefiltdata->HPstates_float[0] = ftmp; } /* First Channel */ /*initial state of composite filter is zero */ for (k = 0; k < NUMBEROFCOMPOSITEAPSECTIONS; k++) { CompositeAPFilterState[k] = 0.0; } /* put every other sample of input into a temporary vector in reverse * (backward) order*/ for (k = 0; k < FRAMESAMPLES_HALF; k++) { tempinoutvec[k] = in[FRAMESAMPLES - 1 - 2 * k]; } /* now all-pass filter the backwards vector. Output values overwrite the * input vector. */ WebRtcIsac_AllPassFilter2Float( tempinoutvec, WebRtcIsac_kCompositeApFactorsFloat, FRAMESAMPLES_HALF, NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState); /* save the backwards filtered output for later forward filtering, but write it in forward order*/ for (k = 0; k < FRAMESAMPLES_HALF; k++) { tempin_ch1[FRAMESAMPLES_HALF + QLOOKAHEAD - 1 - k] = tempinoutvec[k]; } /* save the backwards filter state becaue it will be transformed later into a forward state */ for (k = 0; k < NUMBEROFCOMPOSITEAPSECTIONS; k++) { ForTransform_CompositeAPFilterState[k] = CompositeAPFilterState[k]; } /* now backwards filter the samples in the lookahead buffer. The samples were placed there in the encoding of the previous frame. The output samples overwrite the input samples */ WebRtcIsac_AllPassFilter2Float( prefiltdata->INLABUF1_float, WebRtcIsac_kCompositeApFactorsFloat, QLOOKAHEAD, NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState); /* save the output, but write it in forward order */ /* write the lookahead samples for the next encoding iteration. Every other sample at the end of the input frame is written in reverse order for the lookahead length. Exported in the prefiltdata structure. */ for (k = 0; k < QLOOKAHEAD; k++) { tempin_ch1[QLOOKAHEAD - 1 - k] = prefiltdata->INLABUF1_float[k]; prefiltdata->INLABUF1_float[k] = in[FRAMESAMPLES - 1 - 2 * k]; } /* Second Channel. This is exactly like the first channel, except that the even samples are now filtered instead (lower channel). */ for (k = 0; k < NUMBEROFCOMPOSITEAPSECTIONS; k++) { CompositeAPFilterState[k] = 0.0; } for (k = 0; k < FRAMESAMPLES_HALF; k++) { tempinoutvec[k] = in[FRAMESAMPLES - 2 - 2 * k]; } WebRtcIsac_AllPassFilter2Float( tempinoutvec, WebRtcIsac_kCompositeApFactorsFloat, FRAMESAMPLES_HALF, NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState); for (k = 0; k < FRAMESAMPLES_HALF; k++) { tempin_ch2[FRAMESAMPLES_HALF + QLOOKAHEAD - 1 - k] = tempinoutvec[k]; } for (k = 0; k < NUMBEROFCOMPOSITEAPSECTIONS; k++) { ForTransform_CompositeAPFilterState2[k] = CompositeAPFilterState[k]; } WebRtcIsac_AllPassFilter2Float( prefiltdata->INLABUF2_float, WebRtcIsac_kCompositeApFactorsFloat, QLOOKAHEAD, NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState); for (k = 0; k < QLOOKAHEAD; k++) { tempin_ch2[QLOOKAHEAD - 1 - k] = prefiltdata->INLABUF2_float[k]; prefiltdata->INLABUF2_float[k] = in[FRAMESAMPLES - 2 - 2 * k]; } /* Transform filter states from backward to forward */ /*At this point, each of the states of the backwards composite filters for the two channels are transformed into forward filtering states for the corresponding forward channel filters. Each channel's forward filtering state from the previous encoding iteration is added to the transformed state to get a proper forward state */ /* So the existing NUMBEROFCOMPOSITEAPSECTIONS x 1 (4x1) state vector is multiplied by a NUMBEROFCHANNELAPSECTIONSxNUMBEROFCOMPOSITEAPSECTIONS (2x4) transform matrix to get the new state that is added to the previous 2x1 input state */ for (k = 0; k < NUMBEROFCHANNELAPSECTIONS; k++) { /* k is row variable */ for (n = 0; n < NUMBEROFCOMPOSITEAPSECTIONS; n++) { /* n is column variable */ prefiltdata->INSTAT1_float[k] += ForTransform_CompositeAPFilterState[n] * WebRtcIsac_kTransform1Float[k * NUMBEROFCHANNELAPSECTIONS + n]; prefiltdata->INSTAT2_float[k] += ForTransform_CompositeAPFilterState2[n] * WebRtcIsac_kTransform2Float[k * NUMBEROFCHANNELAPSECTIONS + n]; } } /*obtain polyphase components by forward all-pass filtering through each * channel */ /* the backward filtered samples are now forward filtered with the * corresponding channel filters */ /* The all pass filtering automatically updates the filter states which are exported in the prefiltdata structure */ WebRtcIsac_AllPassFilter2Float(tempin_ch1, WebRtcIsac_kUpperApFactorsFloat, FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTAT1_float); WebRtcIsac_AllPassFilter2Float(tempin_ch2, WebRtcIsac_kLowerApFactorsFloat, FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTAT2_float); /* Now Construct low-pass and high-pass signals as combinations of polyphase * components */ for (k = 0; k < FRAMESAMPLES_HALF; k++) { LP[k] = 0.5f * (tempin_ch1[k] + tempin_ch2[k]); /* low pass signal*/ HP[k] = 0.5f * (tempin_ch1[k] - tempin_ch2[k]); /* high pass signal*/ } /* Lookahead LP and HP signals */ /* now create low pass and high pass signals of the input vector. However, no backwards filtering is performed, and hence no phase equalization is involved. Also, the input contains some samples that are lookahead samples. The high pass and low pass signals that are created are used outside this function for analysis (not encoding) purposes */ /* set up input */ for (k = 0; k < FRAMESAMPLES_HALF; k++) { tempin_ch1[k] = in[2 * k + 1]; tempin_ch2[k] = in[2 * k]; } /* the input filter states are passed in and updated by the all-pass filtering routine and exported in the prefiltdata structure*/ WebRtcIsac_AllPassFilter2Float(tempin_ch1, WebRtcIsac_kUpperApFactorsFloat, FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTATLA1_float); WebRtcIsac_AllPassFilter2Float(tempin_ch2, WebRtcIsac_kLowerApFactorsFloat, FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTATLA2_float); for (k = 0; k < FRAMESAMPLES_HALF; k++) { LP_la[k] = (float)(0.5f * (tempin_ch1[k] + tempin_ch2[k])); /*low pass */ HP_la[k] = (double)(0.5f * (tempin_ch1[k] - tempin_ch2[k])); /* high pass */ } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/isac_vad.h0000664000175000017500000000352614475643423030603 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_VAD_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_VAD_H_ #include #include "modules/audio_coding/codecs/isac/main/source/structs.h" void WebRtcIsac_InitPitchFilter(PitchFiltstr* pitchfiltdata); void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct* state); void WebRtcIsac_InitPreFilterbank(PreFiltBankstr* prefiltdata); double WebRtcIsac_LevDurb(double* a, double* k, double* r, size_t order); /* The number of all-pass filter factors in an upper or lower channel*/ #define NUMBEROFCHANNELAPSECTIONS 2 /* The upper channel all-pass filter factors */ extern const float WebRtcIsac_kUpperApFactorsFloat[2]; /* The lower channel all-pass filter factors */ extern const float WebRtcIsac_kLowerApFactorsFloat[2]; void WebRtcIsac_AllPassFilter2Float(float* InOut, const float* APSectionFactors, int lengthInOut, int NumberOfSections, float* FilterState); void WebRtcIsac_SplitAndFilterFloat(float* in, float* LP, float* HP, double* LP_la, double* HP_la, PreFiltBankstr* prefiltdata); #endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_VAD_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/lattice.c0000664000175000017500000001352014475643423030445 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * lattice.c * * contains the normalized lattice filter routines (MA and AR) for iSAC codec * */ #include #include #include #ifdef WEBRTC_ANDROID #include #endif #include "modules/audio_coding/codecs/isac/main/source/settings.h" #include "modules/audio_coding/codecs/isac/main/source/codec.h" /* filter the signal using normalized lattice filter */ /* MA filter */ void WebRtcIsac_NormLatticeFilterMa(int orderCoef, float *stateF, float *stateG, float *lat_in, double *filtcoeflo, double *lat_out) { int n,k,i,u,temp1; int ord_1 = orderCoef+1; float sth[MAX_AR_MODEL_ORDER]; float cth[MAX_AR_MODEL_ORDER]; float inv_cth[MAX_AR_MODEL_ORDER]; double a[MAX_AR_MODEL_ORDER+1]; float f[MAX_AR_MODEL_ORDER+1][HALF_SUBFRAMELEN], g[MAX_AR_MODEL_ORDER+1][HALF_SUBFRAMELEN]; float gain1; for (u=0;u=0;i--) //get the state of f&g for the first input, for all orders { ARf[i][0] = cth[i]*ARf[i+1][0] - sth[i]*stateG[i]; ARg[i+1][0] = sth[i]*ARf[i+1][0] + cth[i]* stateG[i]; } ARg[0][0] = ARf[0][0]; for(n=0;n<(HALF_SUBFRAMELEN-1);n++) { for(k=orderCoef-1;k>=0;k--) { ARf[k][n+1] = cth[k]*ARf[k+1][n+1] - sth[k]*ARg[k][n]; ARg[k+1][n+1] = sth[k]*ARf[k+1][n+1] + cth[k]* ARg[k][n]; } ARg[0][n+1] = ARf[0][n+1]; } memcpy(lat_out+u * HALF_SUBFRAMELEN, &(ARf[0][0]), sizeof(float) * HALF_SUBFRAMELEN); /* cannot use memcpy in the following */ for (i=0;i0; m--) { tmp_inv = 1.0f / cth2; for (k=1; k<=m; k++) { tmp[k] = ((float)a[k] - sth[m] * (float)a[m-k+1]) * tmp_inv; } for (k=1; k #include #include "modules/audio_coding/codecs/isac/main/source/lpc_analysis.h" #include "modules/audio_coding/codecs/isac/main/source/settings.h" #include "modules/audio_coding/codecs/isac/main/source/codec.h" #include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h" #include "modules/audio_coding/codecs/isac/main/source/filter_functions.h" #include "modules/audio_coding/codecs/isac/main/source/isac_vad.h" /* window */ /* Matlab generation code: * t = (1:256)/257; r = 1-(1-t).^.45; w = sin(r*pi).^3; w = w/sum(w); plot((1:256)/8, w); grid; * for k=1:16, fprintf(1, '%.8f, ', w(k*16 + (-15:0))); fprintf(1, '\n'); end */ static const double kLpcCorrWindow[WINLEN] = { 0.00000000, 0.00000001, 0.00000004, 0.00000010, 0.00000020, 0.00000035, 0.00000055, 0.00000083, 0.00000118, 0.00000163, 0.00000218, 0.00000283, 0.00000361, 0.00000453, 0.00000558, 0.00000679, 0.00000817, 0.00000973, 0.00001147, 0.00001342, 0.00001558, 0.00001796, 0.00002058, 0.00002344, 0.00002657, 0.00002997, 0.00003365, 0.00003762, 0.00004190, 0.00004651, 0.00005144, 0.00005673, 0.00006236, 0.00006837, 0.00007476, 0.00008155, 0.00008875, 0.00009636, 0.00010441, 0.00011290, 0.00012186, 0.00013128, 0.00014119, 0.00015160, 0.00016252, 0.00017396, 0.00018594, 0.00019846, 0.00021155, 0.00022521, 0.00023946, 0.00025432, 0.00026978, 0.00028587, 0.00030260, 0.00031998, 0.00033802, 0.00035674, 0.00037615, 0.00039626, 0.00041708, 0.00043863, 0.00046092, 0.00048396, 0.00050775, 0.00053233, 0.00055768, 0.00058384, 0.00061080, 0.00063858, 0.00066720, 0.00069665, 0.00072696, 0.00075813, 0.00079017, 0.00082310, 0.00085692, 0.00089164, 0.00092728, 0.00096384, 0.00100133, 0.00103976, 0.00107914, 0.00111947, 0.00116077, 0.00120304, 0.00124630, 0.00129053, 0.00133577, 0.00138200, 0.00142924, 0.00147749, 0.00152676, 0.00157705, 0.00162836, 0.00168070, 0.00173408, 0.00178850, 0.00184395, 0.00190045, 0.00195799, 0.00201658, 0.00207621, 0.00213688, 0.00219860, 0.00226137, 0.00232518, 0.00239003, 0.00245591, 0.00252284, 0.00259079, 0.00265977, 0.00272977, 0.00280078, 0.00287280, 0.00294582, 0.00301984, 0.00309484, 0.00317081, 0.00324774, 0.00332563, 0.00340446, 0.00348421, 0.00356488, 0.00364644, 0.00372889, 0.00381220, 0.00389636, 0.00398135, 0.00406715, 0.00415374, 0.00424109, 0.00432920, 0.00441802, 0.00450754, 0.00459773, 0.00468857, 0.00478001, 0.00487205, 0.00496464, 0.00505775, 0.00515136, 0.00524542, 0.00533990, 0.00543476, 0.00552997, 0.00562548, 0.00572125, 0.00581725, 0.00591342, 0.00600973, 0.00610612, 0.00620254, 0.00629895, 0.00639530, 0.00649153, 0.00658758, 0.00668341, 0.00677894, 0.00687413, 0.00696891, 0.00706322, 0.00715699, 0.00725016, 0.00734266, 0.00743441, 0.00752535, 0.00761540, 0.00770449, 0.00779254, 0.00787947, 0.00796519, 0.00804963, 0.00813270, 0.00821431, 0.00829437, 0.00837280, 0.00844949, 0.00852436, 0.00859730, 0.00866822, 0.00873701, 0.00880358, 0.00886781, 0.00892960, 0.00898884, 0.00904542, 0.00909923, 0.00915014, 0.00919805, 0.00924283, 0.00928436, 0.00932252, 0.00935718, 0.00938821, 0.00941550, 0.00943890, 0.00945828, 0.00947351, 0.00948446, 0.00949098, 0.00949294, 0.00949020, 0.00948262, 0.00947005, 0.00945235, 0.00942938, 0.00940099, 0.00936704, 0.00932738, 0.00928186, 0.00923034, 0.00917268, 0.00910872, 0.00903832, 0.00896134, 0.00887763, 0.00878706, 0.00868949, 0.00858478, 0.00847280, 0.00835343, 0.00822653, 0.00809199, 0.00794970, 0.00779956, 0.00764145, 0.00747530, 0.00730103, 0.00711857, 0.00692787, 0.00672888, 0.00652158, 0.00630597, 0.00608208, 0.00584994, 0.00560962, 0.00536124, 0.00510493, 0.00484089, 0.00456935, 0.00429062, 0.00400505, 0.00371310, 0.00341532, 0.00311238, 0.00280511, 0.00249452, 0.00218184, 0.00186864, 0.00155690, 0.00124918, 0.00094895, 0.00066112, 0.00039320, 0.00015881 }; static void WebRtcIsac_GetVars(const double* input, const int16_t* pitchGains_Q12, double* oldEnergy, double* varscale) { double nrg[4], chng, pg; int k; double pitchGains[4]={0,0,0,0};; /* Calculate energies of first and second frame halfs */ nrg[0] = 0.0001; for (k = QLOOKAHEAD/2; k < (FRAMESAMPLES_QUARTER + QLOOKAHEAD) / 2; k++) { nrg[0] += input[k]*input[k]; } nrg[1] = 0.0001; for ( ; k < (FRAMESAMPLES_HALF + QLOOKAHEAD) / 2; k++) { nrg[1] += input[k]*input[k]; } nrg[2] = 0.0001; for ( ; k < (FRAMESAMPLES*3/4 + QLOOKAHEAD) / 2; k++) { nrg[2] += input[k]*input[k]; } nrg[3] = 0.0001; for ( ; k < (FRAMESAMPLES + QLOOKAHEAD) / 2; k++) { nrg[3] += input[k]*input[k]; } /* Calculate average level change */ chng = 0.25 * (fabs(10.0 * log10(nrg[3] / nrg[2])) + fabs(10.0 * log10(nrg[2] / nrg[1])) + fabs(10.0 * log10(nrg[1] / nrg[0])) + fabs(10.0 * log10(nrg[0] / *oldEnergy))); /* Find average pitch gain */ pg = 0.0; for (k=0; k<4; k++) { pitchGains[k] = ((float)pitchGains_Q12[k])/4096; pg += pitchGains[k]; } pg *= 0.25; /* If pitch gain is low and energy constant - increase noise level*/ /* Matlab code: pg = 0:.01:.45; plot(pg, 0.0 + 1.0 * exp( -1.0 * exp(-200.0 * pg.*pg.*pg) / (1.0 + 0.4 * 0) )) */ *varscale = 0.0 + 1.0 * exp( -1.4 * exp(-200.0 * pg*pg*pg) / (1.0 + 0.4 * chng) ); *oldEnergy = nrg[3]; } static void WebRtcIsac_GetVarsUB(const double* input, double* oldEnergy, double* varscale) { double nrg[4], chng; int k; /* Calculate energies of first and second frame halfs */ nrg[0] = 0.0001; for (k = 0; k < (FRAMESAMPLES_QUARTER) / 2; k++) { nrg[0] += input[k]*input[k]; } nrg[1] = 0.0001; for ( ; k < (FRAMESAMPLES_HALF) / 2; k++) { nrg[1] += input[k]*input[k]; } nrg[2] = 0.0001; for ( ; k < (FRAMESAMPLES*3/4) / 2; k++) { nrg[2] += input[k]*input[k]; } nrg[3] = 0.0001; for ( ; k < (FRAMESAMPLES) / 2; k++) { nrg[3] += input[k]*input[k]; } /* Calculate average level change */ chng = 0.25 * (fabs(10.0 * log10(nrg[3] / nrg[2])) + fabs(10.0 * log10(nrg[2] / nrg[1])) + fabs(10.0 * log10(nrg[1] / nrg[0])) + fabs(10.0 * log10(nrg[0] / *oldEnergy))); /* If pitch gain is low and energy constant - increase noise level*/ /* Matlab code: pg = 0:.01:.45; plot(pg, 0.0 + 1.0 * exp( -1.0 * exp(-200.0 * pg.*pg.*pg) / (1.0 + 0.4 * 0) )) */ *varscale = exp( -1.4 / (1.0 + 0.4 * chng) ); *oldEnergy = nrg[3]; } void WebRtcIsac_GetLpcCoefLb(double *inLo, double *inHi, MaskFiltstr *maskdata, double signal_noise_ratio, const int16_t *pitchGains_Q12, double *lo_coeff, double *hi_coeff) { int k, n, j, pos1, pos2; double varscale; double DataLo[WINLEN], DataHi[WINLEN]; double corrlo[ORDERLO+2], corrlo2[ORDERLO+1]; double corrhi[ORDERHI+1]; double k_veclo[ORDERLO], k_vechi[ORDERHI]; double a_LO[ORDERLO+1], a_HI[ORDERHI+1]; double tmp, res_nrg; double FwdA, FwdB; /* hearing threshold level in dB; higher value gives more noise */ const double HearThresOffset = -28.0; /* bandwdith expansion factors for low- and high band */ const double gammaLo = 0.9; const double gammaHi = 0.8; /* less-noise-at-low-frequencies factor */ double aa; /* convert from dB to signal level */ const double H_T_H = pow(10.0, 0.05 * HearThresOffset); double S_N_R = pow(10.0, 0.05 * signal_noise_ratio) / 3.46; /* divide by sqrt(12) */ /* change quallevel depending on pitch gains and level fluctuations */ WebRtcIsac_GetVars(inLo, pitchGains_Q12, &(maskdata->OldEnergy), &varscale); /* less-noise-at-low-frequencies factor */ aa = 0.35 * (0.5 + 0.5 * varscale); /* replace data in buffer by new look-ahead data */ for (pos1 = 0; pos1 < QLOOKAHEAD; pos1++) maskdata->DataBufferLo[pos1 + WINLEN - QLOOKAHEAD] = inLo[pos1]; for (k = 0; k < SUBFRAMES; k++) { /* Update input buffer and multiply signal with window */ for (pos1 = 0; pos1 < WINLEN - UPDATE/2; pos1++) { maskdata->DataBufferLo[pos1] = maskdata->DataBufferLo[pos1 + UPDATE/2]; maskdata->DataBufferHi[pos1] = maskdata->DataBufferHi[pos1 + UPDATE/2]; DataLo[pos1] = maskdata->DataBufferLo[pos1] * kLpcCorrWindow[pos1]; DataHi[pos1] = maskdata->DataBufferHi[pos1] * kLpcCorrWindow[pos1]; } pos2 = k * UPDATE/2; for (n = 0; n < UPDATE/2; n++, pos1++) { maskdata->DataBufferLo[pos1] = inLo[QLOOKAHEAD + pos2]; maskdata->DataBufferHi[pos1] = inHi[pos2++]; DataLo[pos1] = maskdata->DataBufferLo[pos1] * kLpcCorrWindow[pos1]; DataHi[pos1] = maskdata->DataBufferHi[pos1] * kLpcCorrWindow[pos1]; } /* Get correlation coefficients */ WebRtcIsac_AutoCorr(corrlo, DataLo, WINLEN, ORDERLO+1); /* computing autocorrelation */ WebRtcIsac_AutoCorr(corrhi, DataHi, WINLEN, ORDERHI); /* less noise for lower frequencies, by filtering/scaling autocorrelation sequences */ corrlo2[0] = (1.0+aa*aa) * corrlo[0] - 2.0*aa * corrlo[1]; tmp = (1.0 + aa*aa); for (n = 1; n <= ORDERLO; n++) { corrlo2[n] = tmp * corrlo[n] - aa * (corrlo[n-1] + corrlo[n+1]); } tmp = (1.0+aa) * (1.0+aa); for (n = 0; n <= ORDERHI; n++) { corrhi[n] = tmp * corrhi[n]; } /* add white noise floor */ corrlo2[0] += 1e-6; corrhi[0] += 1e-6; FwdA = 0.01; FwdB = 0.01; /* recursive filtering of correlation over subframes */ for (n = 0; n <= ORDERLO; n++) { maskdata->CorrBufLo[n] = FwdA * maskdata->CorrBufLo[n] + corrlo2[n]; corrlo2[n] = ((1.0-FwdA)*FwdB) * maskdata->CorrBufLo[n] + (1.0-FwdB) * corrlo2[n]; } for (n = 0; n <= ORDERHI; n++) { maskdata->CorrBufHi[n] = FwdA * maskdata->CorrBufHi[n] + corrhi[n]; corrhi[n] = ((1.0-FwdA)*FwdB) * maskdata->CorrBufHi[n] + (1.0-FwdB) * corrhi[n]; } /* compute prediction coefficients */ WebRtcIsac_LevDurb(a_LO, k_veclo, corrlo2, ORDERLO); WebRtcIsac_LevDurb(a_HI, k_vechi, corrhi, ORDERHI); /* bandwidth expansion */ tmp = gammaLo; for (n = 1; n <= ORDERLO; n++) { a_LO[n] *= tmp; tmp *= gammaLo; } /* residual energy */ res_nrg = 0.0; for (j = 0; j <= ORDERLO; j++) { for (n = 0; n <= j; n++) { res_nrg += a_LO[j] * corrlo2[j-n] * a_LO[n]; } for (n = j+1; n <= ORDERLO; n++) { res_nrg += a_LO[j] * corrlo2[n-j] * a_LO[n]; } } /* add hearing threshold and compute the gain */ *lo_coeff++ = S_N_R / (sqrt(res_nrg) / varscale + H_T_H); /* copy coefficients to output array */ for (n = 1; n <= ORDERLO; n++) { *lo_coeff++ = a_LO[n]; } /* bandwidth expansion */ tmp = gammaHi; for (n = 1; n <= ORDERHI; n++) { a_HI[n] *= tmp; tmp *= gammaHi; } /* residual energy */ res_nrg = 0.0; for (j = 0; j <= ORDERHI; j++) { for (n = 0; n <= j; n++) { res_nrg += a_HI[j] * corrhi[j-n] * a_HI[n]; } for (n = j+1; n <= ORDERHI; n++) { res_nrg += a_HI[j] * corrhi[n-j] * a_HI[n]; } } /* add hearing threshold and compute of the gain */ *hi_coeff++ = S_N_R / (sqrt(res_nrg) / varscale + H_T_H); /* copy coefficients to output array */ for (n = 1; n <= ORDERHI; n++) { *hi_coeff++ = a_HI[n]; } } } /****************************************************************************** * WebRtcIsac_GetLpcCoefUb() * * Compute LP coefficients and correlation coefficients. At 12 kHz LP * coefficients of the first and the last sub-frame is computed. At 16 kHz * LP coefficients of 4th, 8th and 12th sub-frames are computed. We always * compute correlation coefficients of all sub-frames. * * Inputs: * -inSignal : Input signal * -maskdata : a structure keeping signal from previous frame. * -bandwidth : specifies if the codec is in 0-16 kHz mode or * 0-12 kHz mode. * * Outputs: * -lpCoeff : pointer to a buffer where A-polynomials are * written to (first coeff is 1 and it is not * written) * -corrMat : a matrix where correlation coefficients of each * sub-frame are written to one row. * -varscale : a scale used to compute LPC gains. */ void WebRtcIsac_GetLpcCoefUb( double* inSignal, MaskFiltstr* maskdata, double* lpCoeff, double corrMat[][UB_LPC_ORDER + 1], double* varscale, int16_t bandwidth) { int frameCntr, activeFrameCntr, n, pos1, pos2; int16_t criterion1; int16_t criterion2; int16_t numSubFrames = SUBFRAMES * (1 + (bandwidth == isac16kHz)); double data[WINLEN]; double corrSubFrame[UB_LPC_ORDER+2]; double reflecCoeff[UB_LPC_ORDER]; double aPolynom[UB_LPC_ORDER+1]; double tmp; /* bandwdith expansion factors */ const double gamma = 0.9; /* change quallevel depending on pitch gains and level fluctuations */ WebRtcIsac_GetVarsUB(inSignal, &(maskdata->OldEnergy), varscale); /* replace data in buffer by new look-ahead data */ for(frameCntr = 0, activeFrameCntr = 0; frameCntr < numSubFrames; frameCntr++) { if(frameCntr == SUBFRAMES) { // we are in 16 kHz varscale++; WebRtcIsac_GetVarsUB(&inSignal[FRAMESAMPLES_HALF], &(maskdata->OldEnergy), varscale); } /* Update input buffer and multiply signal with window */ for(pos1 = 0; pos1 < WINLEN - UPDATE/2; pos1++) { maskdata->DataBufferLo[pos1] = maskdata->DataBufferLo[pos1 + UPDATE/2]; data[pos1] = maskdata->DataBufferLo[pos1] * kLpcCorrWindow[pos1]; } pos2 = frameCntr * UPDATE/2; for(n = 0; n < UPDATE/2; n++, pos1++, pos2++) { maskdata->DataBufferLo[pos1] = inSignal[pos2]; data[pos1] = maskdata->DataBufferLo[pos1] * kLpcCorrWindow[pos1]; } /* Get correlation coefficients */ /* computing autocorrelation */ WebRtcIsac_AutoCorr(corrSubFrame, data, WINLEN, UB_LPC_ORDER+1); memcpy(corrMat[frameCntr], corrSubFrame, (UB_LPC_ORDER+1)*sizeof(double)); criterion1 = ((frameCntr == 0) || (frameCntr == (SUBFRAMES - 1))) && (bandwidth == isac12kHz); criterion2 = (((frameCntr+1) % 4) == 0) && (bandwidth == isac16kHz); if(criterion1 || criterion2) { /* add noise */ corrSubFrame[0] += 1e-6; /* compute prediction coefficients */ WebRtcIsac_LevDurb(aPolynom, reflecCoeff, corrSubFrame, UB_LPC_ORDER); /* bandwidth expansion */ tmp = gamma; for (n = 1; n <= UB_LPC_ORDER; n++) { *lpCoeff++ = aPolynom[n] * tmp; tmp *= gamma; } activeFrameCntr++; } } } /****************************************************************************** * WebRtcIsac_GetLpcGain() * * Compute the LPC gains for each sub-frame, given the LPC of each sub-frame * and the corresponding correlation coefficients. * * Inputs: * -signal_noise_ratio : the desired SNR in dB. * -numVecs : number of sub-frames * -corrMat : a matrix of correlation coefficients where * each row is a set of correlation coefficients of * one sub-frame. * -varscale : a scale computed when WebRtcIsac_GetLpcCoefUb() * is called. * * Outputs: * -gain : pointer to a buffer where LP gains are written. * */ void WebRtcIsac_GetLpcGain( double signal_noise_ratio, const double* filtCoeffVecs, int numVecs, double* gain, double corrMat[][UB_LPC_ORDER + 1], const double* varscale) { int16_t j, n; int16_t subFrameCntr; double aPolynom[ORDERLO + 1]; double res_nrg; const double HearThresOffset = -28.0; const double H_T_H = pow(10.0, 0.05 * HearThresOffset); /* divide by sqrt(12) = 3.46 */ const double S_N_R = pow(10.0, 0.05 * signal_noise_ratio) / 3.46; aPolynom[0] = 1; for(subFrameCntr = 0; subFrameCntr < numVecs; subFrameCntr++) { if(subFrameCntr == SUBFRAMES) { // we are in second half of a SWB frame. use new varscale varscale++; } memcpy(&aPolynom[1], &filtCoeffVecs[(subFrameCntr * (UB_LPC_ORDER + 1)) + 1], sizeof(double) * UB_LPC_ORDER); /* residual energy */ res_nrg = 0.0; for(j = 0; j <= UB_LPC_ORDER; j++) { for(n = 0; n <= j; n++) { res_nrg += aPolynom[j] * corrMat[subFrameCntr][j-n] * aPolynom[n]; } for(n = j+1; n <= UB_LPC_ORDER; n++) { res_nrg += aPolynom[j] * corrMat[subFrameCntr][n-j] * aPolynom[n]; } } /* add hearing threshold and compute the gain */ gain[subFrameCntr] = S_N_R / (sqrt(res_nrg) / *varscale + H_T_H); } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_analysis.h0000664000175000017500000000335114475643423031507 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * lpc_analysis.h * * LPC functions * */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYSIS_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYSIS_H_ #include "modules/audio_coding/codecs/isac/main/source/settings.h" #include "modules/audio_coding/codecs/isac/main/source/structs.h" void WebRtcIsac_GetLpcCoefLb(double* inLo, double* inHi, MaskFiltstr* maskdata, double signal_noise_ratio, const int16_t* pitchGains_Q12, double* lo_coeff, double* hi_coeff); void WebRtcIsac_GetLpcGain(double signal_noise_ratio, const double* filtCoeffVecs, int numVecs, double* gain, double corrLo[][UB_LPC_ORDER + 1], const double* varscale); void WebRtcIsac_GetLpcCoefUb(double* inSignal, MaskFiltstr* maskdata, double* lpCoeff, double corr[][UB_LPC_ORDER + 1], double* varscale, int16_t bandwidth); #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYIS_H_ */ ././@PaxHeader0000000000000000000000000000020500000000000010212 xustar00111 path=webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.c 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.0000664000175000017500000001206414475643423032640 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * SWB_KLT_Tables_LPCGain.c * * This file defines tables used for entropy coding of LPC Gain * of upper-band. * */ #include "modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h" #include "modules/audio_coding/codecs/isac/main/source/settings.h" const double WebRtcIsac_kQSizeLpcGain = 0.100000; const double WebRtcIsac_kMeanLpcGain = -3.3822; /* * The smallest reconstruction points for quantiztion of * LPC gains. */ const double WebRtcIsac_kLeftRecPointLpcGain[SUBFRAMES] = { -0.800000, -1.000000, -1.200000, -2.200000, -3.000000, -12.700000 }; /* * Number of reconstruction points of quantizers for LPC Gains. */ const int16_t WebRtcIsac_kNumQCellLpcGain[SUBFRAMES] = { 17, 20, 25, 45, 77, 170 }; /* * Starting index for entropy decoder to search for the right interval, * one entry per LAR coefficient */ const uint16_t WebRtcIsac_kLpcGainEntropySearch[SUBFRAMES] = { 8, 10, 12, 22, 38, 85 }; /* * The following 6 vectors define CDF of 6 decorrelated LPC * gains. */ const uint16_t WebRtcIsac_kLpcGainCdfVec0[18] = { 0, 10, 27, 83, 234, 568, 1601, 4683, 16830, 57534, 63437, 64767, 65229, 65408, 65483, 65514, 65527, 65535 }; const uint16_t WebRtcIsac_kLpcGainCdfVec1[21] = { 0, 15, 33, 84, 185, 385, 807, 1619, 3529, 7850, 19488, 51365, 62437, 64548, 65088, 65304, 65409, 65484, 65507, 65522, 65535 }; const uint16_t WebRtcIsac_kLpcGainCdfVec2[26] = { 0, 15, 29, 54, 89, 145, 228, 380, 652, 1493, 4260, 12359, 34133, 50749, 57224, 60814, 62927, 64078, 64742, 65103, 65311, 65418, 65473, 65509, 65521, 65535 }; const uint16_t WebRtcIsac_kLpcGainCdfVec3[46] = { 0, 8, 12, 16, 26, 42, 56, 76, 111, 164, 247, 366, 508, 693, 1000, 1442, 2155, 3188, 4854, 7387, 11249, 17617, 30079, 46711, 56291, 60127, 62140, 63258, 63954, 64384, 64690, 64891, 65031, 65139, 65227, 65293, 65351, 65399, 65438, 65467, 65492, 65504, 65510, 65518, 65523, 65535 }; const uint16_t WebRtcIsac_kLpcGainCdfVec4[78] = { 0, 17, 29, 39, 51, 70, 104, 154, 234, 324, 443, 590, 760, 971, 1202, 1494, 1845, 2274, 2797, 3366, 4088, 4905, 5899, 7142, 8683, 10625, 12983, 16095, 20637, 28216, 38859, 47237, 51537, 54150, 56066, 57583, 58756, 59685, 60458, 61103, 61659, 62144, 62550, 62886, 63186, 63480, 63743, 63954, 64148, 64320, 64467, 64600, 64719, 64837, 64939, 65014, 65098, 65160, 65211, 65250, 65290, 65325, 65344, 65366, 65391, 65410, 65430, 65447, 65460, 65474, 65487, 65494, 65501, 65509, 65513, 65518, 65520, 65535 }; const uint16_t WebRtcIsac_kLpcGainCdfVec5[171] = { 0, 10, 12, 14, 16, 18, 23, 29, 35, 42, 51, 58, 65, 72, 78, 87, 96, 103, 111, 122, 134, 150, 167, 184, 202, 223, 244, 265, 289, 315, 346, 379, 414, 450, 491, 532, 572, 613, 656, 700, 751, 802, 853, 905, 957, 1021, 1098, 1174, 1250, 1331, 1413, 1490, 1565, 1647, 1730, 1821, 1913, 2004, 2100, 2207, 2314, 2420, 2532, 2652, 2783, 2921, 3056, 3189, 3327, 3468, 3640, 3817, 3993, 4171, 4362, 4554, 4751, 4948, 5142, 5346, 5566, 5799, 6044, 6301, 6565, 6852, 7150, 7470, 7797, 8143, 8492, 8835, 9181, 9547, 9919, 10315, 10718, 11136, 11566, 12015, 12482, 12967, 13458, 13953, 14432, 14903, 15416, 15936, 16452, 16967, 17492, 18024, 18600, 19173, 19736, 20311, 20911, 21490, 22041, 22597, 23157, 23768, 24405, 25034, 25660, 26280, 26899, 27614, 28331, 29015, 29702, 30403, 31107, 31817, 32566, 33381, 34224, 35099, 36112, 37222, 38375, 39549, 40801, 42074, 43350, 44626, 45982, 47354, 48860, 50361, 51845, 53312, 54739, 56026, 57116, 58104, 58996, 59842, 60658, 61488, 62324, 63057, 63769, 64285, 64779, 65076, 65344, 65430, 65500, 65517, 65535 }; /* * An array of pointers to CDFs of decorrelated LPC Gains */ const uint16_t* WebRtcIsac_kLpcGainCdfMat[SUBFRAMES] = { WebRtcIsac_kLpcGainCdfVec0, WebRtcIsac_kLpcGainCdfVec1, WebRtcIsac_kLpcGainCdfVec2, WebRtcIsac_kLpcGainCdfVec3, WebRtcIsac_kLpcGainCdfVec4, WebRtcIsac_kLpcGainCdfVec5 }; /* * A matrix to decorrellate LPC gains of subframes. */ const double WebRtcIsac_kLpcGainDecorrMat[SUBFRAMES][SUBFRAMES] = { {-0.150860, 0.327872, 0.367220, 0.504613, 0.559270, 0.409234}, { 0.457128, -0.613591, -0.289283, -0.029734, 0.393760, 0.418240}, {-0.626043, 0.136489, -0.439118, -0.448323, 0.135987, 0.420869}, { 0.526617, 0.480187, 0.242552, -0.488754, -0.158713, 0.411331}, {-0.302587, -0.494953, 0.588112, -0.063035, -0.404290, 0.387510}, { 0.086378, 0.147714, -0.428875, 0.548300, -0.570121, 0.401391} }; ././@PaxHeader0000000000000000000000000000020500000000000010212 xustar00111 path=webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.0000664000175000017500000000304014475643423032632 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * SWB_KLT_Tables_LPCGain.h * * This file declares tables used for entropy coding of LPC Gain * of upper-band. * */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_ #include #include "modules/audio_coding/codecs/isac/main/source/settings.h" extern const double WebRtcIsac_kQSizeLpcGain; extern const double WebRtcIsac_kLeftRecPointLpcGain[SUBFRAMES]; extern const int16_t WebRtcIsac_kNumQCellLpcGain[SUBFRAMES]; extern const uint16_t WebRtcIsac_kLpcGainEntropySearch[SUBFRAMES]; extern const uint16_t WebRtcIsac_kLpcGainCdfVec0[18]; extern const uint16_t WebRtcIsac_kLpcGainCdfVec1[21]; extern const uint16_t WebRtcIsac_kLpcGainCdfVec2[26]; extern const uint16_t WebRtcIsac_kLpcGainCdfVec3[46]; extern const uint16_t WebRtcIsac_kLpcGainCdfVec4[78]; extern const uint16_t WebRtcIsac_kLpcGainCdfVec5[171]; extern const uint16_t* WebRtcIsac_kLpcGainCdfMat[SUBFRAMES]; extern const double WebRtcIsac_kLpcGainDecorrMat[SUBFRAMES][SUBFRAMES]; #endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_ ././@PaxHeader0000000000000000000000000000021000000000000010206 xustar00114 path=webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.c 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tabl0000664000175000017500000001206614475643423032561 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * SWB_KLT_Tables.c * * This file defines tables used for entropy coding of LPC shape of * upper-band signal if the bandwidth is 12 kHz. * */ #include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h" #include "modules/audio_coding/codecs/isac/main/source/settings.h" /* * Mean value of LAR */ const double WebRtcIsac_kMeanLarUb12[UB_LPC_ORDER] = { 0.03748928306641, 0.09453441192543, -0.01112522344398, 0.03800237516842 }; /* * A rotation matrix to decorrelate intra-vector correlation, * i.e. correlation among components of LAR vector. */ const double WebRtcIsac_kIntraVecDecorrMatUb12[UB_LPC_ORDER][UB_LPC_ORDER] = { {-0.00075365493856, -0.05809964887743, -0.23397966154116, 0.97050367376411}, { 0.00625021257734, -0.17299965610679, 0.95977735920651, 0.22104179375008}, { 0.20543384258374, -0.96202143495696, -0.15301870801552, -0.09432375099565}, {-0.97865075648479, -0.20300322280841, -0.02581111653779, -0.01913568980258} }; /* * A rotation matrix to remove correlation among LAR coefficients * of different LAR vectors. One might guess that decorrelation matrix * for the first component should differ from the second component * but we haven't observed a significant benefit of having different * decorrelation matrices for different components. */ const double WebRtcIsac_kInterVecDecorrMatUb12 [UB_LPC_VEC_PER_FRAME][UB_LPC_VEC_PER_FRAME] = { { 0.70650597970460, -0.70770707262373}, {-0.70770707262373, -0.70650597970460} }; /* * LAR quantization step-size. */ const double WebRtcIsac_kLpcShapeQStepSizeUb12 = 0.150000; /* * The smallest reconstruction points for quantiztion of LAR coefficients. */ const double WebRtcIsac_kLpcShapeLeftRecPointUb12 [UB_LPC_ORDER*UB_LPC_VEC_PER_FRAME] = { -0.900000, -1.050000, -1.350000, -1.800000, -1.350000, -1.650000, -2.250000, -3.450000 }; /* * Number of reconstruction points of quantizers for LAR coefficients. */ const int16_t WebRtcIsac_kLpcShapeNumRecPointUb12 [UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME] = { 13, 15, 19, 27, 19, 24, 32, 48 }; /* * Starting index for entropy decoder to search for the right interval, * one entry per LAR coefficient */ const uint16_t WebRtcIsac_kLpcShapeEntropySearchUb12 [UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME] = { 6, 7, 9, 13, 9, 12, 16, 24 }; /* * The following 8 vectors define CDF of 8 decorrelated LAR * coefficients. */ const uint16_t WebRtcIsac_kLpcShapeCdfVec0Ub12[14] = { 0, 13, 95, 418, 1687, 6498, 21317, 44200, 59029, 63849, 65147, 65449, 65525, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec1Ub12[16] = { 0, 10, 59, 255, 858, 2667, 8200, 22609, 42988, 57202, 62947, 64743, 65308, 65476, 65522, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec2Ub12[20] = { 0, 18, 40, 118, 332, 857, 2017, 4822, 11321, 24330, 41279, 54342, 60637, 63394, 64659, 65184, 65398, 65482, 65518, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec3Ub12[28] = { 0, 21, 38, 90, 196, 398, 770, 1400, 2589, 4650, 8211, 14933, 26044, 39592, 50814, 57452, 60971, 62884, 63995, 64621, 65019, 65273, 65410, 65480, 65514, 65522, 65531, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec4Ub12[20] = { 0, 7, 46, 141, 403, 969, 2132, 4649, 10633, 24902, 43254, 54665, 59928, 62674, 64173, 64938, 65293, 65464, 65523, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec5Ub12[25] = { 0, 7, 22, 72, 174, 411, 854, 1737, 3545, 6774, 13165, 25221, 40980, 52821, 58714, 61706, 63472, 64437, 64989, 65287, 65430, 65503, 65525, 65529, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec6Ub12[33] = { 0, 11, 21, 36, 65, 128, 228, 401, 707, 1241, 2126, 3589, 6060, 10517, 18853, 31114, 42477, 49770, 54271, 57467, 59838, 61569, 62831, 63772, 64433, 64833, 65123, 65306, 65419, 65466, 65499, 65519, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec7Ub12[49] = { 0, 14, 34, 67, 107, 167, 245, 326, 449, 645, 861, 1155, 1508, 2003, 2669, 3544, 4592, 5961, 7583, 9887, 13256, 18765, 26519, 34077, 40034, 44349, 47795, 50663, 53262, 55473, 57458, 59122, 60592, 61742, 62690, 63391, 63997, 64463, 64794, 65045, 65207, 65309, 65394, 65443, 65478, 65504, 65514, 65523, 65535 }; /* * An array of pointers to CDFs of decorrelated LARs */ const uint16_t* WebRtcIsac_kLpcShapeCdfMatUb12 [UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME] = { WebRtcIsac_kLpcShapeCdfVec0Ub12, WebRtcIsac_kLpcShapeCdfVec1Ub12, WebRtcIsac_kLpcShapeCdfVec2Ub12, WebRtcIsac_kLpcShapeCdfVec3Ub12, WebRtcIsac_kLpcShapeCdfVec4Ub12, WebRtcIsac_kLpcShapeCdfVec5Ub12, WebRtcIsac_kLpcShapeCdfVec6Ub12, WebRtcIsac_kLpcShapeCdfVec7Ub12 }; ././@PaxHeader0000000000000000000000000000021000000000000010206 xustar00114 path=webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tabl0000664000175000017500000000427614475643423032565 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * lpc_shape_swb12_tables.h * * This file declares tables used for entropy coding of LPC shape of * upper-band signal if the bandwidth is 12 kHz. * */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_ #include #include "modules/audio_coding/codecs/isac/main/source/settings.h" extern const double WebRtcIsac_kMeanLarUb12[UB_LPC_ORDER]; extern const double WebRtcIsac_kMeanLpcGain; extern const double WebRtcIsac_kIntraVecDecorrMatUb12[UB_LPC_ORDER] [UB_LPC_ORDER]; extern const double WebRtcIsac_kInterVecDecorrMatUb12[UB_LPC_VEC_PER_FRAME] [UB_LPC_VEC_PER_FRAME]; extern const double WebRtcIsac_kLpcShapeQStepSizeUb12; extern const double WebRtcIsac_kLpcShapeLeftRecPointUb12[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME]; extern const int16_t WebRtcIsac_kLpcShapeNumRecPointUb12[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME]; extern const uint16_t WebRtcIsac_kLpcShapeEntropySearchUb12[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec0Ub12[14]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec1Ub12[16]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec2Ub12[20]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec3Ub12[28]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec4Ub12[20]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec5Ub12[25]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec6Ub12[33]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec7Ub12[49]; extern const uint16_t* WebRtcIsac_kLpcShapeCdfMatUb12[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME]; #endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_ ././@PaxHeader0000000000000000000000000000021000000000000010206 xustar00114 path=webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.c 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tabl0000664000175000017500000002020514475643423032557 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * SWB16_KLT_Tables.c * * This file defines tables used for entropy coding of LPC shape of * upper-band signal if the bandwidth is 16 kHz. * */ #include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h" #include "modules/audio_coding/codecs/isac/main/source/settings.h" /* * Mean value of LAR */ const double WebRtcIsac_kMeanLarUb16[UB_LPC_ORDER] = { 0.454978, 0.364747, 0.102999, 0.104523 }; /* * A rotation matrix to decorrelate intra-vector correlation, * i.e. correlation among components of LAR vector. */ const double WebRtcIsac_kIintraVecDecorrMatUb16[UB_LPC_ORDER][UB_LPC_ORDER] = { {-0.020528, -0.085858, -0.002431, 0.996093}, {-0.033155, 0.036102, 0.998786, 0.004866}, { 0.202627, 0.974853, -0.028940, 0.088132}, {-0.978479, 0.202454, -0.039785, -0.002811} }; /* * A rotation matrix to remove correlation among LAR coefficients * of different LAR vectors. One might guess that decorrelation matrix * for the first component should differ from the second component * but we haven't observed a significant benefit of having different * decorrelation matrices for different components. */ const double WebRtcIsac_kInterVecDecorrMatUb16 [UB16_LPC_VEC_PER_FRAME][UB16_LPC_VEC_PER_FRAME] = { { 0.291675, -0.515786, 0.644927, 0.482658}, {-0.647220, 0.479712, 0.289556, 0.516856}, { 0.643084, 0.485489, -0.289307, 0.516763}, {-0.287185, -0.517823, -0.645389, 0.482553} }; /* * The following 16 vectors define CDF of 16 decorrelated LAR * coefficients. */ const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub16[14] = { 0, 2, 20, 159, 1034, 5688, 20892, 44653, 59849, 64485, 65383, 65518, 65534, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec1Ub16[16] = { 0, 1, 7, 43, 276, 1496, 6681, 21653, 43891, 58859, 64022, 65248, 65489, 65529, 65534, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec2Ub16[18] = { 0, 1, 9, 54, 238, 933, 3192, 9461, 23226, 42146, 56138, 62413, 64623, 65300, 65473, 65521, 65533, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec3Ub16[30] = { 0, 2, 4, 8, 17, 36, 75, 155, 329, 683, 1376, 2662, 5047, 9508, 17526, 29027, 40363, 48997, 55096, 59180, 61789, 63407, 64400, 64967, 65273, 65429, 65497, 65526, 65534, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec4Ub16[16] = { 0, 1, 10, 63, 361, 1785, 7407, 22242, 43337, 58125, 63729, 65181, 65472, 65527, 65534, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec5Ub16[17] = { 0, 1, 7, 29, 134, 599, 2443, 8590, 22962, 42635, 56911, 63060, 64940, 65408, 65513, 65531, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec6Ub16[21] = { 0, 1, 5, 16, 57, 191, 611, 1808, 4847, 11755, 24612, 40910, 53789, 60698, 63729, 64924, 65346, 65486, 65523, 65532, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec7Ub16[36] = { 0, 1, 4, 12, 25, 55, 104, 184, 314, 539, 926, 1550, 2479, 3861, 5892, 8845, 13281, 20018, 29019, 38029, 45581, 51557, 56057, 59284, 61517, 63047, 64030, 64648, 65031, 65261, 65402, 65480, 65518, 65530, 65534, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec8Ub16[21] = { 0, 1, 2, 7, 26, 103, 351, 1149, 3583, 10204, 23846, 41711, 55361, 61917, 64382, 65186, 65433, 65506, 65528, 65534, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub160[21] = { 0, 6, 19, 63, 205, 638, 1799, 4784, 11721, 24494, 40803, 53805, 60886, 63822, 64931, 65333, 65472, 65517, 65530, 65533, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub161[28] = { 0, 1, 3, 11, 31, 86, 221, 506, 1101, 2296, 4486, 8477, 15356, 26079, 38941, 49952, 57165, 61257, 63426, 64549, 65097, 65351, 65463, 65510, 65526, 65532, 65534, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub162[55] = { 0, 3, 12, 23, 42, 65, 89, 115, 150, 195, 248, 327, 430, 580, 784, 1099, 1586, 2358, 3651, 5899, 9568, 14312, 19158, 23776, 28267, 32663, 36991, 41153, 45098, 48680, 51870, 54729, 57141, 59158, 60772, 62029, 63000, 63761, 64322, 64728, 65000, 65192, 65321, 65411, 65463, 65496, 65514, 65523, 65527, 65529, 65531, 65532, 65533, 65534, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub163[26] = { 0, 2, 4, 10, 21, 48, 114, 280, 701, 1765, 4555, 11270, 24267, 41213, 54285, 61003, 63767, 64840, 65254, 65421, 65489, 65514, 65526, 65532, 65534, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub164[28] = { 0, 1, 3, 6, 15, 36, 82, 196, 453, 1087, 2557, 5923, 13016, 25366, 40449, 52582, 59539, 62896, 64389, 65033, 65316, 65442, 65494, 65519, 65529, 65533, 65534, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub165[34] = { 0, 2, 4, 8, 18, 35, 73, 146, 279, 524, 980, 1789, 3235, 5784, 10040, 16998, 27070, 38543, 48499, 55421, 59712, 62257, 63748, 64591, 65041, 65278, 65410, 65474, 65508, 65522, 65530, 65533, 65534, 65535 }; const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub166[71] = { 0, 1, 2, 6, 13, 26, 55, 92, 141, 191, 242, 296, 355, 429, 522, 636, 777, 947, 1162, 1428, 1753, 2137, 2605, 3140, 3743, 4409, 5164, 6016, 6982, 8118, 9451, 10993, 12754, 14810, 17130, 19780, 22864, 26424, 30547, 35222, 40140, 44716, 48698, 52056, 54850, 57162, 59068, 60643, 61877, 62827, 63561, 64113, 64519, 64807, 65019, 65167, 65272, 65343, 65399, 65440, 65471, 65487, 65500, 65509, 65518, 65524, 65527, 65531, 65533, 65534, 65535 }; /* * An array of pointers to CDFs of decorrelated LARs */ const uint16_t* WebRtcIsac_kLpcShapeCdfMatUb16 [UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME] = { WebRtcIsac_kLpcShapeCdfVec01Ub16, WebRtcIsac_kLpcShapeCdfVec1Ub16, WebRtcIsac_kLpcShapeCdfVec2Ub16, WebRtcIsac_kLpcShapeCdfVec3Ub16, WebRtcIsac_kLpcShapeCdfVec4Ub16, WebRtcIsac_kLpcShapeCdfVec5Ub16, WebRtcIsac_kLpcShapeCdfVec6Ub16, WebRtcIsac_kLpcShapeCdfVec7Ub16, WebRtcIsac_kLpcShapeCdfVec8Ub16, WebRtcIsac_kLpcShapeCdfVec01Ub160, WebRtcIsac_kLpcShapeCdfVec01Ub161, WebRtcIsac_kLpcShapeCdfVec01Ub162, WebRtcIsac_kLpcShapeCdfVec01Ub163, WebRtcIsac_kLpcShapeCdfVec01Ub164, WebRtcIsac_kLpcShapeCdfVec01Ub165, WebRtcIsac_kLpcShapeCdfVec01Ub166 }; /* * The smallest reconstruction points for quantiztion of LAR coefficients. */ const double WebRtcIsac_kLpcShapeLeftRecPointUb16 [UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME] = { -0.8250, -0.9750, -1.1250, -2.1750, -0.9750, -1.1250, -1.4250, -2.6250, -1.4250, -1.2750, -1.8750, -3.6750, -1.7250, -1.8750, -2.3250, -5.4750 }; /* * Number of reconstruction points of quantizers for LAR coefficients. */ const int16_t WebRtcIsac_kLpcShapeNumRecPointUb16 [UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME] = { 13, 15, 17, 29, 15, 16, 20, 35, 20, 20, 27, 54, 25, 27, 33, 70 }; /* * Starting index for entropy decoder to search for the right interval, * one entry per LAR coefficient */ const uint16_t WebRtcIsac_kLpcShapeEntropySearchUb16 [UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME] = { 6, 7, 8, 14, 7, 8, 10, 17, 10, 10, 13, 27, 12, 13, 16, 35 }; /* * LAR quantization step-size. */ const double WebRtcIsac_kLpcShapeQStepSizeUb16 = 0.150000; ././@PaxHeader0000000000000000000000000000021000000000000010206 xustar00114 path=webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tabl0000664000175000017500000000526714475643423032572 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * lpc_shape_swb16_tables.h * * This file declares tables used for entropy coding of LPC shape of * upper-band signal if the bandwidth is 16 kHz. * */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_ #include #include "modules/audio_coding/codecs/isac/main/source/settings.h" extern const double WebRtcIsac_kMeanLarUb16[UB_LPC_ORDER]; extern const double WebRtcIsac_kIintraVecDecorrMatUb16[UB_LPC_ORDER] [UB_LPC_ORDER]; extern const double WebRtcIsac_kInterVecDecorrMatUb16[UB16_LPC_VEC_PER_FRAME] [UB16_LPC_VEC_PER_FRAME]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub16[14]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec1Ub16[16]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec2Ub16[18]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec3Ub16[30]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec4Ub16[16]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec5Ub16[17]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec6Ub16[21]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec7Ub16[36]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec8Ub16[21]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub160[21]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub161[28]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub162[55]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub163[26]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub164[28]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub165[34]; extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub166[71]; extern const uint16_t* WebRtcIsac_kLpcShapeCdfMatUb16[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; extern const double WebRtcIsac_kLpcShapeLeftRecPointUb16[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; extern const int16_t WebRtcIsac_kLpcShapeNumRecPointUb16[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; extern const uint16_t WebRtcIsac_kLpcShapeEntropySearchUb16[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; extern const double WebRtcIsac_kLpcShapeQStepSizeUb16; #endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_tables.c0000664000175000017500000011066214475643423031135 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* coding tables for the KLT coefficients */ #include "modules/audio_coding/codecs/isac/main/source/lpc_tables.h" #include "modules/audio_coding/codecs/isac/main/source/settings.h" /* cdf array for model indicator */ const uint16_t WebRtcIsac_kQKltModelCdf[4] = { 0, 15434, 37548, 65535 }; /* pointer to cdf array for model indicator */ const uint16_t *WebRtcIsac_kQKltModelCdfPtr[1] = { WebRtcIsac_kQKltModelCdf }; /* initial cdf index for decoder of model indicator */ const uint16_t WebRtcIsac_kQKltModelInitIndex[1] = { 1 }; /* offset to go from rounded value to quantization index */ const short WebRtcIsac_kQKltQuantMinGain[12] = { 3, 6, 4, 6, 6, 9, 5, 16, 11, 34, 32, 47 }; const short WebRtcIsac_kQKltQuantMinShape[108] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 4, 3, 5, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 3, 4, 4, 7, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 3, 4, 4, 5, 7, 13, 0, 1, 1, 2, 3, 2, 2, 2, 4, 4, 5, 6, 7, 11, 9, 13, 12, 26 }; /* maximum quantization index */ const uint16_t WebRtcIsac_kQKltMaxIndGain[12] = { 6, 12, 8, 14, 10, 19, 12, 31, 22, 56, 52, 138 }; const uint16_t WebRtcIsac_kQKltMaxIndShape[108] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 4, 4, 5, 6, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 2, 2, 2, 2, 3, 4, 5, 7, 0, 0, 0, 0, 2, 0, 2, 2, 2, 2, 3, 2, 2, 4, 4, 6, 6, 9, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 3, 2, 4, 4, 7, 7, 9, 13, 0, 0, 2, 2, 2, 2, 2, 2, 3, 4, 5, 4, 6, 8, 8, 10, 16, 25, 0, 2, 2, 4, 5, 4, 4, 4, 7, 8, 9, 10, 13, 19, 17, 23, 25, 49 }; /* index offset */ const uint16_t WebRtcIsac_kQKltOffsetGain[12] = { 0, 7, 20, 29, 44, 55, 75, 88, 120, 143, 200, 253 }; const uint16_t WebRtcIsac_kQKltOffsetShape[108] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 14, 17, 20, 23, 28, 33, 39, 46, 47, 48, 49, 50, 52, 53, 54, 55, 56, 58, 61, 64, 67, 70, 74, 79, 85, 93, 94, 95, 96, 97, 100, 101, 104, 107, 110, 113, 117, 120, 123, 128, 133, 140, 147, 157, 158, 159, 160, 161, 164, 167, 170, 173, 176, 179, 183, 186, 191, 196, 204, 212, 222, 236, 237, 238, 241, 244, 247, 250, 253, 256, 260, 265, 271, 276, 283, 292, 301, 312, 329, 355, 356, 359, 362, 367, 373, 378, 383, 388, 396, 405, 415, 426, 440, 460, 478, 502, 528 }; /* initial cdf index for KLT coefficients */ const uint16_t WebRtcIsac_kQKltInitIndexGain[12] = { 3, 6, 4, 7, 5, 10, 6, 16, 11, 28, 26, 69}; const uint16_t WebRtcIsac_kQKltInitIndexShape[108] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 3, 3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 3, 4, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 2, 1, 1, 2, 2, 3, 3, 5, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 4, 4, 5, 7, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 2, 3, 4, 4, 5, 8, 13, 0, 1, 1, 2, 3, 2, 2, 2, 4, 4, 5, 5, 7, 10, 9, 12, 13, 25 }; /* quantizer representation levels */ const double WebRtcIsac_kQKltLevelsGain[392] = { -2.78127126, -1.76745590, -0.77913790, -0.00437329, 0.79961206, 1.81775776, 2.81389782, -5.78753143, -4.88384084, -3.89320940, -2.88133610, -1.92859977, -0.86347396, 0.02003888, 0.86140400, 1.89667156, 2.97134967, 3.98781964, 4.91727277, 5.82865898, -4.11195874, -2.80898424, -1.87547977, -0.80943825, -0.00679084, 0.79573851, 1.83953397, 2.67586037, 3.76274082, -6.10933968, -4.93034581, -3.89281296, -2.91530625, -1.89684163, -0.85319130, -0.02275767, 0.86862017, 1.91578276, 2.96107339, 3.96543056, 4.91369908, 5.91058154, 6.83848343, 8.07136925, -5.87470395, -4.84703049, -3.84284597, -2.86168446, -1.89290192, -0.82798145, -0.00080013, 0.82594974, 1.85754329, 2.88351798, 3.96172628, -8.85684885, -7.87387461, -6.97811862, -5.93256270, -4.94301439, -3.95513701, -2.96041544, -1.94031192, -0.87961478, -0.00456201, 0.89911505, 1.91723376, 2.94011511, 3.93302540, 4.97990967, 5.93133404, 7.02181199, 7.92407762, 8.80155440, 10.04665814, -4.82396678, -3.85612158, -2.89482244, -1.89558408, -0.90036978, -0.00677823, 0.90607989, 1.90937981, 2.91175777, 3.91637730, 4.97565723, 5.84771228, 7.11145863, -16.07879840, -15.03776309, -13.93905670, -12.95671800, -11.89171202, -10.95820934, -9.95923714, -8.94357334, -7.99068299, -6.97481009, -5.94826231, -4.96673988, -3.97490466, -2.97846970, -1.95130435, -0.94215262, -0.01444043, 0.96770704, 1.95848598, 2.94107862, 3.95666119, 4.97253085, 5.97191122, 6.93277360, 7.96608727, 8.87958779, 10.00264269, 10.86560820, 12.07449071, 13.04491775, 13.97507061, 14.91845261, -10.85696295, -9.83365357, -9.01245635, -7.95915145, -6.95625003, -5.95362618, -4.93468444, -3.98760978, -2.95044407, -1.97041277, -0.97701799, -0.00840234, 0.97834289, 1.98361415, 2.97802439, 3.96415871, 4.95369042, 5.94101770, 6.92756798, 7.94063998, 8.85951828, 9.97077022, 11.00068503, -33.92030406, -32.81426422, -32.00000000, -31.13243639, -30.11886909, -29.06017570, -28.12598824, -27.22045482, -25.81215858, -25.07849962, -23.93018013, -23.02097643, -21.89529725, -20.99091085, -19.98889048, -18.94327044, -17.96562071, -16.96126218, -15.95054062, -14.98516200, -13.97101012, -13.02106500, -11.98438006, -11.03216748, -9.95930286, -8.97043946, -7.98085082, -6.98360995, -5.98998802, -4.98668173, -4.00032906, -3.00420619, -1.98701132, -0.99324682, -0.00609324, 0.98297834, 1.99483076, 3.00305044, 3.97142097, 4.97525759, 5.98612258, 6.97448236, 7.97575900, 9.01086211, 9.98665542, 11.00541438, 11.98078628, 12.92352471, 14.06849675, 14.99949430, 15.94904834, 16.97440321, 18.04040916, 18.88987609, 20.05312391, 21.00000000, 21.79443341, -31.98578825, -31.00000000, -29.89060567, -28.98555686, -27.97114102, -26.84935410, -26.02402230, -24.94195278, -23.92336849, -22.95552382, -21.97932836, -20.96055470, -19.99649553, -19.03436122, -17.96706525, -17.01139515, -16.01363516, -14.99154248, -14.00298333, -12.99630613, -11.99955519, -10.99000421, -10.00819092, -8.99763648, -7.98431793, -7.01769025, -5.99604690, -4.99980697, -3.99334671, -3.01748192, -2.02051217, -1.00848371, -0.01942358, 1.00477757, 1.95477872, 2.98593031, 3.98779079, 4.96862849, 6.02694771, 6.93983733, 7.89874717, 8.99615862, 10.02367921, 10.96293452, 11.84351528, 12.92207187, 13.85122329, 15.05146877, 15.99371264, 17.00000000, 18.00000000, 19.00000000, 19.82763573, -47.00000000, -46.00000000, -44.87138498, -44.00000000, -43.00000000, -42.00000000, -41.00000000, -39.88966612, -38.98913239, -37.80306486, -37.23584325, -35.94200288, -34.99881301, -34.11361858, -33.06507360, -32.13129135, -30.90891364, -29.81511907, -28.99250380, -28.04535391, -26.99767800, -26.04418164, -24.95687851, -24.04865595, -23.03392645, -21.89366707, -20.93517364, -19.99388660, -18.91620943, -18.03749683, -16.99532379, -15.98683813, -15.06421479, -13.99359211, -12.99714098, -11.97022520, -10.98500279, -9.98834422, -8.95729330, -8.01232284, -7.00253661, -5.99681626, -5.01207817, -3.95914904, -3.01232178, -1.96615919, -0.97687670, 0.01228030, 0.98412288, 2.01753544, 3.00580570, 3.97783510, 4.98846894, 6.01321400, 7.00867732, 8.00416375, 9.01771966, 9.98637729, 10.98255180, 11.99194163, 13.01807333, 14.00999545, 15.00118556, 16.00089224, 17.00584148, 17.98251763, 18.99942091, 19.96917690, 20.97839265, 21.98207297, 23.00171271, 23.99930737, 24.99746061, 26.00936304, 26.98240132, 28.01126868, 29.01395915, 29.98153507, 31.01376711, 31.99876818, 33.00475317, 33.99753994, 34.99493913, 35.98933585, 36.95620160, 37.98428461, 38.99317544, 40.01832073, 40.98048133, 41.95999283, 42.98232091, 43.96523612, 44.99574268, 45.99524194, 47.05464025, 48.03821548, 48.99354366, 49.96400411, 50.98017973, 51.95184408, 52.96291806, 54.00194392, 54.96603783, 55.95623778, 57.03076595, 58.05889901, 58.99081551, 59.97928121, 61.05071612, 62.03971580, 63.01286038, 64.01290338, 65.02074503, 65.99454594, 67.00399425, 67.96571257, 68.95305727, 69.92030664, 70.95594862, 71.98088567, 73.04764124, 74.00285480, 75.02696330, 75.89837673, 76.93459997, 78.16266309, 78.83317543, 80.00000000, 80.87251574, 82.09803524, 83.10671664, 84.00000000, 84.77023523, 86.00000000, 87.00000000, 87.92946897, 88.69159118, 90.00000000, 90.90535270 }; const double WebRtcIsac_kQKltLevelsShape[578] = { 0.00032397, 0.00008053, -0.00061202, -0.00012620, 0.00030437, 0.00054764, -0.00027902, 0.00069360, 0.00029449, -0.80219239, 0.00091089, -0.74514927, -0.00094283, 0.64030631, -0.60509119, 0.00035575, 0.61851665, -0.62129957, 0.00375219, 0.60054900, -0.61554359, 0.00054977, 0.63362016, -1.73118727, -0.65422341, 0.00524568, 0.66165298, 1.76785515, -1.83182018, -0.65997434, -0.00011887, 0.67524299, 1.79933938, -1.76344480, -0.72547708, -0.00133017, 0.73104704, 1.75305377, 2.85164534, -2.80423916, -1.71959639, -0.75419722, -0.00329945, 0.77196760, 1.72211069, 2.87339653, 0.00031089, -0.00015311, 0.00018201, -0.00035035, -0.77357251, 0.00154647, -0.00047625, -0.00045299, 0.00086590, 0.00044762, -0.83383829, 0.00024787, -0.68526258, -0.00122472, 0.64643255, -0.60904942, -0.00448987, 0.62309184, -0.59626442, -0.00574132, 0.62296546, -0.63222115, 0.00013441, 0.63609545, -0.66911055, -0.00369971, 0.66346095, 2.07281301, -1.77184694, -0.67640425, -0.00010145, 0.64818392, 1.74948973, -1.69420224, -0.71943894, -0.00004680, 0.75303493, 1.81075983, 2.80610041, -2.80005755, -1.79866753, -0.77409777, -0.00084220, 0.80141293, 1.78291081, 2.73954236, 3.82994169, 0.00015140, -0.00012766, -0.00034241, -0.00119125, -0.76113497, 0.00069246, 0.76722027, 0.00132862, -0.69107530, 0.00010656, 0.77061578, -0.78012970, 0.00095947, 0.77828502, -0.64787758, 0.00217168, 0.63050167, -0.58601125, 0.00306596, 0.59466308, -0.58603410, 0.00059779, 0.64257970, 1.76512766, -0.61193600, -0.00259517, 0.59767574, -0.61026273, 0.00315811, 0.61725479, -1.69169719, -0.65816029, 0.00067575, 0.65576890, 2.00000000, -1.72689193, -0.69780808, -0.00040990, 0.70668487, 1.74198458, -3.79028154, -3.00000000, -1.73194459, -0.70179341, -0.00106695, 0.71302629, 1.76849782, -2.89332364, -1.78585007, -0.78731491, -0.00132610, 0.79692976, 1.75247009, 2.97828682, -5.26238694, -3.69559829, -2.87286122, -1.84908818, -0.84434577, -0.01167975, 0.84641753, 1.84087672, 2.87628156, 3.83556679, -0.00190204, 0.00092642, 0.00354385, -0.00012982, -0.67742785, 0.00229509, 0.64935672, -0.58444751, 0.00470733, 0.57299534, -0.58456202, -0.00097715, 0.64593607, -0.64060330, -0.00638534, 0.59680157, -0.59287537, 0.00490772, 0.58919707, -0.60306173, -0.00417464, 0.60562100, -1.75218757, -0.63018569, -0.00225922, 0.63863300, -0.63949939, -0.00126421, 0.64268914, -1.75851182, -0.68318060, 0.00510418, 0.69049211, 1.88178506, -1.71136148, -0.72710534, -0.00815559, 0.73412917, 1.79996711, -2.77111145, -1.73940498, -0.78212945, 0.01074476, 0.77688916, 1.76873972, 2.87281379, 3.77554698, -3.75832725, -2.95463235, -1.80451491, -0.80017226, 0.00149902, 0.80729206, 1.78265046, 2.89391793, -3.78236148, -2.83640598, -1.82532067, -0.88844327, -0.00620952, 0.88208030, 1.85757631, 2.81712391, 3.88430176, 5.16179367, -7.00000000, -5.93805408, -4.87172597, -3.87524433, -2.89399744, -1.92359563, -0.92136341, -0.00172725, 0.93087018, 1.90528280, 2.89809686, 3.88085708, 4.89147740, 5.89078692, -0.00239502, 0.00312564, -1.00000000, 0.00178325, 1.00000000, -0.62198029, 0.00143254, 0.65344051, -0.59851220, -0.00676987, 0.61510140, -0.58894151, 0.00385055, 0.59794203, -0.59808568, -0.00038214, 0.57625703, -0.63009713, -0.01107985, 0.61278758, -0.64206758, -0.00154369, 0.65480598, 1.80604162, -1.80909286, -0.67810514, 0.00205762, 0.68571097, 1.79453891, -3.22682422, -1.73808453, -0.71870305, -0.00738594, 0.71486172, 1.73005326, -1.66891897, -0.73689615, -0.00616203, 0.74262409, 1.73807899, -2.92417482, -1.73866741, -0.78133871, 0.00764425, 0.80027264, 1.78668732, 2.74992588, -4.00000000, -2.75578740, -1.83697516, -0.83117035, -0.00355191, 0.83527172, 1.82814700, 2.77377675, 3.80718693, -3.81667698, -2.83575471, -1.83372350, -0.86579471, 0.00547578, 0.87582281, 1.82858793, 2.87265007, 3.91405377, -4.87521600, -3.78999094, -2.86437014, -1.86964365, -0.90618018, 0.00128243, 0.91497811, 1.87374952, 2.83199819, 3.91519130, 4.76632822, -6.68713448, -6.01252467, -4.94587936, -3.88795368, -2.91299088, -1.92592211, -0.95504570, -0.00089980, 0.94565200, 1.93239633, 2.91832808, 3.91363475, 4.88920034, 5.96471415, 6.83905252, 7.86195009, 8.81571018,-12.96141759, -11.73039516,-10.96459719, -9.97382433, -9.04414433, -7.89460619, -6.96628608, -5.93236595, -4.93337924, -3.95479990, -2.96451499, -1.96635876, -0.97271229, -0.00402238, 0.98343930, 1.98348291, 2.96641164, 3.95456471, 4.95517089, 5.98975714, 6.90322073, 7.90468849, 8.85639467, 9.97255498, 10.79006309, 11.81988596, 0.04950500, -1.00000000, -0.01226628, 1.00000000, -0.59479469, -0.10438305, 0.59822144, -2.00000000, -0.67109149, -0.09256692, 0.65171621, 2.00000000, -3.00000000, -1.68391999, -0.76681039, -0.03354151, 0.71509146, 1.77615472, -2.00000000, -0.68661511, -0.02497881, 0.66478398, 2.00000000, -2.00000000, -0.67032784, -0.00920582, 0.64892756, 2.00000000, -2.00000000, -0.68561894, 0.03641869, 0.73021611, 1.68293863, -4.00000000, -2.72024184, -1.80096059, -0.81696185, 0.03604685, 0.79232033, 1.70070730, 3.00000000, -4.00000000, -2.71795670, -1.80482986, -0.86001162, 0.03764903, 0.87723968, 1.79970771, 2.72685932, 3.67589143, -5.00000000, -4.00000000, -2.85492548, -1.78996365, -0.83250358, -0.01376828, 0.84195506, 1.78161105, 2.76754458, 4.00000000, -6.00000000, -5.00000000, -3.82268811, -2.77563624, -1.82608163, -0.86486114, -0.02671886, 0.86693165, 1.88422879, 2.86248347, 3.95632216, -7.00000000, -6.00000000, -5.00000000, -3.77533988, -2.86391432, -1.87052039, -0.90513658, 0.06271236, 0.91083620, 1.85734756, 2.86031688, 3.82019418, 4.94420394, 6.00000000, -11.00000000,-10.00000000, -9.00000000, -8.00000000, -6.91952415, -6.00000000, -4.92044374, -3.87845165, -2.87392362, -1.88413020, -0.91915740, 0.00318517, 0.91602800, 1.89664838, 2.88925058, 3.84123856, 4.78988651, 5.94526812, 6.81953917, 8.00000000, -9.00000000, -8.00000000, -7.03319143, -5.94530963, -4.86669720, -3.92438007, -2.88620396, -1.92848070, -0.94365985, 0.01671855, 0.97349410, 1.93419878, 2.89740109, 3.89662823, 4.83235583, 5.88106535, 6.80328232, 8.00000000,-13.00000000,-12.00000000, -11.00000000,-10.00000000, -9.00000000, -7.86033489, -6.83344055, -5.89844215, -4.90811454, -3.94841298, -2.95820490, -1.98627966, -0.99161468, -0.02286136, 0.96055651, 1.95052433, 2.93969396, 3.94304346, 4.88522624, 5.87434241, 6.78309433, 7.87244101, 9.00000000, 10.00000000,-12.09117356,-11.00000000,-10.00000000, -8.84766108, -7.86934236, -6.98544896, -5.94233429, -4.95583292, -3.95575986, -2.97085529, -1.98955811, -0.99359873, -0.00485413, 0.98298870, 1.98093258, 2.96430203, 3.95540216, 4.96915010, 5.96775124, 6.99236918, 7.96503302, 8.99864542, 9.85857723, 10.96541926, 11.91647197, 12.71060069,-26.00000000,-25.00000000, -24.00585596,-23.11642573,-22.14271284,-20.89800711,-19.87815799, -19.05036354,-17.88555651,-16.86471209,-15.97711073,-14.94012359, -14.02661226,-12.98243228,-11.97489256,-10.97402777, -9.96425624, -9.01085220, -7.97372506, -6.98795002, -5.97271328, -5.00191694, -3.98055849, -2.98458048, -1.99470442, -0.99656768, -0.00825666, 1.00272004, 1.99922218, 2.99357669, 4.01407905, 5.01003897, 5.98115528, 7.00018958, 8.00338125, 8.98981046, 9.98990318, 10.96341479, 11.96866930, 12.99175139, 13.94580443, 14.95745083, 15.98992869, 16.97484646, 17.99630043, 18.93396897, 19.88347741, 20.96532482, 21.92191032, 23.22314702 }; /* cdf tables for quantizer indices */ const uint16_t WebRtcIsac_kQKltCdfGain[404] = { 0, 13, 301, 3730, 61784, 65167, 65489, 65535, 0, 17, 142, 314, 929, 2466, 7678, 56450, 63463, 64740, 65204, 65426, 65527, 65535, 0, 8, 100, 724, 6301, 60105, 65125, 65510, 65531, 65535, 0, 13, 117, 368, 1068, 3010, 11928, 53603, 61177, 63404, 64505, 65108, 65422, 65502, 65531, 65535, 0, 4, 17, 96, 410, 1859, 12125, 54361, 64103, 65305, 65497, 65535, 0, 4, 88, 230, 469, 950, 1746, 3228, 6092, 16592, 44756, 56848, 61256, 63308, 64325, 64920, 65309, 65460, 65502, 65522, 65535, 0, 88, 352, 1675, 6339, 20749, 46686, 59284, 63525, 64949, 65359, 65502, 65527, 65535, 0, 13, 38, 63, 117, 234, 381, 641, 929, 1407, 2043, 2809, 4032, 5753, 8792, 14407, 24308, 38941, 48947, 55403, 59293, 61411, 62688, 63630, 64329, 64840, 65188, 65376, 65472, 65506, 65527, 65531, 65535, 0, 8, 29, 75, 222, 615, 1327, 2801, 5623, 9931, 16094, 24966, 34419, 43458, 50676, 56186, 60055, 62500, 63936, 64765, 65225, 65435, 65514, 65535, 0, 8, 13, 15, 17, 21, 33, 59, 71, 92, 151, 243, 360, 456, 674, 934, 1223, 1583, 1989, 2504, 3031, 3617, 4354, 5154, 6163, 7411, 8780, 10747, 12874, 15591, 18974, 23027, 27436, 32020, 36948, 41830, 46205, 49797, 53042, 56094, 58418, 60360, 61763, 62818, 63559, 64103, 64509, 64798, 65045, 65162, 65288, 65363, 65447, 65506, 65522, 65531, 65533, 65535, 0, 4, 6, 25, 38, 71, 138, 264, 519, 808, 1227, 1825, 2516, 3408, 4279, 5560, 7092, 9197, 11420, 14108, 16947, 20300, 23926, 27459, 31164, 34827, 38575, 42178, 45540, 48747, 51444, 54090, 56426, 58460, 60080, 61595, 62734, 63668, 64275, 64673, 64936, 65112, 65217, 65334, 65426, 65464, 65477, 65489, 65518, 65527, 65529, 65531, 65533, 65535, 0, 2, 4, 8, 10, 12, 14, 16, 21, 33, 50, 71, 84, 92, 105, 138, 180, 255, 318, 377, 435, 473, 511, 590, 682, 758, 913, 1097, 1256, 1449, 1671, 1884, 2169, 2445, 2772, 3157, 3563, 3944, 4375, 4848, 5334, 5820, 6448, 7101, 7716, 8378, 9102, 9956, 10752, 11648, 12707, 13670, 14758, 15910, 17187, 18472, 19627, 20649, 21951, 23169, 24283, 25552, 26862, 28227, 29391, 30764, 31882, 33213, 34432, 35600, 36910, 38116, 39464, 40729, 41872, 43144, 44371, 45514, 46762, 47813, 48968, 50069, 51032, 51974, 52908, 53737, 54603, 55445, 56282, 56990, 57572, 58191, 58840, 59410, 59887, 60264, 60607, 60946, 61269, 61516, 61771, 61960, 62198, 62408, 62558, 62776, 62985, 63207, 63408, 63546, 63739, 63906, 64070, 64237, 64371, 64551, 64677, 64836, 64999, 65095, 65213, 65284, 65338, 65380, 65426, 65447, 65472, 65485, 65487, 65489, 65502, 65510, 65512, 65514, 65516, 65518, 65522, 65531, 65533, 65535 }; const uint16_t WebRtcIsac_kQKltCdfShape[686] = { 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 4, 65535, 0, 8, 65514, 65535, 0, 29, 65481, 65535, 0, 121, 65439, 65535, 0, 239, 65284, 65535, 0, 8, 779, 64999, 65527, 65535, 0, 8, 888, 64693, 65522, 65535, 0, 29, 2604, 62843, 65497, 65531, 65535, 0, 25, 176, 4576, 61164, 65275, 65527, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 4, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 4, 65535, 0, 33, 65502, 65535, 0, 54, 65481, 65535, 0, 251, 65309, 65535, 0, 611, 65074, 65535, 0, 1273, 64292, 65527, 65535, 0, 4, 1809, 63940, 65518, 65535, 0, 88, 4392, 60603, 65426, 65531, 65535, 0, 25, 419, 7046, 57756, 64961, 65514, 65531, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 4, 65531, 65535, 0, 65535, 0, 8, 65531, 65535, 0, 4, 65527, 65535, 0, 17, 65510, 65535, 0, 42, 65481, 65535, 0, 197, 65342, 65531, 65535, 0, 385, 65154, 65535, 0, 1005, 64522, 65535, 0, 8, 1985, 63469, 65533, 65535, 0, 38, 3119, 61884, 65514, 65535, 0, 4, 6, 67, 4961, 60804, 65472, 65535, 0, 17, 565, 9182, 56538, 65087, 65514, 65535, 0, 8, 63, 327, 2118, 14490, 52774, 63839, 65376, 65522, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 17, 65522, 65535, 0, 59, 65489, 65535, 0, 50, 65522, 65535, 0, 54, 65489, 65535, 0, 310, 65179, 65535, 0, 615, 64836, 65535, 0, 4, 1503, 63965, 65535, 0, 2780, 63383, 65535, 0, 21, 3919, 61051, 65527, 65535, 0, 84, 6674, 59929, 65435, 65535, 0, 4, 255, 7976, 55784, 65150, 65518, 65531, 65535, 0, 4, 8, 582, 10726, 53465, 64949, 65518, 65535, 0, 29, 339, 3006, 17555, 49517, 62956, 65200, 65497, 65531, 65535, 0, 2, 33, 138, 565, 2324, 7670, 22089, 45966, 58949, 63479, 64966, 65380, 65518, 65535, 0, 65535, 0, 65535, 0, 2, 65533, 65535, 0, 46, 65514, 65535, 0, 414, 65091, 65535, 0, 540, 64911, 65535, 0, 419, 65162, 65535, 0, 976, 64790, 65535, 0, 2977, 62495, 65531, 65535, 0, 4, 3852, 61034, 65527, 65535, 0, 4, 29, 6021, 60243, 65468, 65535, 0, 84, 6711, 58066, 65418, 65535, 0, 13, 281, 9550, 54917, 65125, 65506, 65535, 0, 2, 63, 984, 12108, 52644, 64342, 65435, 65527, 65535, 0, 29, 251, 2014, 14871, 47553, 62881, 65229, 65518, 65535, 0, 13, 142, 749, 4220, 18497, 45200, 60913, 64823, 65426, 65527, 65535, 0, 13, 71, 264, 1176, 3789, 10500, 24480, 43488, 56324, 62315, 64493, 65242, 65464, 65514, 65522, 65531, 65535, 0, 4, 13, 38, 109, 205, 448, 850, 1708, 3429, 6276, 11371, 19221, 29734, 40955, 49391, 55411, 59460, 62102, 63793, 64656, 65150, 65401, 65485, 65522, 65531, 65535, 0, 65535, 0, 2, 65533, 65535, 0, 1160, 65476, 65535, 0, 2, 6640, 64763, 65533, 65535, 0, 2, 38, 9923, 61009, 65527, 65535, 0, 2, 4949, 63092, 65533, 65535, 0, 2, 3090, 63398, 65533, 65535, 0, 2, 2520, 58744, 65510, 65535, 0, 2, 13, 544, 8784, 51403, 65148, 65533, 65535, 0, 2, 25, 1017, 10412, 43550, 63651, 65489, 65527, 65535, 0, 2, 4, 29, 783, 13377, 52462, 64524, 65495, 65533, 65535, 0, 2, 4, 6, 100, 1817, 18451, 52590, 63559, 65376, 65531, 65535, 0, 2, 4, 6, 46, 385, 2562, 11225, 37416, 60488, 65026, 65487, 65529, 65533, 65535, 0, 2, 4, 6, 8, 10, 12, 42, 222, 971, 5221, 19811, 45048, 60312, 64486, 65294, 65474, 65525, 65529, 65533, 65535, 0, 2, 4, 8, 71, 167, 666, 2533, 7875, 19622, 38082, 54359, 62108, 64633, 65290, 65495, 65529, 65533, 65535, 0, 2, 4, 6, 8, 10, 13, 109, 586, 1930, 4949, 11600, 22641, 36125, 48312, 56899, 61495, 63927, 64932, 65389, 65489, 65518, 65531, 65533, 65535, 0, 4, 6, 8, 67, 209, 712, 1838, 4195, 8432, 14432, 22834, 31723, 40523, 48139, 53929, 57865, 60657, 62403, 63584, 64363, 64907, 65167, 65372, 65472, 65514, 65535, 0, 2, 4, 13, 25, 42, 46, 50, 75, 113, 147, 281, 448, 657, 909, 1185, 1591, 1976, 2600, 3676, 5317, 7398, 9914, 12941, 16169, 19477, 22885, 26464, 29851, 33360, 37228, 41139, 44802, 48654, 52058, 55181, 57676, 59581, 61022, 62190, 63107, 63676, 64199, 64547, 64924, 65158, 65313, 65430, 65481, 65518, 65535 }; /* pointers to cdf tables for quantizer indices */ const uint16_t *WebRtcIsac_kQKltCdfPtrGain[12] = { WebRtcIsac_kQKltCdfGain +0 +0, WebRtcIsac_kQKltCdfGain +0 +8, WebRtcIsac_kQKltCdfGain +0 +22, WebRtcIsac_kQKltCdfGain +0 +32, WebRtcIsac_kQKltCdfGain +0 +48, WebRtcIsac_kQKltCdfGain +0 +60, WebRtcIsac_kQKltCdfGain +0 +81, WebRtcIsac_kQKltCdfGain +0 +95, WebRtcIsac_kQKltCdfGain +0 +128, WebRtcIsac_kQKltCdfGain +0 +152, WebRtcIsac_kQKltCdfGain +0 +210, WebRtcIsac_kQKltCdfGain +0 +264 }; const uint16_t *WebRtcIsac_kQKltCdfPtrShape[108] = { WebRtcIsac_kQKltCdfShape +0 +0, WebRtcIsac_kQKltCdfShape +0 +2, WebRtcIsac_kQKltCdfShape +0 +4, WebRtcIsac_kQKltCdfShape +0 +6, WebRtcIsac_kQKltCdfShape +0 +8, WebRtcIsac_kQKltCdfShape +0 +10, WebRtcIsac_kQKltCdfShape +0 +12, WebRtcIsac_kQKltCdfShape +0 +14, WebRtcIsac_kQKltCdfShape +0 +16, WebRtcIsac_kQKltCdfShape +0 +18, WebRtcIsac_kQKltCdfShape +0 +21, WebRtcIsac_kQKltCdfShape +0 +25, WebRtcIsac_kQKltCdfShape +0 +29, WebRtcIsac_kQKltCdfShape +0 +33, WebRtcIsac_kQKltCdfShape +0 +37, WebRtcIsac_kQKltCdfShape +0 +43, WebRtcIsac_kQKltCdfShape +0 +49, WebRtcIsac_kQKltCdfShape +0 +56, WebRtcIsac_kQKltCdfShape +0 +64, WebRtcIsac_kQKltCdfShape +0 +66, WebRtcIsac_kQKltCdfShape +0 +68, WebRtcIsac_kQKltCdfShape +0 +70, WebRtcIsac_kQKltCdfShape +0 +72, WebRtcIsac_kQKltCdfShape +0 +75, WebRtcIsac_kQKltCdfShape +0 +77, WebRtcIsac_kQKltCdfShape +0 +79, WebRtcIsac_kQKltCdfShape +0 +81, WebRtcIsac_kQKltCdfShape +0 +83, WebRtcIsac_kQKltCdfShape +0 +86, WebRtcIsac_kQKltCdfShape +0 +90, WebRtcIsac_kQKltCdfShape +0 +94, WebRtcIsac_kQKltCdfShape +0 +98, WebRtcIsac_kQKltCdfShape +0 +102, WebRtcIsac_kQKltCdfShape +0 +107, WebRtcIsac_kQKltCdfShape +0 +113, WebRtcIsac_kQKltCdfShape +0 +120, WebRtcIsac_kQKltCdfShape +0 +129, WebRtcIsac_kQKltCdfShape +0 +131, WebRtcIsac_kQKltCdfShape +0 +133, WebRtcIsac_kQKltCdfShape +0 +135, WebRtcIsac_kQKltCdfShape +0 +137, WebRtcIsac_kQKltCdfShape +0 +141, WebRtcIsac_kQKltCdfShape +0 +143, WebRtcIsac_kQKltCdfShape +0 +147, WebRtcIsac_kQKltCdfShape +0 +151, WebRtcIsac_kQKltCdfShape +0 +155, WebRtcIsac_kQKltCdfShape +0 +159, WebRtcIsac_kQKltCdfShape +0 +164, WebRtcIsac_kQKltCdfShape +0 +168, WebRtcIsac_kQKltCdfShape +0 +172, WebRtcIsac_kQKltCdfShape +0 +178, WebRtcIsac_kQKltCdfShape +0 +184, WebRtcIsac_kQKltCdfShape +0 +192, WebRtcIsac_kQKltCdfShape +0 +200, WebRtcIsac_kQKltCdfShape +0 +211, WebRtcIsac_kQKltCdfShape +0 +213, WebRtcIsac_kQKltCdfShape +0 +215, WebRtcIsac_kQKltCdfShape +0 +217, WebRtcIsac_kQKltCdfShape +0 +219, WebRtcIsac_kQKltCdfShape +0 +223, WebRtcIsac_kQKltCdfShape +0 +227, WebRtcIsac_kQKltCdfShape +0 +231, WebRtcIsac_kQKltCdfShape +0 +235, WebRtcIsac_kQKltCdfShape +0 +239, WebRtcIsac_kQKltCdfShape +0 +243, WebRtcIsac_kQKltCdfShape +0 +248, WebRtcIsac_kQKltCdfShape +0 +252, WebRtcIsac_kQKltCdfShape +0 +258, WebRtcIsac_kQKltCdfShape +0 +264, WebRtcIsac_kQKltCdfShape +0 +273, WebRtcIsac_kQKltCdfShape +0 +282, WebRtcIsac_kQKltCdfShape +0 +293, WebRtcIsac_kQKltCdfShape +0 +308, WebRtcIsac_kQKltCdfShape +0 +310, WebRtcIsac_kQKltCdfShape +0 +312, WebRtcIsac_kQKltCdfShape +0 +316, WebRtcIsac_kQKltCdfShape +0 +320, WebRtcIsac_kQKltCdfShape +0 +324, WebRtcIsac_kQKltCdfShape +0 +328, WebRtcIsac_kQKltCdfShape +0 +332, WebRtcIsac_kQKltCdfShape +0 +336, WebRtcIsac_kQKltCdfShape +0 +341, WebRtcIsac_kQKltCdfShape +0 +347, WebRtcIsac_kQKltCdfShape +0 +354, WebRtcIsac_kQKltCdfShape +0 +360, WebRtcIsac_kQKltCdfShape +0 +368, WebRtcIsac_kQKltCdfShape +0 +378, WebRtcIsac_kQKltCdfShape +0 +388, WebRtcIsac_kQKltCdfShape +0 +400, WebRtcIsac_kQKltCdfShape +0 +418, WebRtcIsac_kQKltCdfShape +0 +445, WebRtcIsac_kQKltCdfShape +0 +447, WebRtcIsac_kQKltCdfShape +0 +451, WebRtcIsac_kQKltCdfShape +0 +455, WebRtcIsac_kQKltCdfShape +0 +461, WebRtcIsac_kQKltCdfShape +0 +468, WebRtcIsac_kQKltCdfShape +0 +474, WebRtcIsac_kQKltCdfShape +0 +480, WebRtcIsac_kQKltCdfShape +0 +486, WebRtcIsac_kQKltCdfShape +0 +495, WebRtcIsac_kQKltCdfShape +0 +505, WebRtcIsac_kQKltCdfShape +0 +516, WebRtcIsac_kQKltCdfShape +0 +528, WebRtcIsac_kQKltCdfShape +0 +543, WebRtcIsac_kQKltCdfShape +0 +564, WebRtcIsac_kQKltCdfShape +0 +583, WebRtcIsac_kQKltCdfShape +0 +608, WebRtcIsac_kQKltCdfShape +0 +635 }; /* left KLT transforms */ const double WebRtcIsac_kKltT1Gain[4] = { -0.79742827, 0.60341375, 0.60341375, 0.79742827 }; const double WebRtcIsac_kKltT1Shape[324] = { 0.00159597, 0.00049320, 0.00513821, 0.00021066, 0.01338581, -0.00422367, -0.00272072, 0.00935107, 0.02047622, 0.02691189, 0.00478236, 0.03969702, 0.00886698, 0.04877604, -0.10898362, -0.05930891, -0.03415047, 0.98889721, 0.00293558, -0.00035282, 0.01156321, -0.00195341, -0.00937631, 0.01052213, -0.02551163, 0.01644059, 0.03189927, 0.07754773, -0.08742313, -0.03026338, 0.05136248, -0.14395974, 0.17725040, 0.22664856, 0.93380230, 0.07076411, 0.00557890, -0.00222834, 0.01377569, 0.01466808, 0.02847361, -0.00603178, 0.02382480, -0.01210452, 0.03797267, -0.02371480, 0.11260335, -0.07366682, 0.00453436, -0.04136941, -0.07912843, -0.95031418, 0.25295337, -0.05302216, -0.00617554, -0.00044040, -0.00653778, 0.01097838, 0.01529174, 0.01374431, -0.00748512, -0.00020034, 0.02432713, 0.11101570, -0.08556891, 0.09282249, -0.01029446, 0.67556443, -0.67454300, 0.06910063, 0.20866865, -0.10318050, 0.00932175, 0.00524058, 0.00803610, -0.00594676, -0.01082578, 0.01069906, 0.00546768, 0.01565291, 0.06816200, 0.10201227, 0.16812734, 0.22984074, 0.58213170, -0.54138651, -0.51379962, 0.06847390, -0.01920037, -0.04592324, -0.00467394, 0.00328858, 0.00377424, -0.00987448, 0.08222096, -0.00377301, 0.04551941, -0.02592517, 0.16317082, 0.13077530, 0.22702921, -0.31215289, -0.69645962, -0.38047101, -0.39339411, 0.11124777, 0.02508035, -0.00708074, 0.00400344, 0.00040331, 0.01142402, 0.01725406, 0.01635170, 0.14285366, 0.03949233, -0.05905676, 0.05877154, -0.17497577, -0.32479440, 0.80754464, -0.38085603, -0.17055430, -0.03168622, -0.07531451, 0.02942002, -0.02148095, -0.00754114, -0.00322372, 0.00567812, -0.01701521, -0.12358320, 0.11473564, 0.09070136, 0.06533068, -0.22560802, 0.19209022, 0.81605094, 0.36592275, -0.09919829, 0.16667122, 0.16300725, 0.04803807, 0.06739263, -0.00156752, -0.01685302, -0.00905240, -0.02297836, -0.00469939, 0.06310613, -0.16391930, 0.10919511, 0.12529293, 0.85581322, -0.32145522, 0.24539076, 0.07181839, 0.07289591, 0.14066759, 0.10406711, 0.05815518, 0.01072680, -0.00759339, 0.00053486, -0.00044865, 0.03407361, 0.01645348, 0.08758579, 0.27722240, 0.53665485, -0.74853376, -0.01118192, -0.19805430, 0.06130619, -0.09675299, 0.08978480, 0.03405255, -0.00706867, 0.05102045, 0.03250746, 0.01849966, -0.01216314, -0.01184187, -0.01579288, 0.00114807, 0.11376166, 0.88342114, -0.36425379, 0.13863190, 0.12524180, -0.13553892, 0.04715856, -0.12341103, 0.04531568, 0.01899360, -0.00206897, 0.00567768, -0.01444163, 0.00411946, -0.00855896, 0.00381663, -0.01664861, -0.05534280, 0.21328278, 0.20161162, 0.72360394, 0.59130708, -0.08043791, 0.08757349, -0.13893918, -0.05147377, 0.02680690, -0.01144070, 0.00625162, -0.00634215, -0.01248947, -0.00329455, -0.00609625, -0.00136305, -0.05097048, -0.01029851, 0.25065384, -0.16856837, -0.07123372, 0.15992623, -0.39487617, -0.79972301, 0.18118185, -0.04826639, -0.01805578, -0.02927253, -0.16400618, 0.07472763, 0.10376449, 0.01705406, 0.01065801, -0.01500498, 0.02039914, 0.37776349, -0.84484186, 0.10434286, 0.15616990, 0.13474456, -0.00906238, -0.25238368, -0.03820885, -0.10650905, -0.03880833, -0.03660028, -0.09640894, 0.00583314, 0.01922097, 0.01489911, -0.02431117, -0.09372217, 0.39404721, -0.84786223, -0.31277121, 0.03193850, 0.01974060, 0.01887901, 0.00337911, -0.11359599, -0.02792521, -0.03220184, -0.01533311, 0.00015962, -0.04225043, -0.00933965, 0.00675311, 0.00206060, 0.15926771, 0.40199829, -0.80792558, -0.35591604, -0.17169764, 0.02830436, 0.02459982, -0.03438589, 0.00718705, -0.01798329, -0.01594508, -0.00702430, -0.00952419, -0.00962701, -0.01307212, -0.01749740, 0.01299602, 0.00587270, -0.36103108, -0.82039266, -0.43092844, -0.08500097, -0.04361674, -0.00333482, 0.01250434, -0.02538295, -0.00921797, 0.01645071, -0.01400872, 0.00317607, 0.00003277, -0.01617646, -0.00616863, -0.00882661, 0.00466157, 0.00353237, 0.91803104, -0.39503305, -0.02048964, 0.00060125, 0.01980634, 0.00300109, 0.00313880, 0.00657337, 0.00715163, 0.00000261, 0.00854276, -0.00154825, -0.00516128, 0.00909527, 0.00095609, 0.00701196, -0.00221867, -0.00156741 }; /* right KLT transforms */ const double WebRtcIsac_kKltT2Gain[36] = { 0.14572837, -0.45446306, 0.61990621, -0.52197033, 0.32145074, -0.11026900, -0.20698282, 0.48962182, -0.27127933, -0.33627476, 0.65094037, -0.32715751, 0.40262573, -0.47844405, -0.33876075, 0.44130653, 0.37383966, -0.39964662, -0.51730480, 0.06611973, 0.49030187, 0.47512886, -0.02141226, -0.51129451, -0.58578569, -0.39132064, -0.13187771, 0.15649421, 0.40735596, 0.54396897, 0.40381276, 0.40904942, 0.41179766, 0.41167576, 0.40840251, 0.40468132 }; const double WebRtcIsac_kKltT2Shape[36] = { 0.13427386, -0.35132558, 0.52506528, -0.59419077, 0.45075085, -0.16312057, 0.29857439, -0.58660147, 0.34265431, 0.20879510, -0.56063262, 0.30238345, 0.43308283, -0.41186999, -0.35288681, 0.42768996, 0.36094634, -0.45284910, -0.47116680, 0.02893449, 0.54326135, 0.45249040, -0.06264420, -0.52283830, 0.57137758, 0.44298139, 0.12617554, -0.20819946, -0.42324603, -0.48876443, 0.39597050, 0.40713935, 0.41389880, 0.41512486, 0.41130400, 0.40575001 }; /* means of log gains and LAR coefficients*/ const double WebRtcIsac_kLpcMeansGain[12] = { -6.86881911, -5.35075273, -6.86792680, -5.36200897, -6.86401538, -5.36921533, -6.86802969, -5.36893966, -6.86538097, -5.36315063, -6.85535304, -5.35155315 }; const double WebRtcIsac_kLpcMeansShape[108] = { -0.91232981, 0.26258634, -0.33716701, 0.08477430, -0.03378426, 0.14423909, 0.07036185, 0.06155019, 0.01490385, 0.04138740, 0.01427317, 0.01288970, 0.83872106, 0.25750199, 0.07988929, -0.01957923, 0.00831390, 0.01770300, -0.90957164, 0.25732216, -0.33385344, 0.08735740, -0.03715332, 0.14584917, 0.06998990, 0.06131968, 0.01504379, 0.04067339, 0.01428039, 0.01406460, 0.83846243, 0.26169862, 0.08109025, -0.01767055, 0.00970539, 0.01954310, -0.90490803, 0.24656405, -0.33578607, 0.08843286, -0.03749139, 0.14443959, 0.07214669, 0.06170993, 0.01449947, 0.04134309, 0.01314762, 0.01413471, 0.83895203, 0.26748062, 0.08197507, -0.01781298, 0.00885967, 0.01922394, -0.90922472, 0.24495889, -0.33921540, 0.08877169, -0.03581332, 0.14199172, 0.07444032, 0.06185940, 0.01502054, 0.04185113, 0.01276579, 0.01355457, 0.83645358, 0.26631720, 0.08119697, -0.01835449, 0.00788512, 0.01846446, -0.90482253, 0.24658310, -0.34019734, 0.08281090, -0.03486038, 0.14359248, 0.07401336, 0.06001471, 0.01528421, 0.04254560, 0.01321472, 0.01240799, 0.83857127, 0.26281654, 0.08174380, -0.02099842, 0.00755176, 0.01699448, -0.90132307, 0.25174308, -0.33838268, 0.07883863, -0.02877906, 0.14105407, 0.07220290, 0.06000352, 0.01684879, 0.04226844, 0.01331331, 0.01269244, 0.83832138, 0.25467485, 0.08118028, -0.02120528, 0.00747832, 0.01567212 }; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_tables.h0000664000175000017500000000603014475643423031133 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * lpc_tables.h * * header file for coding tables for the LPC coefficients * */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_ #include "modules/audio_coding/codecs/isac/main/source/settings.h" #include "modules/audio_coding/codecs/isac/main/source/structs.h" #define KLT_STEPSIZE 1.00000000 #define KLT_NUM_AVG_GAIN 0 #define KLT_NUM_AVG_SHAPE 0 #define KLT_NUM_MODELS 3 #define LPC_GAIN_SCALE 4.000f #define LPC_LOBAND_SCALE 2.100f #define LPC_LOBAND_ORDER ORDERLO #define LPC_HIBAND_SCALE 0.450f #define LPC_HIBAND_ORDER ORDERHI #define LPC_GAIN_ORDER 2 #define LPC_SHAPE_ORDER (LPC_LOBAND_ORDER + LPC_HIBAND_ORDER) #define KLT_ORDER_GAIN (LPC_GAIN_ORDER * SUBFRAMES) #define KLT_ORDER_SHAPE (LPC_SHAPE_ORDER * SUBFRAMES) /* cdf array for model indicator */ extern const uint16_t WebRtcIsac_kQKltModelCdf[KLT_NUM_MODELS + 1]; /* pointer to cdf array for model indicator */ extern const uint16_t* WebRtcIsac_kQKltModelCdfPtr[1]; /* initial cdf index for decoder of model indicator */ extern const uint16_t WebRtcIsac_kQKltModelInitIndex[1]; /* offset to go from rounded value to quantization index */ extern const short WebRtcIsac_kQKltQuantMinGain[12]; extern const short WebRtcIsac_kQKltQuantMinShape[108]; /* maximum quantization index */ extern const uint16_t WebRtcIsac_kQKltMaxIndGain[12]; extern const uint16_t WebRtcIsac_kQKltMaxIndShape[108]; /* index offset */ extern const uint16_t WebRtcIsac_kQKltOffsetGain[12]; extern const uint16_t WebRtcIsac_kQKltOffsetShape[108]; /* initial cdf index for KLT coefficients */ extern const uint16_t WebRtcIsac_kQKltInitIndexGain[12]; extern const uint16_t WebRtcIsac_kQKltInitIndexShape[108]; /* quantizer representation levels */ extern const double WebRtcIsac_kQKltLevelsGain[392]; extern const double WebRtcIsac_kQKltLevelsShape[578]; /* cdf tables for quantizer indices */ extern const uint16_t WebRtcIsac_kQKltCdfGain[404]; extern const uint16_t WebRtcIsac_kQKltCdfShape[686]; /* pointers to cdf tables for quantizer indices */ extern const uint16_t* WebRtcIsac_kQKltCdfPtrGain[12]; extern const uint16_t* WebRtcIsac_kQKltCdfPtrShape[108]; /* left KLT transforms */ extern const double WebRtcIsac_kKltT1Gain[4]; extern const double WebRtcIsac_kKltT1Shape[324]; /* right KLT transforms */ extern const double WebRtcIsac_kKltT2Gain[36]; extern const double WebRtcIsac_kKltT2Shape[36]; /* means of log gains and LAR coefficients */ extern const double WebRtcIsac_kLpcMeansGain[12]; extern const double WebRtcIsac_kLpcMeansShape[108]; #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/os_specific_inline.h0000664000175000017500000000221014475643423032643 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_ #include #include "rtc_base/system/arch.h" #if defined(WEBRTC_POSIX) #define WebRtcIsac_lrint lrint #elif (defined(WEBRTC_ARCH_X86) && defined(WIN32)) static __inline long int WebRtcIsac_lrint(double x_dbl) { long int x_int; __asm { fld x_dbl fistp x_int } ; return x_int; } #else // Do a slow but correct implementation of lrint static __inline long int WebRtcIsac_lrint(double x_dbl) { long int x_int; x_int = (long int)floor(x_dbl + 0.499999999999); return x_int; } #endif #endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_estimator.c0000664000175000017500000006142014475643423032220 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h" #include #include #include #ifdef WEBRTC_ANDROID #include #endif #include "modules/audio_coding/codecs/isac/main/source/filter_functions.h" #include "modules/audio_coding/codecs/isac/main/source/pitch_filter.h" #include "rtc_base/system/ignore_warnings.h" static const double kInterpolWin[8] = {-0.00067556028640, 0.02184247643159, -0.12203175715679, 0.60086484101160, 0.60086484101160, -0.12203175715679, 0.02184247643159, -0.00067556028640}; /* interpolation filter */ __inline static void IntrepolFilter(double *data_ptr, double *intrp) { *intrp = kInterpolWin[0] * data_ptr[-3]; *intrp += kInterpolWin[1] * data_ptr[-2]; *intrp += kInterpolWin[2] * data_ptr[-1]; *intrp += kInterpolWin[3] * data_ptr[0]; *intrp += kInterpolWin[4] * data_ptr[1]; *intrp += kInterpolWin[5] * data_ptr[2]; *intrp += kInterpolWin[6] * data_ptr[3]; *intrp += kInterpolWin[7] * data_ptr[4]; } /* 2D parabolic interpolation */ /* probably some 0.5 factors can be eliminated, and the square-roots can be removed from the Cholesky fact. */ __inline static void Intrpol2D(double T[3][3], double *x, double *y, double *peak_val) { double c, b[2], A[2][2]; double t1, t2, d; double delta1, delta2; // double T[3][3] = {{-1.25, -.25,-.25}, {-.25, .75, .75}, {-.25, .75, .75}}; // should result in: delta1 = 0.5; delta2 = 0.0; peak_val = 1.0 c = T[1][1]; b[0] = 0.5 * (T[1][2] + T[2][1] - T[0][1] - T[1][0]); b[1] = 0.5 * (T[1][0] + T[2][1] - T[0][1] - T[1][2]); A[0][1] = -0.5 * (T[0][1] + T[2][1] - T[1][0] - T[1][2]); t1 = 0.5 * (T[0][0] + T[2][2]) - c; t2 = 0.5 * (T[2][0] + T[0][2]) - c; d = (T[0][1] + T[1][2] + T[1][0] + T[2][1]) - 4.0 * c - t1 - t2; A[0][0] = -t1 - 0.5 * d; A[1][1] = -t2 - 0.5 * d; /* deal with singularities or ill-conditioned cases */ if ( (A[0][0] < 1e-7) || ((A[0][0] * A[1][1] - A[0][1] * A[0][1]) < 1e-7) ) { *peak_val = T[1][1]; return; } /* Cholesky decomposition: replace A by upper-triangular factor */ A[0][0] = sqrt(A[0][0]); A[0][1] = A[0][1] / A[0][0]; A[1][1] = sqrt(A[1][1] - A[0][1] * A[0][1]); /* compute [x; y] = -0.5 * inv(A) * b */ t1 = b[0] / A[0][0]; t2 = (b[1] - t1 * A[0][1]) / A[1][1]; delta2 = t2 / A[1][1]; delta1 = 0.5 * (t1 - delta2 * A[0][1]) / A[0][0]; delta2 *= 0.5; /* limit norm */ t1 = delta1 * delta1 + delta2 * delta2; if (t1 > 1.0) { delta1 /= t1; delta2 /= t1; } *peak_val = 0.5 * (b[0] * delta1 + b[1] * delta2) + c; *x += delta1; *y += delta2; } static void PCorr(const double *in, double *outcorr) { double sum, ysum, prod; const double *x, *inptr; int k, n; //ysum = 1e-6; /* use this with float (i.s.o. double)! */ ysum = 1e-13; sum = 0.0; x = in + PITCH_MAX_LAG/2 + 2; for (n = 0; n < PITCH_CORR_LEN2; n++) { ysum += in[n] * in[n]; sum += x[n] * in[n]; } outcorr += PITCH_LAG_SPAN2 - 1; /* index of last element in array */ *outcorr = sum / sqrt(ysum); for (k = 1; k < PITCH_LAG_SPAN2; k++) { ysum -= in[k-1] * in[k-1]; ysum += in[PITCH_CORR_LEN2 + k - 1] * in[PITCH_CORR_LEN2 + k - 1]; sum = 0.0; inptr = &in[k]; prod = x[0] * inptr[0]; for (n = 1; n < PITCH_CORR_LEN2; n++) { sum += prod; prod = x[n] * inptr[n]; } sum += prod; outcorr--; *outcorr = sum / sqrt(ysum); } } static void WebRtcIsac_AllpassFilterForDec(double* InOut, const double* APSectionFactors, size_t lengthInOut, double* FilterState) { // This performs all-pass filtering--a series of first order all-pass // sections are used to filter the input in a cascade manner. size_t n, j; double temp; for (j = 0; j < ALLPASSSECTIONS; j++) { for (n = 0; n < lengthInOut; n += 2) { temp = InOut[n]; // store input InOut[n] = FilterState[j] + APSectionFactors[j] * temp; FilterState[j] = -APSectionFactors[j] * InOut[n] + temp; } } } static void WebRtcIsac_DecimateAllpass( const double* in, double* state_in, // array of size: 2*ALLPASSSECTIONS+1 size_t N, // number of input samples double* out) { // array of size N/2 static const double APupper[ALLPASSSECTIONS] = {0.0347, 0.3826}; static const double APlower[ALLPASSSECTIONS] = {0.1544, 0.744}; size_t n; double data_vec[PITCH_FRAME_LEN]; /* copy input */ memcpy(data_vec + 1, in, sizeof(double) * (N - 1)); data_vec[0] = state_in[2 * ALLPASSSECTIONS]; // the z^(-1) state state_in[2 * ALLPASSSECTIONS] = in[N - 1]; WebRtcIsac_AllpassFilterForDec(data_vec + 1, APupper, N, state_in); WebRtcIsac_AllpassFilterForDec(data_vec, APlower, N, state_in + ALLPASSSECTIONS); for (n = 0; n < N / 2; n++) out[n] = data_vec[2 * n] + data_vec[2 * n + 1]; } RTC_PUSH_IGNORING_WFRAME_LARGER_THAN() static void WebRtcIsac_InitializePitch(const double* in, const double old_lag, const double old_gain, PitchAnalysisStruct* State, double* lags) { double buf_dec[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2+2]; double ratio, log_lag, gain_bias; double bias; double corrvec1[PITCH_LAG_SPAN2]; double corrvec2[PITCH_LAG_SPAN2]; int m, k; // Allocating 10 extra entries at the begining of the CorrSurf double corrSurfBuff[10 + (2*PITCH_BW+3)*(PITCH_LAG_SPAN2+4)]; double* CorrSurf[2*PITCH_BW+3]; double *CorrSurfPtr1, *CorrSurfPtr2; double LagWin[3] = {0.2, 0.5, 0.98}; int ind1, ind2, peaks_ind, peak, max_ind; int peaks[PITCH_MAX_NUM_PEAKS]; double adj, gain_tmp; double corr, corr_max; double intrp_a, intrp_b, intrp_c, intrp_d; double peak_vals[PITCH_MAX_NUM_PEAKS]; double lags1[PITCH_MAX_NUM_PEAKS]; double lags2[PITCH_MAX_NUM_PEAKS]; double T[3][3]; int row; for(k = 0; k < 2*PITCH_BW+3; k++) { CorrSurf[k] = &corrSurfBuff[10 + k * (PITCH_LAG_SPAN2+4)]; } /* reset CorrSurf matrix */ memset(corrSurfBuff, 0, sizeof(double) * (10 + (2*PITCH_BW+3) * (PITCH_LAG_SPAN2+4))); //warnings -DH max_ind = 0; peak = 0; /* copy old values from state buffer */ memcpy(buf_dec, State->dec_buffer, sizeof(double) * (PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2)); /* decimation; put result after the old values */ WebRtcIsac_DecimateAllpass(in, State->decimator_state, PITCH_FRAME_LEN, &buf_dec[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2]); /* low-pass filtering */ for (k = PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2; k < PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2+2; k++) buf_dec[k] += 0.75 * buf_dec[k-1] - 0.25 * buf_dec[k-2]; /* copy end part back into state buffer */ memcpy(State->dec_buffer, buf_dec+PITCH_FRAME_LEN/2, sizeof(double) * (PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2)); /* compute correlation for first and second half of the frame */ PCorr(buf_dec, corrvec1); PCorr(buf_dec + PITCH_CORR_STEP2, corrvec2); /* bias towards pitch lag of previous frame */ log_lag = log(0.5 * old_lag); gain_bias = 4.0 * old_gain * old_gain; if (gain_bias > 0.8) gain_bias = 0.8; for (k = 0; k < PITCH_LAG_SPAN2; k++) { ratio = log((double) (k + (PITCH_MIN_LAG/2-2))) - log_lag; bias = 1.0 + gain_bias * exp(-5.0 * ratio * ratio); corrvec1[k] *= bias; } /* taper correlation functions */ for (k = 0; k < 3; k++) { gain_tmp = LagWin[k]; corrvec1[k] *= gain_tmp; corrvec2[k] *= gain_tmp; corrvec1[PITCH_LAG_SPAN2-1-k] *= gain_tmp; corrvec2[PITCH_LAG_SPAN2-1-k] *= gain_tmp; } corr_max = 0.0; /* fill middle row of correlation surface */ ind1 = 0; ind2 = 0; CorrSurfPtr1 = &CorrSurf[PITCH_BW][2]; for (k = 0; k < PITCH_LAG_SPAN2; k++) { corr = corrvec1[ind1++] + corrvec2[ind2++]; CorrSurfPtr1[k] = corr; if (corr > corr_max) { corr_max = corr; /* update maximum */ max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]); } } /* fill first and last rows of correlation surface */ ind1 = 0; ind2 = PITCH_BW; CorrSurfPtr1 = &CorrSurf[0][2]; CorrSurfPtr2 = &CorrSurf[2*PITCH_BW][PITCH_BW+2]; for (k = 0; k < PITCH_LAG_SPAN2-PITCH_BW; k++) { ratio = ((double) (ind1 + 12)) / ((double) (ind2 + 12)); adj = 0.2 * ratio * (2.0 - ratio); /* adjustment factor; inverse parabola as a function of ratio */ corr = adj * (corrvec1[ind1] + corrvec2[ind2]); CorrSurfPtr1[k] = corr; if (corr > corr_max) { corr_max = corr; /* update maximum */ max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]); } corr = adj * (corrvec1[ind2++] + corrvec2[ind1++]); CorrSurfPtr2[k] = corr; if (corr > corr_max) { corr_max = corr; /* update maximum */ max_ind = (int)(&CorrSurfPtr2[k] - &CorrSurf[0][0]); } } /* fill second and next to last rows of correlation surface */ ind1 = 0; ind2 = PITCH_BW-1; CorrSurfPtr1 = &CorrSurf[1][2]; CorrSurfPtr2 = &CorrSurf[2*PITCH_BW-1][PITCH_BW+1]; for (k = 0; k < PITCH_LAG_SPAN2-PITCH_BW+1; k++) { ratio = ((double) (ind1 + 12)) / ((double) (ind2 + 12)); adj = 0.9 * ratio * (2.0 - ratio); /* adjustment factor; inverse parabola as a function of ratio */ corr = adj * (corrvec1[ind1] + corrvec2[ind2]); CorrSurfPtr1[k] = corr; if (corr > corr_max) { corr_max = corr; /* update maximum */ max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]); } corr = adj * (corrvec1[ind2++] + corrvec2[ind1++]); CorrSurfPtr2[k] = corr; if (corr > corr_max) { corr_max = corr; /* update maximum */ max_ind = (int)(&CorrSurfPtr2[k] - &CorrSurf[0][0]); } } /* fill remainder of correlation surface */ for (m = 2; m < PITCH_BW; m++) { ind1 = 0; ind2 = PITCH_BW - m; /* always larger than ind1 */ CorrSurfPtr1 = &CorrSurf[m][2]; CorrSurfPtr2 = &CorrSurf[2*PITCH_BW-m][PITCH_BW+2-m]; for (k = 0; k < PITCH_LAG_SPAN2-PITCH_BW+m; k++) { ratio = ((double) (ind1 + 12)) / ((double) (ind2 + 12)); adj = ratio * (2.0 - ratio); /* adjustment factor; inverse parabola as a function of ratio */ corr = adj * (corrvec1[ind1] + corrvec2[ind2]); CorrSurfPtr1[k] = corr; if (corr > corr_max) { corr_max = corr; /* update maximum */ max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]); } corr = adj * (corrvec1[ind2++] + corrvec2[ind1++]); CorrSurfPtr2[k] = corr; if (corr > corr_max) { corr_max = corr; /* update maximum */ max_ind = (int)(&CorrSurfPtr2[k] - &CorrSurf[0][0]); } } } /* threshold value to qualify as a peak */ corr_max *= 0.6; peaks_ind = 0; /* find peaks */ for (m = 1; m < PITCH_BW+1; m++) { if (peaks_ind == PITCH_MAX_NUM_PEAKS) break; CorrSurfPtr1 = &CorrSurf[m][2]; for (k = 2; k < PITCH_LAG_SPAN2-PITCH_BW-2+m; k++) { corr = CorrSurfPtr1[k]; if (corr > corr_max) { if ( (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+5)]) && (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+4)]) ) { if ( (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+4)]) && (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+5)]) ) { /* found a peak; store index into matrix */ peaks[peaks_ind++] = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]); if (peaks_ind == PITCH_MAX_NUM_PEAKS) break; } } } } } for (m = PITCH_BW+1; m < 2*PITCH_BW; m++) { if (peaks_ind == PITCH_MAX_NUM_PEAKS) break; CorrSurfPtr1 = &CorrSurf[m][2]; for (k = 2+m-PITCH_BW; k < PITCH_LAG_SPAN2-2; k++) { corr = CorrSurfPtr1[k]; if (corr > corr_max) { if ( (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+5)]) && (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+4)]) ) { if ( (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+4)]) && (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+5)]) ) { /* found a peak; store index into matrix */ peaks[peaks_ind++] = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]); if (peaks_ind == PITCH_MAX_NUM_PEAKS) break; } } } } } if (peaks_ind > 0) { /* examine each peak */ CorrSurfPtr1 = &CorrSurf[0][0]; for (k = 0; k < peaks_ind; k++) { peak = peaks[k]; /* compute four interpolated values around current peak */ IntrepolFilter(&CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)], &intrp_a); IntrepolFilter(&CorrSurfPtr1[peak - 1 ], &intrp_b); IntrepolFilter(&CorrSurfPtr1[peak ], &intrp_c); IntrepolFilter(&CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)], &intrp_d); /* determine maximum of the interpolated values */ corr = CorrSurfPtr1[peak]; corr_max = intrp_a; if (intrp_b > corr_max) corr_max = intrp_b; if (intrp_c > corr_max) corr_max = intrp_c; if (intrp_d > corr_max) corr_max = intrp_d; /* determine where the peak sits and fill a 3x3 matrix around it */ row = peak / (PITCH_LAG_SPAN2+4); lags1[k] = (double) ((peak - row * (PITCH_LAG_SPAN2+4)) + PITCH_MIN_LAG/2 - 4); lags2[k] = (double) (lags1[k] + PITCH_BW - row); if ( corr > corr_max ) { T[0][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)]; T[2][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)]; T[1][1] = corr; T[0][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)]; T[2][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)]; T[1][0] = intrp_a; T[0][1] = intrp_b; T[2][1] = intrp_c; T[1][2] = intrp_d; } else { if (intrp_a == corr_max) { lags1[k] -= 0.5; lags2[k] += 0.5; IntrepolFilter(&CorrSurfPtr1[peak - 2*(PITCH_LAG_SPAN2+5)], &T[0][0]); IntrepolFilter(&CorrSurfPtr1[peak - (2*PITCH_LAG_SPAN2+9)], &T[2][0]); T[1][1] = intrp_a; T[0][2] = intrp_b; T[2][2] = intrp_c; T[1][0] = CorrSurfPtr1[peak - (2*PITCH_LAG_SPAN2+9)]; T[0][1] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)]; T[2][1] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)]; T[1][2] = corr; } else if (intrp_b == corr_max) { lags1[k] -= 0.5; lags2[k] -= 0.5; IntrepolFilter(&CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+6)], &T[0][0]); T[2][0] = intrp_a; T[1][1] = intrp_b; IntrepolFilter(&CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+3)], &T[0][2]); T[2][2] = intrp_d; T[1][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)]; T[0][1] = CorrSurfPtr1[peak - 1]; T[2][1] = corr; T[1][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)]; } else if (intrp_c == corr_max) { lags1[k] += 0.5; lags2[k] += 0.5; T[0][0] = intrp_a; IntrepolFilter(&CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)], &T[2][0]); T[1][1] = intrp_c; T[0][2] = intrp_d; IntrepolFilter(&CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)], &T[2][2]); T[1][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)]; T[0][1] = corr; T[2][1] = CorrSurfPtr1[peak + 1]; T[1][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)]; } else { lags1[k] += 0.5; lags2[k] -= 0.5; T[0][0] = intrp_b; T[2][0] = intrp_c; T[1][1] = intrp_d; IntrepolFilter(&CorrSurfPtr1[peak + 2*(PITCH_LAG_SPAN2+4)], &T[0][2]); IntrepolFilter(&CorrSurfPtr1[peak + (2*PITCH_LAG_SPAN2+9)], &T[2][2]); T[1][0] = corr; T[0][1] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)]; T[2][1] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)]; T[1][2] = CorrSurfPtr1[peak + (2*PITCH_LAG_SPAN2+9)]; } } /* 2D parabolic interpolation gives more accurate lags and peak value */ Intrpol2D(T, &lags1[k], &lags2[k], &peak_vals[k]); } /* determine the highest peak, after applying a bias towards short lags */ corr_max = 0.0; for (k = 0; k < peaks_ind; k++) { corr = peak_vals[k] * pow(PITCH_PEAK_DECAY, log(lags1[k] + lags2[k])); if (corr > corr_max) { corr_max = corr; peak = k; } } lags1[peak] *= 2.0; lags2[peak] *= 2.0; if (lags1[peak] < (double) PITCH_MIN_LAG) lags1[peak] = (double) PITCH_MIN_LAG; if (lags2[peak] < (double) PITCH_MIN_LAG) lags2[peak] = (double) PITCH_MIN_LAG; if (lags1[peak] > (double) PITCH_MAX_LAG) lags1[peak] = (double) PITCH_MAX_LAG; if (lags2[peak] > (double) PITCH_MAX_LAG) lags2[peak] = (double) PITCH_MAX_LAG; /* store lags of highest peak in output array */ lags[0] = lags1[peak]; lags[1] = lags1[peak]; lags[2] = lags2[peak]; lags[3] = lags2[peak]; } else { row = max_ind / (PITCH_LAG_SPAN2+4); lags1[0] = (double) ((max_ind - row * (PITCH_LAG_SPAN2+4)) + PITCH_MIN_LAG/2 - 4); lags2[0] = (double) (lags1[0] + PITCH_BW - row); if (lags1[0] < (double) PITCH_MIN_LAG) lags1[0] = (double) PITCH_MIN_LAG; if (lags2[0] < (double) PITCH_MIN_LAG) lags2[0] = (double) PITCH_MIN_LAG; if (lags1[0] > (double) PITCH_MAX_LAG) lags1[0] = (double) PITCH_MAX_LAG; if (lags2[0] > (double) PITCH_MAX_LAG) lags2[0] = (double) PITCH_MAX_LAG; /* store lags of highest peak in output array */ lags[0] = lags1[0]; lags[1] = lags1[0]; lags[2] = lags2[0]; lags[3] = lags2[0]; } } RTC_POP_IGNORING_WFRAME_LARGER_THAN() /* create weighting matrix by orthogonalizing a basis of polynomials of increasing order * t = (0:4)'; * A = [t.^0, t.^1, t.^2, t.^3, t.^4]; * [Q, dummy] = qr(A); * P.Weight = Q * diag([0, .1, .5, 1, 1]) * Q'; */ static const double kWeight[5][5] = { { 0.29714285714286, -0.30857142857143, -0.05714285714286, 0.05142857142857, 0.01714285714286}, {-0.30857142857143, 0.67428571428571, -0.27142857142857, -0.14571428571429, 0.05142857142857}, {-0.05714285714286, -0.27142857142857, 0.65714285714286, -0.27142857142857, -0.05714285714286}, { 0.05142857142857, -0.14571428571429, -0.27142857142857, 0.67428571428571, -0.30857142857143}, { 0.01714285714286, 0.05142857142857, -0.05714285714286, -0.30857142857143, 0.29714285714286} }; /* second order high-pass filter */ static void WebRtcIsac_Highpass(const double* in, double* out, double* state, size_t N) { /* create high-pass filter ocefficients * z = 0.998 * exp(j*2*pi*35/8000); * p = 0.94 * exp(j*2*pi*140/8000); * HP_b = [1, -2*real(z), abs(z)^2]; * HP_a = [1, -2*real(p), abs(p)^2]; */ static const double a_coef[2] = { 1.86864659625574, -0.88360000000000}; static const double b_coef[2] = {-1.99524591718270, 0.99600400000000}; size_t k; for (k=0; khp_state, PITCH_FRAME_LEN); /* copy from state into buffer */ memcpy(Whitened, State->whitened_buf, sizeof(double) * QLOOKAHEAD); /* compute weighted and whitened signals */ WebRtcIsac_WeightingFilter(HPin, &Weighted[0], &Whitened[QLOOKAHEAD], &(State->Wghtstr)); /* copy from buffer into state */ memcpy(State->whitened_buf, Whitened+PITCH_FRAME_LEN, sizeof(double) * QLOOKAHEAD); old_lag = State->PFstr_wght.oldlagp[0]; old_gain = State->PFstr_wght.oldgainp[0]; /* inital pitch estimate */ WebRtcIsac_InitializePitch(Weighted, old_lag, old_gain, State, lags); /* Iterative optimization of lags - to be done */ /* compute energy of whitened signal */ nrg_wht = 0.0; for (k = 0; k < PITCH_FRAME_LEN + QLOOKAHEAD; k++) nrg_wht += Whitened[k] * Whitened[k]; /* Iterative optimization of gains */ /* set weights for energy, gain fluctiation, and spectral gain penalty functions */ Wnrg = 1.0 / nrg_wht; Wgain = 0.005; Wfluct = 3.0; /* set initial gains */ for (k = 0; k < 4; k++) gains[k] = PITCH_MAX_GAIN_06; /* two iterations should be enough */ for (iter = 0; iter < 2; iter++) { /* compute Jacobian of pre-filter output towards gains */ WebRtcIsac_PitchfilterPre_gains(Whitened, out_G, out_dG, &(State->PFstr_wght), lags, gains); /* gradient and approximate Hessian (lower triangle) for minimizing the filter's output power */ for (k = 0; k < 4; k++) { tmp = 0.0; for (n = 0; n < PITCH_FRAME_LEN + QLOOKAHEAD; n++) tmp += out_G[n] * out_dG[k][n]; grad[k] = tmp * Wnrg; } for (k = 0; k < 4; k++) { for (m = 0; m <= k; m++) { tmp = 0.0; for (n = 0; n < PITCH_FRAME_LEN + QLOOKAHEAD; n++) tmp += out_dG[m][n] * out_dG[k][n]; H[k][m] = tmp * Wnrg; } } /* add gradient and Hessian (lower triangle) for dampening fast gain changes */ for (k = 0; k < 4; k++) { tmp = kWeight[k+1][0] * old_gain; for (m = 0; m < 4; m++) tmp += kWeight[k+1][m+1] * gains[m]; grad[k] += tmp * Wfluct; } for (k = 0; k < 4; k++) { for (m = 0; m <= k; m++) { H[k][m] += kWeight[k+1][m+1] * Wfluct; } } /* add gradient and Hessian for dampening gain */ for (k = 0; k < 3; k++) { tmp = 1.0 / (1 - gains[k]); grad[k] += tmp * tmp * Wgain; H[k][k] += 2.0 * tmp * (tmp * tmp * Wgain); } tmp = 1.0 / (1 - gains[3]); grad[3] += 1.33 * (tmp * tmp * Wgain); H[3][3] += 2.66 * tmp * (tmp * tmp * Wgain); /* compute Cholesky factorization of Hessian * by overwritting the upper triangle; scale factors on diagonal * (for non pc-platforms store the inverse of the diagonals seperately to minimize divisions) */ H[0][1] = H[1][0] / H[0][0]; H[0][2] = H[2][0] / H[0][0]; H[0][3] = H[3][0] / H[0][0]; H[1][1] -= H[0][0] * H[0][1] * H[0][1]; H[1][2] = (H[2][1] - H[0][1] * H[2][0]) / H[1][1]; H[1][3] = (H[3][1] - H[0][1] * H[3][0]) / H[1][1]; H[2][2] -= H[0][0] * H[0][2] * H[0][2] + H[1][1] * H[1][2] * H[1][2]; H[2][3] = (H[3][2] - H[0][2] * H[3][0] - H[1][2] * H[1][1] * H[1][3]) / H[2][2]; H[3][3] -= H[0][0] * H[0][3] * H[0][3] + H[1][1] * H[1][3] * H[1][3] + H[2][2] * H[2][3] * H[2][3]; /* Compute update as delta_gains = -inv(H) * grad */ /* copy and negate */ for (k = 0; k < 4; k++) dG[k] = -grad[k]; /* back substitution */ dG[1] -= dG[0] * H[0][1]; dG[2] -= dG[0] * H[0][2] + dG[1] * H[1][2]; dG[3] -= dG[0] * H[0][3] + dG[1] * H[1][3] + dG[2] * H[2][3]; /* scale */ for (k = 0; k < 4; k++) dG[k] /= H[k][k]; /* back substitution */ dG[2] -= dG[3] * H[2][3]; dG[1] -= dG[3] * H[1][3] + dG[2] * H[1][2]; dG[0] -= dG[3] * H[0][3] + dG[2] * H[0][2] + dG[1] * H[0][1]; /* update gains and check range */ for (k = 0; k < 4; k++) { gains[k] += dG[k]; if (gains[k] > PITCH_MAX_GAIN) gains[k] = PITCH_MAX_GAIN; else if (gains[k] < 0.0) gains[k] = 0.0; } } /* update state for next frame */ WebRtcIsac_PitchfilterPre(Whitened, out, &(State->PFstr_wght), lags, gains); /* concatenate previous input's end and current input */ memcpy(inbuf, State->inbuf, sizeof(double) * QLOOKAHEAD); memcpy(inbuf+QLOOKAHEAD, in, sizeof(double) * PITCH_FRAME_LEN); /* lookahead pitch filtering for masking analysis */ WebRtcIsac_PitchfilterPre_la(inbuf, out, &(State->PFstr), lags, gains); /* store last part of input */ for (k = 0; k < QLOOKAHEAD; k++) State->inbuf[k] = inbuf[k + PITCH_FRAME_LEN]; } RTC_POP_IGNORING_WFRAME_LARGER_THAN() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_estimator.h0000664000175000017500000000174314475643423032227 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * pitch_estimator.h * * Pitch functions * */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_ #include #include "modules/audio_coding/codecs/isac/main/source/structs.h" void WebRtcIsac_PitchAnalysis( const double* in, /* PITCH_FRAME_LEN samples */ double* out, /* PITCH_FRAME_LEN+QLOOKAHEAD samples */ PitchAnalysisStruct* State, double* lags, double* gains); #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_filter.c0000664000175000017500000003663414475643423031507 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include #include #include #include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h" #include "modules/audio_coding/codecs/isac/main/source/os_specific_inline.h" #include "rtc_base/compile_assert_c.h" /* * We are implementing the following filters; * * Pre-filtering: * y(z) = x(z) + damper(z) * gain * (x(z) + y(z)) * z ^ (-lag); * * Post-filtering: * y(z) = x(z) - damper(z) * gain * (x(z) + y(z)) * z ^ (-lag); * * Note that |lag| is a floating number so we perform an interpolation to * obtain the correct |lag|. * */ static const double kDampFilter[PITCH_DAMPORDER] = {-0.07, 0.25, 0.64, 0.25, -0.07}; /* interpolation coefficients; generated by design_pitch_filter.m */ static const double kIntrpCoef[PITCH_FRACS][PITCH_FRACORDER] = { {-0.02239172458614, 0.06653315052934, -0.16515880017569, 0.60701333734125, 0.64671399919202, -0.20249000396417, 0.09926548334755, -0.04765933793109, 0.01754159521746}, {-0.01985640750434, 0.05816126837866, -0.13991265473714, 0.44560418147643, 0.79117042386876, -0.20266133815188, 0.09585268418555, -0.04533310458084, 0.01654127246314}, {-0.01463300534216, 0.04229888475060, -0.09897034715253, 0.28284326017787, 0.90385267956632, -0.16976950138649, 0.07704272393639, -0.03584218578311, 0.01295781500709}, {-0.00764851320885, 0.02184035544377, -0.04985561057281, 0.13083306574393, 0.97545011664662, -0.10177807997561, 0.04400901776474, -0.02010737175166, 0.00719783432422}, {-0.00000000000000, 0.00000000000000, -0.00000000000001, 0.00000000000001, 0.99999999999999, 0.00000000000001, -0.00000000000001, 0.00000000000000, -0.00000000000000}, {0.00719783432422, -0.02010737175166, 0.04400901776474, -0.10177807997562, 0.97545011664663, 0.13083306574393, -0.04985561057280, 0.02184035544377, -0.00764851320885}, {0.01295781500710, -0.03584218578312, 0.07704272393640, -0.16976950138650, 0.90385267956634, 0.28284326017785, -0.09897034715252, 0.04229888475059, -0.01463300534216}, {0.01654127246315, -0.04533310458085, 0.09585268418557, -0.20266133815190, 0.79117042386878, 0.44560418147640, -0.13991265473712, 0.05816126837865, -0.01985640750433} }; /* * Enumerating the operation of the filter. * iSAC has 4 different pitch-filter which are very similar in their structure. * * kPitchFilterPre : In this mode the filter is operating as pitch * pre-filter. This is used at the encoder. * kPitchFilterPost : In this mode the filter is operating as pitch * post-filter. This is the inverse of pre-filter and used * in the decoder. * kPitchFilterPreLa : This is, in structure, similar to pre-filtering but * utilizing 3 millisecond lookahead. It is used to * obtain the signal for LPC analysis. * kPitchFilterPreGain : This is, in structure, similar to pre-filtering but * differential changes in gain is considered. This is * used to find the optimal gain. */ typedef enum { kPitchFilterPre, kPitchFilterPost, kPitchFilterPreLa, kPitchFilterPreGain } PitchFilterOperation; /* * Structure with parameters used for pitch-filtering. * buffer : a buffer where the sum of previous inputs and outputs * are stored. * damper_state : the state of the damping filter. The filter is defined by * |kDampFilter|. * interpol_coeff : pointer to a set of coefficient which are used to utilize * fractional pitch by interpolation. * gain : pitch-gain to be applied to the current segment of input. * lag : pitch-lag for the current segment of input. * lag_offset : the offset of lag w.r.t. current sample. * sub_frame : sub-frame index, there are 4 pitch sub-frames in an iSAC * frame. * This specifies the usage of the filter. See * 'PitchFilterOperation' for operational modes. * num_samples : number of samples to be processed in each segment. * index : index of the input and output sample. * damper_state_dg : state of damping filter for different trial gains. * gain_mult : differential changes to gain. */ typedef struct { double buffer[PITCH_INTBUFFSIZE + QLOOKAHEAD]; double damper_state[PITCH_DAMPORDER]; const double *interpol_coeff; double gain; double lag; int lag_offset; int sub_frame; PitchFilterOperation mode; int num_samples; int index; double damper_state_dg[4][PITCH_DAMPORDER]; double gain_mult[4]; } PitchFilterParam; /********************************************************************** * FilterSegment() * Filter one segment, a quarter of a frame. * * Inputs * in_data : pointer to the input signal of 30 ms at 8 kHz sample-rate. * filter_param : pitch filter parameters. * * Outputs * out_data : pointer to a buffer where the filtered signal is written to. * out_dg : [only used in kPitchFilterPreGain] pointer to a buffer * where the output of different gain values (differential * change to gain) is written. */ static void FilterSegment(const double* in_data, PitchFilterParam* parameters, double* out_data, double out_dg[][PITCH_FRAME_LEN + QLOOKAHEAD]) { int n; int m; int j; double sum; double sum2; /* Index of |parameters->buffer| where the output is written to. */ int pos = parameters->index + PITCH_BUFFSIZE; /* Index of |parameters->buffer| where samples are read for fractional-lag * computation. */ int pos_lag = pos - parameters->lag_offset; for (n = 0; n < parameters->num_samples; ++n) { /* Shift low pass filter states. */ for (m = PITCH_DAMPORDER - 1; m > 0; --m) { parameters->damper_state[m] = parameters->damper_state[m - 1]; } /* Filter to get fractional pitch. */ sum = 0.0; for (m = 0; m < PITCH_FRACORDER; ++m) { sum += parameters->buffer[pos_lag + m] * parameters->interpol_coeff[m]; } /* Multiply with gain. */ parameters->damper_state[0] = parameters->gain * sum; if (parameters->mode == kPitchFilterPreGain) { int lag_index = parameters->index - parameters->lag_offset; int m_tmp = (lag_index < 0) ? -lag_index : 0; /* Update the damper state for the new sample. */ for (m = PITCH_DAMPORDER - 1; m > 0; --m) { for (j = 0; j < 4; ++j) { parameters->damper_state_dg[j][m] = parameters->damper_state_dg[j][m - 1]; } } for (j = 0; j < parameters->sub_frame + 1; ++j) { /* Filter for fractional pitch. */ sum2 = 0.0; for (m = PITCH_FRACORDER-1; m >= m_tmp; --m) { /* |lag_index + m| is always larger than or equal to zero, see how * m_tmp is computed. This is equivalent to assume samples outside * |out_dg[j]| are zero. */ sum2 += out_dg[j][lag_index + m] * parameters->interpol_coeff[m]; } /* Add the contribution of differential gain change. */ parameters->damper_state_dg[j][0] = parameters->gain_mult[j] * sum + parameters->gain * sum2; } /* Filter with damping filter, and store the results. */ for (j = 0; j < parameters->sub_frame + 1; ++j) { sum = 0.0; for (m = 0; m < PITCH_DAMPORDER; ++m) { sum -= parameters->damper_state_dg[j][m] * kDampFilter[m]; } out_dg[j][parameters->index] = sum; } } /* Filter with damping filter. */ sum = 0.0; for (m = 0; m < PITCH_DAMPORDER; ++m) { sum += parameters->damper_state[m] * kDampFilter[m]; } /* Subtract from input and update buffer. */ out_data[parameters->index] = in_data[parameters->index] - sum; parameters->buffer[pos] = in_data[parameters->index] + out_data[parameters->index]; ++parameters->index; ++pos; ++pos_lag; } return; } /* Update filter parameters based on the pitch-gains and pitch-lags. */ static void Update(PitchFilterParam* parameters) { double fraction; int fraction_index; /* Compute integer lag-offset. */ parameters->lag_offset = WebRtcIsac_lrint(parameters->lag + PITCH_FILTDELAY + 0.5); /* Find correct set of coefficients for computing fractional pitch. */ fraction = parameters->lag_offset - (parameters->lag + PITCH_FILTDELAY); fraction_index = WebRtcIsac_lrint(PITCH_FRACS * fraction - 0.5); parameters->interpol_coeff = kIntrpCoef[fraction_index]; if (parameters->mode == kPitchFilterPreGain) { /* If in this mode make a differential change to pitch gain. */ parameters->gain_mult[parameters->sub_frame] += 0.2; if (parameters->gain_mult[parameters->sub_frame] > 1.0) { parameters->gain_mult[parameters->sub_frame] = 1.0; } if (parameters->sub_frame > 0) { parameters->gain_mult[parameters->sub_frame - 1] -= 0.2; } } } /****************************************************************************** * FilterFrame() * Filter a frame of 30 millisecond, given pitch-lags and pitch-gains. * * Inputs * in_data : pointer to the input signal of 30 ms at 8 kHz sample-rate. * lags : pointer to pitch-lags, 4 lags per frame. * gains : pointer to pitch-gians, 4 gains per frame. * mode : defining the functionality of the filter. It takes the * following values. * kPitchFilterPre: Pitch pre-filter, used at encoder. * kPitchFilterPost: Pitch post-filter, used at decoder. * kPitchFilterPreLa: Pitch pre-filter with lookahead. * kPitchFilterPreGain: Pitch pre-filter used to otain optimal * pitch-gains. * * Outputs * out_data : pointer to a buffer where the filtered signal is written to. * out_dg : [only used in kPitchFilterPreGain] pointer to a buffer * where the output of different gain values (differential * change to gain) is written. */ static void FilterFrame(const double* in_data, PitchFiltstr* filter_state, double* lags, double* gains, PitchFilterOperation mode, double* out_data, double out_dg[][PITCH_FRAME_LEN + QLOOKAHEAD]) { PitchFilterParam filter_parameters; double gain_delta, lag_delta; double old_lag, old_gain; int n; int m; const double kEnhancer = 1.3; /* Set up buffer and states. */ filter_parameters.index = 0; filter_parameters.lag_offset = 0; filter_parameters.mode = mode; /* Copy states to local variables. */ memcpy(filter_parameters.buffer, filter_state->ubuf, sizeof(filter_state->ubuf)); RTC_COMPILE_ASSERT(sizeof(filter_parameters.buffer) >= sizeof(filter_state->ubuf)); memset(filter_parameters.buffer + sizeof(filter_state->ubuf) / sizeof(filter_state->ubuf[0]), 0, sizeof(filter_parameters.buffer) - sizeof(filter_state->ubuf)); memcpy(filter_parameters.damper_state, filter_state->ystate, sizeof(filter_state->ystate)); if (mode == kPitchFilterPreGain) { /* Clear buffers. */ memset(filter_parameters.gain_mult, 0, sizeof(filter_parameters.gain_mult)); memset(filter_parameters.damper_state_dg, 0, sizeof(filter_parameters.damper_state_dg)); for (n = 0; n < PITCH_SUBFRAMES; ++n) { //memset(out_dg[n], 0, sizeof(double) * (PITCH_FRAME_LEN + QLOOKAHEAD)); memset(out_dg[n], 0, sizeof(out_dg[n])); } } else if (mode == kPitchFilterPost) { /* Make output more periodic. Negative sign is to change the structure * of the filter. */ for (n = 0; n < PITCH_SUBFRAMES; ++n) { gains[n] *= -kEnhancer; } } old_lag = *filter_state->oldlagp; old_gain = *filter_state->oldgainp; /* No interpolation if pitch lag step is big. */ if ((lags[0] > (PITCH_UPSTEP * old_lag)) || (lags[0] < (PITCH_DOWNSTEP * old_lag))) { old_lag = lags[0]; old_gain = gains[0]; if (mode == kPitchFilterPreGain) { filter_parameters.gain_mult[0] = 1.0; } } filter_parameters.num_samples = PITCH_UPDATE; for (m = 0; m < PITCH_SUBFRAMES; ++m) { /* Set the sub-frame value. */ filter_parameters.sub_frame = m; /* Calculate interpolation steps for pitch-lag and pitch-gain. */ lag_delta = (lags[m] - old_lag) / PITCH_GRAN_PER_SUBFRAME; filter_parameters.lag = old_lag; gain_delta = (gains[m] - old_gain) / PITCH_GRAN_PER_SUBFRAME; filter_parameters.gain = old_gain; /* Store for the next sub-frame. */ old_lag = lags[m]; old_gain = gains[m]; for (n = 0; n < PITCH_GRAN_PER_SUBFRAME; ++n) { /* Step-wise interpolation of pitch gains and lags. As pitch-lag changes, * some parameters of filter need to be update. */ filter_parameters.gain += gain_delta; filter_parameters.lag += lag_delta; /* Update parameters according to new lag value. */ Update(&filter_parameters); /* Filter a segment of input. */ FilterSegment(in_data, &filter_parameters, out_data, out_dg); } } if (mode != kPitchFilterPreGain) { /* Export buffer and states. */ memcpy(filter_state->ubuf, &filter_parameters.buffer[PITCH_FRAME_LEN], sizeof(filter_state->ubuf)); memcpy(filter_state->ystate, filter_parameters.damper_state, sizeof(filter_state->ystate)); /* Store for the next frame. */ *filter_state->oldlagp = old_lag; *filter_state->oldgainp = old_gain; } if ((mode == kPitchFilterPreGain) || (mode == kPitchFilterPreLa)) { /* Filter the lookahead segment, this is treated as the last sub-frame. So * set |pf_param| to last sub-frame. */ filter_parameters.sub_frame = PITCH_SUBFRAMES - 1; filter_parameters.num_samples = QLOOKAHEAD; FilterSegment(in_data, &filter_parameters, out_data, out_dg); } } void WebRtcIsac_PitchfilterPre(double* in_data, double* out_data, PitchFiltstr* pf_state, double* lags, double* gains) { FilterFrame(in_data, pf_state, lags, gains, kPitchFilterPre, out_data, NULL); } void WebRtcIsac_PitchfilterPre_la(double* in_data, double* out_data, PitchFiltstr* pf_state, double* lags, double* gains) { FilterFrame(in_data, pf_state, lags, gains, kPitchFilterPreLa, out_data, NULL); } void WebRtcIsac_PitchfilterPre_gains( double* in_data, double* out_data, double out_dg[][PITCH_FRAME_LEN + QLOOKAHEAD], PitchFiltstr *pf_state, double* lags, double* gains) { FilterFrame(in_data, pf_state, lags, gains, kPitchFilterPreGain, out_data, out_dg); } void WebRtcIsac_PitchfilterPost(double* in_data, double* out_data, PitchFiltstr* pf_state, double* lags, double* gains) { FilterFrame(in_data, pf_state, lags, gains, kPitchFilterPost, out_data, NULL); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_filter.h0000664000175000017500000000311214475643423031475 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_FILTER_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_FILTER_H_ #include "modules/audio_coding/codecs/isac/main/source/structs.h" void WebRtcIsac_PitchfilterPre(double* indat, double* outdat, PitchFiltstr* pfp, double* lags, double* gains); void WebRtcIsac_PitchfilterPost(double* indat, double* outdat, PitchFiltstr* pfp, double* lags, double* gains); void WebRtcIsac_PitchfilterPre_la(double* indat, double* outdat, PitchFiltstr* pfp, double* lags, double* gains); void WebRtcIsac_PitchfilterPre_gains( double* indat, double* outdat, double out_dG[][PITCH_FRAME_LEN + QLOOKAHEAD], PitchFiltstr* pfp, double* lags, double* gains); #endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_FILTER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.c0000664000175000017500000002023114475643423032454 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h" #include "modules/audio_coding/codecs/isac/main/source/settings.h" /* header file for coding tables for the pitch filter side-info in the entropy coder */ /********************* Pitch Filter Gain Coefficient Tables ************************/ /* cdf for quantized pitch filter gains */ const uint16_t WebRtcIsac_kQPitchGainCdf[255] = { 0, 2, 4, 6, 64, 901, 903, 905, 16954, 16956, 16961, 17360, 17362, 17364, 17366, 17368, 17370, 17372, 17374, 17411, 17514, 17516, 17583, 18790, 18796, 18802, 20760, 20777, 20782, 21722, 21724, 21728, 21738, 21740, 21742, 21744, 21746, 21748, 22224, 22227, 22230, 23214, 23229, 23239, 25086, 25108, 25120, 26088, 26094, 26098, 26175, 26177, 26179, 26181, 26183, 26185, 26484, 26507, 26522, 27705, 27731, 27750, 29767, 29799, 29817, 30866, 30883, 30885, 31025, 31029, 31031, 31033, 31035, 31037, 31114, 31126, 31134, 32687, 32722, 32767, 35718, 35742, 35757, 36943, 36952, 36954, 37115, 37128, 37130, 37132, 37134, 37136, 37143, 37145, 37152, 38843, 38863, 38897, 47458, 47467, 47474, 49040, 49061, 49063, 49145, 49157, 49159, 49161, 49163, 49165, 49167, 49169, 49171, 49757, 49770, 49782, 61333, 61344, 61346, 62860, 62883, 62885, 62887, 62889, 62891, 62893, 62895, 62897, 62899, 62901, 62903, 62905, 62907, 62909, 65496, 65498, 65500, 65521, 65523, 65525, 65527, 65529, 65531, 65533, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535}; /* index limits and ranges */ const int16_t WebRtcIsac_kIndexLowerLimitGain[3] = { -7, -2, -1}; const int16_t WebRtcIsac_kIndexUpperLimitGain[3] = { 0, 3, 1}; const uint16_t WebRtcIsac_kIndexMultsGain[2] = { 18, 3}; /* size of cdf table */ const uint16_t WebRtcIsac_kQCdfTableSizeGain[1] = { 256}; ///////////////////////////FIXED POINT /* mean values of pitch filter gains in FIXED point */ const int16_t WebRtcIsac_kQMeanGain1Q12[144] = { 843, 1092, 1336, 1222, 1405, 1656, 1500, 1815, 1843, 1838, 1839, 1843, 1843, 1843, 1843, 1843, 1843, 1843, 814, 846, 1092, 1013, 1174, 1383, 1391, 1511, 1584, 1734, 1753, 1843, 1843, 1843, 1843, 1843, 1843, 1843, 524, 689, 777, 845, 947, 1069, 1090, 1263, 1380, 1447, 1559, 1676, 1645, 1749, 1843, 1843, 1843, 1843, 81, 477, 563, 611, 706, 806, 849, 1012, 1192, 1128, 1330, 1489, 1425, 1576, 1826, 1741, 1843, 1843, 0, 290, 305, 356, 488, 575, 602, 741, 890, 835, 1079, 1196, 1182, 1376, 1519, 1506, 1680, 1843, 0, 47, 97, 69, 289, 381, 385, 474, 617, 664, 803, 1079, 935, 1160, 1269, 1265, 1506, 1741, 0, 0, 0, 0, 112, 120, 190, 283, 442, 343, 526, 809, 684, 935, 1134, 1020, 1265, 1506, 0, 0, 0, 0, 0, 0, 0, 111, 256, 87, 373, 597, 430, 684, 935, 770, 1020, 1265}; const int16_t WebRtcIsac_kQMeanGain2Q12[144] = { 1760, 1525, 1285, 1747, 1671, 1393, 1843, 1826, 1555, 1843, 1784, 1606, 1843, 1843, 1711, 1843, 1843, 1814, 1389, 1275, 1040, 1564, 1414, 1252, 1610, 1495, 1343, 1753, 1592, 1405, 1804, 1720, 1475, 1843, 1814, 1581, 1208, 1061, 856, 1349, 1148, 994, 1390, 1253, 1111, 1495, 1343, 1178, 1770, 1465, 1234, 1814, 1581, 1342, 1040, 793, 713, 1053, 895, 737, 1128, 1003, 861, 1277, 1094, 981, 1475, 1192, 1019, 1581, 1342, 1098, 855, 570, 483, 833, 648, 540, 948, 744, 572, 1009, 844, 636, 1234, 934, 685, 1342, 1217, 984, 537, 318, 124, 603, 423, 350, 687, 479, 322, 791, 581, 430, 987, 671, 488, 1098, 849, 597, 283, 27, 0, 397, 222, 38, 513, 271, 124, 624, 325, 157, 737, 484, 233, 849, 597, 343, 27, 0, 0, 141, 0, 0, 256, 69, 0, 370, 87, 0, 484, 229, 0, 597, 343, 87}; const int16_t WebRtcIsac_kQMeanGain3Q12[144] = { 1843, 1843, 1711, 1843, 1818, 1606, 1843, 1827, 1511, 1814, 1639, 1393, 1760, 1525, 1285, 1656, 1419, 1176, 1835, 1718, 1475, 1841, 1650, 1387, 1648, 1498, 1287, 1600, 1411, 1176, 1522, 1299, 1040, 1419, 1176, 928, 1773, 1461, 1128, 1532, 1355, 1202, 1429, 1260, 1115, 1398, 1151, 1025, 1172, 1080, 790, 1176, 928, 677, 1475, 1147, 1019, 1276, 1096, 922, 1214, 1010, 901, 1057, 893, 800, 1040, 796, 734, 928, 677, 424, 1137, 897, 753, 1120, 830, 710, 875, 751, 601, 795, 642, 583, 790, 544, 475, 677, 474, 140, 987, 750, 482, 697, 573, 450, 691, 487, 303, 661, 394, 332, 537, 303, 220, 424, 168, 0, 737, 484, 229, 624, 348, 153, 441, 261, 136, 397, 166, 51, 283, 27, 0, 168, 0, 0, 484, 229, 0, 370, 57, 0, 256, 43, 0, 141, 0, 0, 27, 0, 0, 0, 0, 0}; const int16_t WebRtcIsac_kQMeanGain4Q12[144] = { 1843, 1843, 1843, 1843, 1841, 1843, 1500, 1821, 1843, 1222, 1434, 1656, 843, 1092, 1336, 504, 757, 1007, 1843, 1843, 1843, 1838, 1791, 1843, 1265, 1505, 1599, 965, 1219, 1425, 730, 821, 1092, 249, 504, 757, 1783, 1819, 1843, 1351, 1567, 1727, 1096, 1268, 1409, 805, 961, 1131, 444, 670, 843, 0, 249, 504, 1425, 1655, 1743, 1096, 1324, 1448, 822, 1019, 1199, 490, 704, 867, 81, 450, 555, 0, 0, 249, 1247, 1428, 1530, 881, 1073, 1283, 610, 759, 939, 278, 464, 645, 0, 200, 270, 0, 0, 0, 935, 1163, 1410, 528, 790, 1068, 377, 499, 717, 173, 240, 274, 0, 43, 62, 0, 0, 0, 684, 935, 1182, 343, 551, 735, 161, 262, 423, 0, 55, 27, 0, 0, 0, 0, 0, 0, 430, 684, 935, 87, 377, 597, 0, 46, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0}; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h0000664000175000017500000000311014475643423032456 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * pitch_gain_tables.h * * This file contains tables for the pitch filter side-info in the entropy * coder. * */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_ #include /* header file for coding tables for the pitch filter side-info in the entropy * coder */ /********************* Pitch Filter Gain Coefficient Tables * ************************/ /* cdf for quantized pitch filter gains */ extern const uint16_t WebRtcIsac_kQPitchGainCdf[255]; /* index limits and ranges */ extern const int16_t WebRtcIsac_kIndexLowerLimitGain[3]; extern const int16_t WebRtcIsac_kIndexUpperLimitGain[3]; extern const uint16_t WebRtcIsac_kIndexMultsGain[2]; /* mean values of pitch filter gains */ //(Y) extern const int16_t WebRtcIsac_kQMeanGain1Q12[144]; extern const int16_t WebRtcIsac_kQMeanGain2Q12[144]; extern const int16_t WebRtcIsac_kQMeanGain3Q12[144]; extern const int16_t WebRtcIsac_kQMeanGain4Q12[144]; //(Y) /* size of cdf table */ extern const uint16_t WebRtcIsac_kQCdfTableSizeGain[1]; #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.c0000664000175000017500000003537314475643423032316 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h" #include "modules/audio_coding/codecs/isac/main/source/settings.h" /* header file for coding tables for the pitch filter side-info in the entropy coder */ /********************* Pitch Filter Gain Coefficient Tables ************************/ /* tables for use with small pitch gain */ /* cdf for quantized pitch filter lags */ const uint16_t WebRtcIsac_kQPitchLagCdf1Lo[127] = { 0, 134, 336, 549, 778, 998, 1264, 1512, 1777, 2070, 2423, 2794, 3051, 3361, 3708, 3979, 4315, 4610, 4933, 5269, 5575, 5896, 6155, 6480, 6816, 7129, 7477, 7764, 8061, 8358, 8718, 9020, 9390, 9783, 10177, 10543, 10885, 11342, 11795, 12213, 12680, 13096, 13524, 13919, 14436, 14903, 15349, 15795, 16267, 16734, 17266, 17697, 18130, 18632, 19080, 19447, 19884, 20315, 20735, 21288, 21764, 22264, 22723, 23193, 23680, 24111, 24557, 25022, 25537, 26082, 26543, 27090, 27620, 28139, 28652, 29149, 29634, 30175, 30692, 31273, 31866, 32506, 33059, 33650, 34296, 34955, 35629, 36295, 36967, 37726, 38559, 39458, 40364, 41293, 42256, 43215, 44231, 45253, 46274, 47359, 48482, 49678, 50810, 51853, 53016, 54148, 55235, 56263, 57282, 58363, 59288, 60179, 61076, 61806, 62474, 63129, 63656, 64160, 64533, 64856, 65152, 65535, 65535, 65535, 65535, 65535, 65535}; const uint16_t WebRtcIsac_kQPitchLagCdf2Lo[20] = { 0, 429, 3558, 5861, 8558, 11639, 15210, 19502, 24773, 31983, 42602, 48567, 52601, 55676, 58160, 60172, 61889, 63235, 65383, 65535}; const uint16_t WebRtcIsac_kQPitchLagCdf3Lo[2] = { 0, 65535}; const uint16_t WebRtcIsac_kQPitchLagCdf4Lo[10] = { 0, 2966, 6368, 11182, 19431, 37793, 48532, 55353, 60626, 65535}; const uint16_t *WebRtcIsac_kQPitchLagCdfPtrLo[4] = {WebRtcIsac_kQPitchLagCdf1Lo, WebRtcIsac_kQPitchLagCdf2Lo, WebRtcIsac_kQPitchLagCdf3Lo, WebRtcIsac_kQPitchLagCdf4Lo}; /* size of first cdf table */ const uint16_t WebRtcIsac_kQPitchLagCdfSizeLo[1] = {128}; /* index limits and ranges */ const int16_t WebRtcIsac_kQIndexLowerLimitLagLo[4] = { -140, -9, 0, -4}; const int16_t WebRtcIsac_kQIndexUpperLimitLagLo[4] = { -20, 9, 0, 4}; /* initial index for arithmetic decoder */ const uint16_t WebRtcIsac_kQInitIndexLagLo[3] = { 10, 1, 5}; /* mean values of pitch filter lags */ const double WebRtcIsac_kQMeanLag2Lo[19] = { -17.21385070, -15.82678944, -14.07123081, -12.03003877, -10.01311864, -8.00794627, -5.91162987, -3.89231876, -1.90220980, -0.01879275, 1.89144232, 3.88123171, 5.92146992, 7.96435361, 9.98923648, 11.98266347, 13.96101002, 15.74855713, 17.10976611}; const double WebRtcIsac_kQMeanLag3Lo[1] = { 0.00000000}; const double WebRtcIsac_kQMeanLag4Lo[9] = { -7.76246496, -5.92083980, -3.94095226, -1.89502305, 0.03724681, 1.93054221, 3.96443467, 5.91726366, 7.78434291}; const double WebRtcIsac_kQPitchLagStepsizeLo = 2.000000; /* tables for use with medium pitch gain */ /* cdf for quantized pitch filter lags */ const uint16_t WebRtcIsac_kQPitchLagCdf1Mid[255] = { 0, 28, 61, 88, 121, 149, 233, 331, 475, 559, 624, 661, 689, 712, 745, 791, 815, 843, 866, 922, 959, 1024, 1061, 1117, 1178, 1238, 1280, 1350, 1453, 1513, 1564, 1625, 1671, 1741, 1788, 1904, 2072, 2421, 2626, 2770, 2840, 2900, 2942, 3012, 3068, 3115, 3147, 3194, 3254, 3319, 3366, 3520, 3678, 3780, 3850, 3911, 3957, 4032, 4106, 4185, 4292, 4474, 4683, 4842, 5019, 5191, 5321, 5428, 5540, 5675, 5763, 5847, 5959, 6127, 6304, 6564, 6839, 7090, 7263, 7421, 7556, 7728, 7872, 7984, 8142, 8361, 8580, 8743, 8938, 9227, 9409, 9539, 9674, 9795, 9930, 10060, 10177, 10382, 10614, 10861, 11038, 11271, 11415, 11629, 11792, 12044, 12193, 12416, 12574, 12821, 13007, 13235, 13445, 13654, 13901, 14134, 14488, 15000, 15703, 16285, 16504, 16797, 17086, 17328, 17579, 17807, 17998, 18268, 18538, 18836, 19087, 19274, 19474, 19716, 19935, 20270, 20833, 21303, 21532, 21741, 21978, 22207, 22523, 22770, 23054, 23613, 23943, 24204, 24399, 24651, 24832, 25074, 25270, 25549, 25759, 26015, 26150, 26424, 26713, 27048, 27342, 27504, 27681, 27854, 28021, 28207, 28412, 28664, 28859, 29064, 29278, 29548, 29748, 30107, 30377, 30656, 30856, 31164, 31452, 31755, 32011, 32328, 32626, 32919, 33319, 33789, 34329, 34925, 35396, 35973, 36443, 36964, 37551, 38156, 38724, 39357, 40023, 40908, 41587, 42602, 43924, 45037, 45810, 46597, 47421, 48291, 49092, 50051, 51448, 52719, 53440, 54241, 54944, 55977, 56676, 57299, 57872, 58389, 59059, 59688, 60237, 60782, 61094, 61573, 61890, 62290, 62658, 63030, 63217, 63454, 63622, 63882, 64003, 64273, 64427, 64529, 64581, 64697, 64758, 64902, 65414, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535}; const uint16_t WebRtcIsac_kQPitchLagCdf2Mid[36] = { 0, 71, 335, 581, 836, 1039, 1323, 1795, 2258, 2608, 3005, 3591, 4243, 5344, 7163, 10583, 16848, 28078, 49448, 57007, 60357, 61850, 62837, 63437, 63872, 64188, 64377, 64614, 64774, 64949, 65039, 65115, 65223, 65360, 65474, 65535}; const uint16_t WebRtcIsac_kQPitchLagCdf3Mid[2] = { 0, 65535}; const uint16_t WebRtcIsac_kQPitchLagCdf4Mid[20] = { 0, 28, 246, 459, 667, 1045, 1523, 2337, 4337, 11347, 44231, 56709, 60781, 62243, 63161, 63969, 64608, 65062, 65502, 65535}; const uint16_t *WebRtcIsac_kQPitchLagCdfPtrMid[4] = {WebRtcIsac_kQPitchLagCdf1Mid, WebRtcIsac_kQPitchLagCdf2Mid, WebRtcIsac_kQPitchLagCdf3Mid, WebRtcIsac_kQPitchLagCdf4Mid}; /* size of first cdf table */ const uint16_t WebRtcIsac_kQPitchLagCdfSizeMid[1] = {256}; /* index limits and ranges */ const int16_t WebRtcIsac_kQIndexLowerLimitLagMid[4] = { -280, -17, 0, -9}; const int16_t WebRtcIsac_kQIndexUpperLimitLagMid[4] = { -40, 17, 0, 9}; /* initial index for arithmetic decoder */ const uint16_t WebRtcIsac_kQInitIndexLagMid[3] = { 18, 1, 10}; /* mean values of pitch filter lags */ const double WebRtcIsac_kQMeanLag2Mid[35] = { -16.89183900, -15.86949778, -15.05476653, -14.00664348, -13.02793036, -12.07324237, -11.00542532, -10.11250602, -8.90792971, -8.02474753, -7.00426767, -5.94055287, -4.98251338, -3.91053158, -2.98820425, -1.93524245, -0.92978085, -0.01722509, 0.91317387, 1.92973955, 2.96908851, 3.93728974, 4.96308471, 5.92244151, 7.08673497, 8.00993708, 9.04656316, 9.98538742, 10.97851694, 11.94772884, 13.02426166, 14.00039951, 15.01347042, 15.80758023, 16.94086895}; const double WebRtcIsac_kQMeanLag3Mid[1] = { 0.00000000}; const double WebRtcIsac_kQMeanLag4Mid[19] = { -8.60409403, -7.89198395, -7.03450280, -5.86260421, -4.93822322, -3.93078706, -2.91302322, -1.91824007, -0.87003282, 0.02822649, 0.89951758, 1.87495484, 2.91802604, 3.96874074, 5.06571703, 5.93618227, 7.00520185, 7.88497726, 8.64160364}; const double WebRtcIsac_kQPitchLagStepsizeMid = 1.000000; /* tables for use with large pitch gain */ /* cdf for quantized pitch filter lags */ const uint16_t WebRtcIsac_kQPitchLagCdf1Hi[511] = { 0, 7, 18, 33, 69, 105, 156, 228, 315, 612, 680, 691, 709, 724, 735, 738, 742, 746, 749, 753, 756, 760, 764, 774, 782, 785, 789, 796, 800, 803, 807, 814, 818, 822, 829, 832, 847, 854, 858, 869, 876, 883, 898, 908, 934, 977, 1010, 1050, 1060, 1064, 1075, 1078, 1086, 1089, 1093, 1104, 1111, 1122, 1133, 1136, 1151, 1162, 1183, 1209, 1252, 1281, 1339, 1364, 1386, 1401, 1411, 1415, 1426, 1430, 1433, 1440, 1448, 1455, 1462, 1477, 1487, 1495, 1502, 1506, 1509, 1516, 1524, 1531, 1535, 1542, 1553, 1556, 1578, 1589, 1611, 1625, 1639, 1643, 1654, 1665, 1672, 1687, 1694, 1705, 1708, 1719, 1730, 1744, 1752, 1759, 1791, 1795, 1820, 1867, 1886, 1915, 1936, 1943, 1965, 1987, 2041, 2099, 2161, 2175, 2200, 2211, 2226, 2233, 2244, 2251, 2266, 2280, 2287, 2298, 2309, 2316, 2331, 2342, 2356, 2378, 2403, 2418, 2447, 2497, 2544, 2602, 2863, 2895, 2903, 2935, 2950, 2971, 3004, 3011, 3018, 3029, 3040, 3062, 3087, 3127, 3152, 3170, 3199, 3243, 3293, 3322, 3340, 3377, 3402, 3427, 3474, 3518, 3543, 3579, 3601, 3637, 3659, 3706, 3731, 3760, 3818, 3847, 3869, 3901, 3920, 3952, 4068, 4169, 4220, 4271, 4524, 4571, 4604, 4632, 4672, 4730, 4777, 4806, 4857, 4904, 4951, 5002, 5031, 5060, 5107, 5150, 5212, 5266, 5331, 5382, 5432, 5490, 5544, 5610, 5700, 5762, 5812, 5874, 5972, 6022, 6091, 6163, 6232, 6305, 6402, 6540, 6685, 6880, 7090, 7271, 7379, 7452, 7542, 7625, 7687, 7770, 7843, 7911, 7966, 8024, 8096, 8190, 8252, 8320, 8411, 8501, 8585, 8639, 8751, 8842, 8918, 8986, 9066, 9127, 9203, 9269, 9345, 9406, 9464, 9536, 9612, 9667, 9735, 9844, 9931, 10036, 10119, 10199, 10260, 10358, 10441, 10514, 10666, 10734, 10872, 10951, 11053, 11125, 11223, 11324, 11516, 11664, 11737, 11816, 11892, 12008, 12120, 12200, 12280, 12392, 12490, 12576, 12685, 12812, 12917, 13003, 13108, 13210, 13300, 13384, 13470, 13579, 13673, 13771, 13879, 13999, 14136, 14201, 14368, 14614, 14759, 14867, 14958, 15030, 15121, 15189, 15280, 15385, 15461, 15555, 15653, 15768, 15884, 15971, 16069, 16145, 16210, 16279, 16380, 16463, 16539, 16615, 16688, 16818, 16919, 17017, 18041, 18338, 18523, 18649, 18790, 18917, 19047, 19167, 19315, 19460, 19601, 19731, 19858, 20068, 20173, 20318, 20466, 20625, 20741, 20911, 21045, 21201, 21396, 21588, 21816, 22022, 22305, 22547, 22786, 23072, 23322, 23600, 23879, 24168, 24433, 24769, 25120, 25511, 25895, 26289, 26792, 27219, 27683, 28077, 28566, 29094, 29546, 29977, 30491, 30991, 31573, 32105, 32594, 33173, 33788, 34497, 35181, 35833, 36488, 37255, 37921, 38645, 39275, 39894, 40505, 41167, 41790, 42431, 43096, 43723, 44385, 45134, 45858, 46607, 47349, 48091, 48768, 49405, 49955, 50555, 51167, 51985, 52611, 53078, 53494, 53965, 54435, 54996, 55601, 56125, 56563, 56838, 57244, 57566, 57967, 58297, 58771, 59093, 59419, 59647, 59886, 60143, 60461, 60693, 60917, 61170, 61416, 61634, 61891, 62122, 62310, 62455, 62632, 62839, 63103, 63436, 63639, 63805, 63906, 64015, 64192, 64355, 64475, 64558, 64663, 64742, 64811, 64865, 64916, 64956, 64981, 65025, 65068, 65115, 65195, 65314, 65419, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535}; const uint16_t WebRtcIsac_kQPitchLagCdf2Hi[68] = { 0, 7, 11, 22, 37, 52, 56, 59, 81, 85, 89, 96, 115, 130, 137, 152, 170, 181, 193, 200, 207, 233, 237, 259, 289, 318, 363, 433, 592, 992, 1607, 3062, 6149, 12206, 25522, 48368, 58223, 61918, 63640, 64584, 64943, 65098, 65206, 65268, 65294, 65335, 65350, 65372, 65387, 65402, 65413, 65420, 65428, 65435, 65439, 65450, 65454, 65468, 65472, 65476, 65483, 65491, 65498, 65505, 65516, 65520, 65528, 65535}; const uint16_t WebRtcIsac_kQPitchLagCdf3Hi[2] = { 0, 65535}; const uint16_t WebRtcIsac_kQPitchLagCdf4Hi[35] = { 0, 7, 19, 30, 41, 48, 63, 74, 82, 96, 122, 152, 215, 330, 701, 2611, 10931, 48106, 61177, 64341, 65112, 65238, 65309, 65338, 65364, 65379, 65401, 65427, 65453, 65465, 65476, 65490, 65509, 65528, 65535}; const uint16_t *WebRtcIsac_kQPitchLagCdfPtrHi[4] = {WebRtcIsac_kQPitchLagCdf1Hi, WebRtcIsac_kQPitchLagCdf2Hi, WebRtcIsac_kQPitchLagCdf3Hi, WebRtcIsac_kQPitchLagCdf4Hi}; /* size of first cdf table */ const uint16_t WebRtcIsac_kQPitchLagCdfSizeHi[1] = {512}; /* index limits and ranges */ const int16_t WebRtcIsac_kQindexLowerLimitLagHi[4] = { -552, -34, 0, -16}; const int16_t WebRtcIsac_kQindexUpperLimitLagHi[4] = { -80, 32, 0, 17}; /* initial index for arithmetic decoder */ const uint16_t WebRtcIsac_kQInitIndexLagHi[3] = { 34, 1, 18}; /* mean values of pitch filter lags */ const double WebRtcIsac_kQMeanLag2Hi[67] = { -17.07263295, -16.50000000, -15.83966081, -15.55613708, -14.96948007, -14.50000000, -14.00000000, -13.48377986, -13.00000000, -12.50000000, -11.93199636, -11.44530414, -11.04197641, -10.39910301, -10.15202337, -9.51322461, -8.93357741, -8.46456632, -8.10270672, -7.53751847, -6.98686404, -6.50000000, -6.08463150, -5.46872991, -5.00864717, -4.50163760, -4.01382410, -3.43856708, -2.96898001, -2.46554810, -1.96861004, -1.47106701, -0.97197237, -0.46561654, -0.00531409, 0.45767857, 0.96777907, 1.47507903, 1.97740425, 2.46695420, 3.00695774, 3.47167185, 4.02712538, 4.49280007, 5.01087640, 5.48191963, 6.04916550, 6.51511058, 6.97297819, 7.46565499, 8.01489405, 8.39912001, 8.91819757, 9.50000000, 10.11654065, 10.50000000, 11.03712583, 11.50000000, 12.00000000, 12.38964346, 12.89466127, 13.43657881, 13.96013840, 14.46279912, 15.00000000, 15.39412269, 15.96662441}; const double WebRtcIsac_kQMeanLag3Hi[1] = { 0.00000000}; const double WebRtcIsac_kQMeanLag4Hi[34] = { -7.98331221, -7.47988769, -7.03626557, -6.52708003, -6.06982173, -5.51856292, -5.05827033, -4.45909878, -3.99125864, -3.45308135, -3.02328139, -2.47297273, -1.94341995, -1.44699056, -0.93612243, -0.43012406, 0.01120357, 0.44054812, 0.93199883, 1.45669587, 1.97218322, 2.50187419, 2.98748690, 3.49343202, 4.01660147, 4.50984306, 5.01402683, 5.58936797, 5.91787793, 6.59998900, 6.85034315, 7.53503316, 7.87711194, 8.53631648}; const double WebRtcIsac_kQPitchLagStepsizeHi = 0.500000; /* transform matrix */ const double WebRtcIsac_kTransform[4][4] = { {-0.50000000, -0.50000000, -0.50000000, -0.50000000}, { 0.67082039, 0.22360680, -0.22360680, -0.67082039}, { 0.50000000, -0.50000000, -0.50000000, 0.50000000}, { 0.22360680, -0.67082039, 0.67082039, -0.22360680}}; /* transpose transform matrix */ const double WebRtcIsac_kTransformTranspose[4][4] = { {-0.50000000, 0.67082039, 0.50000000, 0.22360680}, {-0.50000000, 0.22360680, -0.50000000, -0.67082039}, {-0.50000000, -0.22360680, -0.50000000, 0.67082039}, {-0.50000000, -0.67082039, 0.50000000, -0.22360680}}; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h0000664000175000017500000000754514475643423032323 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * pitch_lag_tables.h * * This file contains tables for the pitch filter side-info in the entropy * coder. * */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_ #include /* header file for coding tables for the pitch filter side-info in the entropy * coder */ /********************* Pitch Filter Lag Coefficient Tables * ************************/ /* tables for use with small pitch gain */ /* cdfs for quantized pitch lags */ extern const uint16_t WebRtcIsac_kQPitchLagCdf1Lo[127]; extern const uint16_t WebRtcIsac_kQPitchLagCdf2Lo[20]; extern const uint16_t WebRtcIsac_kQPitchLagCdf3Lo[2]; extern const uint16_t WebRtcIsac_kQPitchLagCdf4Lo[10]; extern const uint16_t* WebRtcIsac_kQPitchLagCdfPtrLo[4]; /* size of first cdf table */ extern const uint16_t WebRtcIsac_kQPitchLagCdfSizeLo[1]; /* index limits and ranges */ extern const int16_t WebRtcIsac_kQIndexLowerLimitLagLo[4]; extern const int16_t WebRtcIsac_kQIndexUpperLimitLagLo[4]; /* initial index for arithmetic decoder */ extern const uint16_t WebRtcIsac_kQInitIndexLagLo[3]; /* mean values of pitch filter lags */ extern const double WebRtcIsac_kQMeanLag2Lo[19]; extern const double WebRtcIsac_kQMeanLag3Lo[1]; extern const double WebRtcIsac_kQMeanLag4Lo[9]; extern const double WebRtcIsac_kQPitchLagStepsizeLo; /* tables for use with medium pitch gain */ /* cdfs for quantized pitch lags */ extern const uint16_t WebRtcIsac_kQPitchLagCdf1Mid[255]; extern const uint16_t WebRtcIsac_kQPitchLagCdf2Mid[36]; extern const uint16_t WebRtcIsac_kQPitchLagCdf3Mid[2]; extern const uint16_t WebRtcIsac_kQPitchLagCdf4Mid[20]; extern const uint16_t* WebRtcIsac_kQPitchLagCdfPtrMid[4]; /* size of first cdf table */ extern const uint16_t WebRtcIsac_kQPitchLagCdfSizeMid[1]; /* index limits and ranges */ extern const int16_t WebRtcIsac_kQIndexLowerLimitLagMid[4]; extern const int16_t WebRtcIsac_kQIndexUpperLimitLagMid[4]; /* initial index for arithmetic decoder */ extern const uint16_t WebRtcIsac_kQInitIndexLagMid[3]; /* mean values of pitch filter lags */ extern const double WebRtcIsac_kQMeanLag2Mid[35]; extern const double WebRtcIsac_kQMeanLag3Mid[1]; extern const double WebRtcIsac_kQMeanLag4Mid[19]; extern const double WebRtcIsac_kQPitchLagStepsizeMid; /* tables for use with large pitch gain */ /* cdfs for quantized pitch lags */ extern const uint16_t WebRtcIsac_kQPitchLagCdf1Hi[511]; extern const uint16_t WebRtcIsac_kQPitchLagCdf2Hi[68]; extern const uint16_t WebRtcIsac_kQPitchLagCdf3Hi[2]; extern const uint16_t WebRtcIsac_kQPitchLagCdf4Hi[35]; extern const uint16_t* WebRtcIsac_kQPitchLagCdfPtrHi[4]; /* size of first cdf table */ extern const uint16_t WebRtcIsac_kQPitchLagCdfSizeHi[1]; /* index limits and ranges */ extern const int16_t WebRtcIsac_kQindexLowerLimitLagHi[4]; extern const int16_t WebRtcIsac_kQindexUpperLimitLagHi[4]; /* initial index for arithmetic decoder */ extern const uint16_t WebRtcIsac_kQInitIndexLagHi[3]; /* mean values of pitch filter lags */ extern const double WebRtcIsac_kQMeanLag2Hi[67]; extern const double WebRtcIsac_kQMeanLag3Hi[1]; extern const double WebRtcIsac_kQMeanLag4Hi[34]; extern const double WebRtcIsac_kQPitchLagStepsizeHi; /* transform matrix */ extern const double WebRtcIsac_kTransform[4][4]; /* transpose transform matrix */ extern const double WebRtcIsac_kTransformTranspose[4][4]; #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/settings.h0000664000175000017500000001525014475643423030667 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * settings.h * * Declaration of #defines used in the iSAC codec * */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_ /* sampling frequency (Hz) */ #define FS 16000 /* number of samples per frame (either 320 (20ms), 480 (30ms) or 960 (60ms)) */ #define INITIAL_FRAMESAMPLES 960 /* do not modify the following; this will have to be modified if we * have a 20ms framesize option */ /**********************************************************************/ /* miliseconds */ #define FRAMESIZE 30 /* number of samples per frame processed in the encoder, 480 */ #define FRAMESAMPLES 480 /* ((FRAMESIZE*FS)/1000) */ #define FRAMESAMPLES_HALF 240 #define FRAMESAMPLES_QUARTER 120 /**********************************************************************/ /* max number of samples per frame (= 60 ms frame) */ #define MAX_FRAMESAMPLES 960 #define MAX_SWBFRAMESAMPLES (MAX_FRAMESAMPLES * 2) /* number of samples per 10ms frame */ #define FRAMESAMPLES_10ms ((10 * FS) / 1000) #define SWBFRAMESAMPLES_10ms (FRAMESAMPLES_10ms * 2) /* number of samples in 30 ms frame */ #define FRAMESAMPLES_30ms 480 /* number of subframes */ #define SUBFRAMES 6 /* length of a subframe */ #define UPDATE 80 /* length of half a subframe (low/high band) */ #define HALF_SUBFRAMELEN (UPDATE / 2) /* samples of look ahead (in a half-band, so actually * half the samples of look ahead @ FS) */ #define QLOOKAHEAD 24 /* 3 ms */ /* order of AR model in spectral entropy coder */ #define AR_ORDER 6 /* order of LP model in spectral entropy coder */ #define LP_ORDER 0 /* window length (masking analysis) */ #define WINLEN 256 /* order of low-band pole filter used to approximate masking curve */ #define ORDERLO 12 /* order of hi-band pole filter used to approximate masking curve */ #define ORDERHI 6 #define UB_LPC_ORDER 4 #define UB_LPC_VEC_PER_FRAME 2 #define UB16_LPC_VEC_PER_FRAME 4 #define UB_ACTIVE_SUBFRAMES 2 #define UB_MAX_LPC_ORDER 6 #define UB_INTERPOL_SEGMENTS 1 #define UB16_INTERPOL_SEGMENTS 3 #define LB_TOTAL_DELAY_SAMPLES 48 enum ISACBandwidth { isac8kHz = 8, isac12kHz = 12, isac16kHz = 16 }; enum ISACBand { kIsacLowerBand = 0, kIsacUpperBand12 = 1, kIsacUpperBand16 = 2 }; enum IsacSamplingRate { kIsacWideband = 16, kIsacSuperWideband = 32 }; #define UB_LPC_GAIN_DIM SUBFRAMES #define FB_STATE_SIZE_WORD32 6 /* order for post_filter_bank */ #define POSTQORDER 3 /* order for pre-filterbank */ #define QORDER 3 /* another order */ #define QORDER_ALL (POSTQORDER + QORDER - 1) /* for decimator */ #define ALLPASSSECTIONS 2 /* array size for byte stream in number of bytes. */ /* The old maximum size still needed for the decoding */ #define STREAM_SIZE_MAX 600 #define STREAM_SIZE_MAX_30 200 /* 200 bytes=53.4 kbps @ 30 ms.framelength */ #define STREAM_SIZE_MAX_60 400 /* 400 bytes=53.4 kbps @ 60 ms.framelength */ /* storage size for bit counts */ #define BIT_COUNTER_SIZE 30 /* maximum order of any AR model or filter */ #define MAX_AR_MODEL_ORDER 12 // 50 /* For pitch analysis */ #define PITCH_FRAME_LEN (FRAMESAMPLES_HALF) /* 30 ms */ #define PITCH_MAX_LAG 140 /* 57 Hz */ #define PITCH_MIN_LAG 20 /* 400 Hz */ #define PITCH_MAX_GAIN 0.45 #define PITCH_MAX_GAIN_06 0.27 /* PITCH_MAX_GAIN*0.6 */ #define PITCH_MAX_GAIN_Q12 1843 #define PITCH_LAG_SPAN2 (PITCH_MAX_LAG / 2 - PITCH_MIN_LAG / 2 + 5) #define PITCH_CORR_LEN2 60 /* 15 ms */ #define PITCH_CORR_STEP2 (PITCH_FRAME_LEN / 4) #define PITCH_BW 11 /* half the band width of correlation surface */ #define PITCH_SUBFRAMES 4 #define PITCH_GRAN_PER_SUBFRAME 5 #define PITCH_SUBFRAME_LEN (PITCH_FRAME_LEN / PITCH_SUBFRAMES) #define PITCH_UPDATE (PITCH_SUBFRAME_LEN / PITCH_GRAN_PER_SUBFRAME) /* maximum number of peaks to be examined in correlation surface */ #define PITCH_MAX_NUM_PEAKS 10 #define PITCH_PEAK_DECAY 0.85 /* For weighting filter */ #define PITCH_WLPCORDER 6 #define PITCH_WLPCWINLEN PITCH_FRAME_LEN #define PITCH_WLPCASYM 0.3 /* asymmetry parameter */ #define PITCH_WLPCBUFLEN PITCH_WLPCWINLEN /* For pitch filter */ /* Extra 50 for fraction and LP filters */ #define PITCH_BUFFSIZE (PITCH_MAX_LAG + 50) #define PITCH_INTBUFFSIZE (PITCH_FRAME_LEN + PITCH_BUFFSIZE) /* Max rel. step for interpolation */ #define PITCH_UPSTEP 1.5 /* Max rel. step for interpolation */ #define PITCH_DOWNSTEP 0.67 #define PITCH_FRACS 8 #define PITCH_FRACORDER 9 #define PITCH_DAMPORDER 5 #define PITCH_FILTDELAY 1.5f /* stepsize for quantization of the pitch Gain */ #define PITCH_GAIN_STEPSIZE 0.125 /* Order of high pass filter */ #define HPORDER 2 /* some mathematical constants */ /* log2(exp) */ #define LOG2EXP 1.44269504088896 #define PI 3.14159265358979 /* Maximum number of iterations allowed to limit payload size */ #define MAX_PAYLOAD_LIMIT_ITERATION 5 /* Redundant Coding */ #define RCU_BOTTLENECK_BPS 16000 #define RCU_TRANSCODING_SCALE 0.40f #define RCU_TRANSCODING_SCALE_INVERSE 2.5f #define RCU_TRANSCODING_SCALE_UB 0.50f #define RCU_TRANSCODING_SCALE_UB_INVERSE 2.0f /* Define Error codes */ /* 6000 General */ #define ISAC_MEMORY_ALLOCATION_FAILED 6010 #define ISAC_MODE_MISMATCH 6020 #define ISAC_DISALLOWED_BOTTLENECK 6030 #define ISAC_DISALLOWED_FRAME_LENGTH 6040 #define ISAC_UNSUPPORTED_SAMPLING_FREQUENCY 6050 /* 6200 Bandwidth estimator */ #define ISAC_RANGE_ERROR_BW_ESTIMATOR 6240 /* 6400 Encoder */ #define ISAC_ENCODER_NOT_INITIATED 6410 #define ISAC_DISALLOWED_CODING_MODE 6420 #define ISAC_DISALLOWED_FRAME_MODE_ENCODER 6430 #define ISAC_DISALLOWED_BITSTREAM_LENGTH 6440 #define ISAC_PAYLOAD_LARGER_THAN_LIMIT 6450 #define ISAC_DISALLOWED_ENCODER_BANDWIDTH 6460 /* 6600 Decoder */ #define ISAC_DECODER_NOT_INITIATED 6610 #define ISAC_EMPTY_PACKET 6620 #define ISAC_DISALLOWED_FRAME_MODE_DECODER 6630 #define ISAC_RANGE_ERROR_DECODE_FRAME_LENGTH 6640 #define ISAC_RANGE_ERROR_DECODE_BANDWIDTH 6650 #define ISAC_RANGE_ERROR_DECODE_PITCH_GAIN 6660 #define ISAC_RANGE_ERROR_DECODE_PITCH_LAG 6670 #define ISAC_RANGE_ERROR_DECODE_LPC 6680 #define ISAC_RANGE_ERROR_DECODE_SPECTRUM 6690 #define ISAC_LENGTH_MISMATCH 6730 #define ISAC_RANGE_ERROR_DECODE_BANDWITH 6740 #define ISAC_DISALLOWED_BANDWIDTH_MODE_DECODER 6750 #define ISAC_DISALLOWED_LPC_MODEL 6760 /* 6800 Call setup formats */ #define ISAC_INCOMPATIBLE_FORMATS 6810 #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_ */ ././@PaxHeader0000000000000000000000000000021200000000000010210 xustar00116 path=webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.c 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_ta0000664000175000017500000001650214475643423032772 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h" #include "modules/audio_coding/codecs/isac/main/source/settings.h" /********************* AR Coefficient Tables ************************/ /* cdf for quantized reflection coefficient 1 */ const uint16_t WebRtcIsac_kQArRc1Cdf[NUM_AR_RC_QUANT_BAUNDARY] = { 0, 2, 4, 129, 7707, 57485, 65495, 65527, 65529, 65531, 65533, 65535}; /* cdf for quantized reflection coefficient 2 */ const uint16_t WebRtcIsac_kQArRc2Cdf[NUM_AR_RC_QUANT_BAUNDARY] = { 0, 2, 4, 7, 531, 25298, 64525, 65526, 65529, 65531, 65533, 65535}; /* cdf for quantized reflection coefficient 3 */ const uint16_t WebRtcIsac_kQArRc3Cdf[NUM_AR_RC_QUANT_BAUNDARY] = { 0, 2, 4, 6, 620, 22898, 64843, 65527, 65529, 65531, 65533, 65535}; /* cdf for quantized reflection coefficient 4 */ const uint16_t WebRtcIsac_kQArRc4Cdf[NUM_AR_RC_QUANT_BAUNDARY] = { 0, 2, 4, 6, 35, 10034, 60733, 65506, 65529, 65531, 65533, 65535}; /* cdf for quantized reflection coefficient 5 */ const uint16_t WebRtcIsac_kQArRc5Cdf[NUM_AR_RC_QUANT_BAUNDARY] = { 0, 2, 4, 6, 36, 7567, 56727, 65385, 65529, 65531, 65533, 65535}; /* cdf for quantized reflection coefficient 6 */ const uint16_t WebRtcIsac_kQArRc6Cdf[NUM_AR_RC_QUANT_BAUNDARY] = { 0, 2, 4, 6, 14, 6579, 57360, 65409, 65529, 65531, 65533, 65535}; /* representation levels for quantized reflection coefficient 1 */ const int16_t WebRtcIsac_kQArRc1Levels[NUM_AR_RC_QUANT_BAUNDARY - 1] = { -32104, -29007, -23202, -15496, -9279, -2577, 5934, 17535, 24512, 29503, 32104 }; /* representation levels for quantized reflection coefficient 2 */ const int16_t WebRtcIsac_kQArRc2Levels[NUM_AR_RC_QUANT_BAUNDARY - 1] = { -32104, -29503, -23494, -15261, -7309, -1399, 6158, 16381, 24512, 29503, 32104 }; /* representation levels for quantized reflection coefficient 3 */ const int16_t WebRtcIsac_kQArRc3Levels[NUM_AR_RC_QUANT_BAUNDARY - 1] = { -32104, -29503, -23157, -15186, -7347, -1359, 5829, 17535, 24512, 29503, 32104 }; /* representation levels for quantized reflection coefficient 4 */ const int16_t WebRtcIsac_kQArRc4Levels[NUM_AR_RC_QUANT_BAUNDARY - 1] = { -32104, -29503, -24512, -15362, -6665, -342, 6596, 14585, 24512, 29503, 32104 }; /* representation levels for quantized reflection coefficient 5 */ const int16_t WebRtcIsac_kQArRc5Levels[NUM_AR_RC_QUANT_BAUNDARY - 1] = { -32104, -29503, -24512, -15005, -6564, -106, 7123, 14920, 24512, 29503, 32104 }; /* representation levels for quantized reflection coefficient 6 */ const int16_t WebRtcIsac_kQArRc6Levels[NUM_AR_RC_QUANT_BAUNDARY - 1] = { -32104, -29503, -24512, -15096, -6656, -37, 7036, 14847, 24512, 29503, 32104 }; /* quantization boundary levels for reflection coefficients */ const int16_t WebRtcIsac_kQArBoundaryLevels[NUM_AR_RC_QUANT_BAUNDARY] = { -32768, -31441, -27566, -21458, -13612, -4663, 4663, 13612, 21458, 27566, 31441, 32767 }; /* initial index for AR reflection coefficient quantizer and cdf table search */ const uint16_t WebRtcIsac_kQArRcInitIndex[6] = { 5, 5, 5, 5, 5, 5}; /* pointers to AR cdf tables */ const uint16_t *WebRtcIsac_kQArRcCdfPtr[AR_ORDER] = { WebRtcIsac_kQArRc1Cdf, WebRtcIsac_kQArRc2Cdf, WebRtcIsac_kQArRc3Cdf, WebRtcIsac_kQArRc4Cdf, WebRtcIsac_kQArRc5Cdf, WebRtcIsac_kQArRc6Cdf }; /* pointers to AR representation levels tables */ const int16_t *WebRtcIsac_kQArRcLevelsPtr[AR_ORDER] = { WebRtcIsac_kQArRc1Levels, WebRtcIsac_kQArRc2Levels, WebRtcIsac_kQArRc3Levels, WebRtcIsac_kQArRc4Levels, WebRtcIsac_kQArRc5Levels, WebRtcIsac_kQArRc6Levels }; /******************** GAIN Coefficient Tables ***********************/ /* cdf for Gain coefficient */ const uint16_t WebRtcIsac_kQGainCdf[19] = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 1172, 11119, 29411, 51699, 64445, 65527, 65529, 65531, 65533, 65535}; /* representation levels for quantized squared Gain coefficient */ const int32_t WebRtcIsac_kQGain2Levels[18] = { // 17, 28, 46, 76, 128, 215, 364, 709, 1268, 1960, 3405, 6078, 11286, 17827, 51918, 134498, 487432, 2048000}; 128, 128, 128, 128, 128, 215, 364, 709, 1268, 1960, 3405, 6078, 11286, 17827, 51918, 134498, 487432, 2048000}; /* quantization boundary levels for squared Gain coefficient */ const int32_t WebRtcIsac_kQGain2BoundaryLevels[19] = { 0, 21, 35, 59, 99, 166, 280, 475, 815, 1414, 2495, 4505, 8397, 16405, 34431, 81359, 240497, 921600, 0x7FFFFFFF}; /* pointers to Gain cdf table */ const uint16_t *WebRtcIsac_kQGainCdf_ptr[1] = {WebRtcIsac_kQGainCdf}; /* Gain initial index for gain quantizer and cdf table search */ const uint16_t WebRtcIsac_kQGainInitIndex[1] = {11}; /************************* Cosine Tables ****************************/ /* Cosine table */ const int16_t WebRtcIsac_kCos[6][60] = { {512, 512, 511, 510, 508, 507, 505, 502, 499, 496, 493, 489, 485, 480, 476, 470, 465, 459, 453, 447, 440, 433, 426, 418, 410, 402, 394, 385, 376, 367, 357, 348, 338, 327, 317, 306, 295, 284, 273, 262, 250, 238, 226, 214, 202, 190, 177, 165, 152, 139, 126, 113, 100, 87, 73, 60, 47, 33, 20, 7}, {512, 510, 508, 503, 498, 491, 483, 473, 462, 450, 437, 422, 406, 389, 371, 352, 333, 312, 290, 268, 244, 220, 196, 171, 145, 120, 93, 67, 40, 13, -13, -40, -67, -93, -120, -145, -171, -196, -220, -244, -268, -290, -312, -333, -352, -371, -389, -406, -422, -437, -450, -462, -473, -483, -491, -498, -503, -508, -510, -512}, {512, 508, 502, 493, 480, 465, 447, 426, 402, 376, 348, 317, 284, 250, 214, 177, 139, 100, 60, 20, -20, -60, -100, -139, -177, -214, -250, -284, -317, -348, -376, -402, -426, -447, -465, -480, -493, -502, -508, -512, -512, -508, -502, -493, -480, -465, -447, -426, -402, -376, -348, -317, -284, -250, -214, -177, -139, -100, -60, -20}, {511, 506, 495, 478, 456, 429, 398, 362, 322, 279, 232, 183, 133, 80, 27, -27, -80, -133, -183, -232, -279, -322, -362, -398, -429, -456, -478, -495, -506, -511, -511, -506, -495, -478, -456, -429, -398, -362, -322, -279, -232, -183, -133, -80, -27, 27, 80, 133, 183, 232, 279, 322, 362, 398, 429, 456, 478, 495, 506, 511}, {511, 502, 485, 459, 426, 385, 338, 284, 226, 165, 100, 33, -33, -100, -165, -226, -284, -338, -385, -426, -459, -485, -502, -511, -511, -502, -485, -459, -426, -385, -338, -284, -226, -165, -100, -33, 33, 100, 165, 226, 284, 338, 385, 426, 459, 485, 502, 511, 511, 502, 485, 459, 426, 385, 338, 284, 226, 165, 100, 33}, {510, 498, 473, 437, 389, 333, 268, 196, 120, 40, -40, -120, -196, -268, -333, -389, -437, -473, -498, -510, -510, -498, -473, -437, -389, -333, -268, -196, -120, -40, 40, 120, 196, 268, 333, 389, 437, 473, 498, 510, 510, 498, 473, 437, 389, 333, 268, 196, 120, 40, -40, -120, -196, -268, -333, -389, -437, -473, -498, -510} }; ././@PaxHeader0000000000000000000000000000021200000000000010210 xustar00116 path=webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_ta0000664000175000017500000000557314475643423033000 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * spectrum_ar_model_tables.h * * This file contains definitions of tables with AR coefficients, * Gain coefficients and cosine tables. * */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ #include "modules/audio_coding/codecs/isac/main/source/structs.h" #define NUM_AR_RC_QUANT_BAUNDARY 12 /********************* AR Coefficient Tables ************************/ /* cdf for quantized reflection coefficient 1 */ extern const uint16_t WebRtcIsac_kQArRc1Cdf[NUM_AR_RC_QUANT_BAUNDARY]; /* cdf for quantized reflection coefficient 2 */ extern const uint16_t WebRtcIsac_kQArRc2Cdf[NUM_AR_RC_QUANT_BAUNDARY]; /* cdf for quantized reflection coefficient 3 */ extern const uint16_t WebRtcIsac_kQArRc3Cdf[NUM_AR_RC_QUANT_BAUNDARY]; /* cdf for quantized reflection coefficient 4 */ extern const uint16_t WebRtcIsac_kQArRc4Cdf[NUM_AR_RC_QUANT_BAUNDARY]; /* cdf for quantized reflection coefficient 5 */ extern const uint16_t WebRtcIsac_kQArRc5Cdf[NUM_AR_RC_QUANT_BAUNDARY]; /* cdf for quantized reflection coefficient 6 */ extern const uint16_t WebRtcIsac_kQArRc6Cdf[NUM_AR_RC_QUANT_BAUNDARY]; /* quantization boundary levels for reflection coefficients */ extern const int16_t WebRtcIsac_kQArBoundaryLevels[NUM_AR_RC_QUANT_BAUNDARY]; /* initial indices for AR reflection coefficient quantizer and cdf table search */ extern const uint16_t WebRtcIsac_kQArRcInitIndex[AR_ORDER]; /* pointers to AR cdf tables */ extern const uint16_t* WebRtcIsac_kQArRcCdfPtr[AR_ORDER]; /* pointers to AR representation levels tables */ extern const int16_t* WebRtcIsac_kQArRcLevelsPtr[AR_ORDER]; /******************** GAIN Coefficient Tables ***********************/ /* cdf for Gain coefficient */ extern const uint16_t WebRtcIsac_kQGainCdf[19]; /* representation levels for quantized Gain coefficient */ extern const int32_t WebRtcIsac_kQGain2Levels[18]; /* squared quantization boundary levels for Gain coefficient */ extern const int32_t WebRtcIsac_kQGain2BoundaryLevels[19]; /* pointer to Gain cdf table */ extern const uint16_t* WebRtcIsac_kQGainCdf_ptr[1]; /* Gain initial index for gain quantizer and cdf table search */ extern const uint16_t WebRtcIsac_kQGainInitIndex[1]; /************************* Cosine Tables ****************************/ /* Cosine table */ extern const int16_t WebRtcIsac_kCos[6][60]; #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ \ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/structs.h0000664000175000017500000003022114475643423030531 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * structs.h * * This header file contains all the structs used in the ISAC codec * */ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_ #include "modules/audio_coding/codecs/isac/bandwidth_info.h" #include "modules/audio_coding/codecs/isac/main/source/settings.h" #include "modules/third_party/fft/fft.h" typedef struct Bitstreamstruct { uint8_t stream[STREAM_SIZE_MAX]; uint32_t W_upper; uint32_t streamval; uint32_t stream_index; } Bitstr; typedef struct { double DataBufferLo[WINLEN]; double DataBufferHi[WINLEN]; double CorrBufLo[ORDERLO + 1]; double CorrBufHi[ORDERHI + 1]; float PreStateLoF[ORDERLO + 1]; float PreStateLoG[ORDERLO + 1]; float PreStateHiF[ORDERHI + 1]; float PreStateHiG[ORDERHI + 1]; float PostStateLoF[ORDERLO + 1]; float PostStateLoG[ORDERLO + 1]; float PostStateHiF[ORDERHI + 1]; float PostStateHiG[ORDERHI + 1]; double OldEnergy; } MaskFiltstr; typedef struct { // state vectors for each of the two analysis filters double INSTAT1[2 * (QORDER - 1)]; double INSTAT2[2 * (QORDER - 1)]; double INSTATLA1[2 * (QORDER - 1)]; double INSTATLA2[2 * (QORDER - 1)]; double INLABUF1[QLOOKAHEAD]; double INLABUF2[QLOOKAHEAD]; float INSTAT1_float[2 * (QORDER - 1)]; float INSTAT2_float[2 * (QORDER - 1)]; float INSTATLA1_float[2 * (QORDER - 1)]; float INSTATLA2_float[2 * (QORDER - 1)]; float INLABUF1_float[QLOOKAHEAD]; float INLABUF2_float[QLOOKAHEAD]; /* High pass filter */ double HPstates[HPORDER]; float HPstates_float[HPORDER]; } PreFiltBankstr; typedef struct { // state vectors for each of the two analysis filters double STATE_0_LOWER[2 * POSTQORDER]; double STATE_0_UPPER[2 * POSTQORDER]; /* High pass filter */ double HPstates1[HPORDER]; double HPstates2[HPORDER]; float STATE_0_LOWER_float[2 * POSTQORDER]; float STATE_0_UPPER_float[2 * POSTQORDER]; float HPstates1_float[HPORDER]; float HPstates2_float[HPORDER]; } PostFiltBankstr; typedef struct { // data buffer for pitch filter double ubuf[PITCH_BUFFSIZE]; // low pass state vector double ystate[PITCH_DAMPORDER]; // old lag and gain double oldlagp[1]; double oldgainp[1]; } PitchFiltstr; typedef struct { // data buffer double buffer[PITCH_WLPCBUFLEN]; // state vectors double istate[PITCH_WLPCORDER]; double weostate[PITCH_WLPCORDER]; double whostate[PITCH_WLPCORDER]; // LPC window -> should be a global array because constant double window[PITCH_WLPCWINLEN]; } WeightFiltstr; typedef struct { // for inital estimator double dec_buffer[PITCH_CORR_LEN2 + PITCH_CORR_STEP2 + PITCH_MAX_LAG / 2 - PITCH_FRAME_LEN / 2 + 2]; double decimator_state[2 * ALLPASSSECTIONS + 1]; double hp_state[2]; double whitened_buf[QLOOKAHEAD]; double inbuf[QLOOKAHEAD]; PitchFiltstr PFstr_wght; PitchFiltstr PFstr; WeightFiltstr Wghtstr; } PitchAnalysisStruct; /* Have instance of struct together with other iSAC structs */ typedef struct { /* Previous frame length (in ms) */ int32_t prev_frame_length; /* Previous RTP timestamp from received packet (in samples relative beginning) */ int32_t prev_rec_rtp_number; /* Send timestamp for previous packet (in ms using timeGetTime()) */ uint32_t prev_rec_send_ts; /* Arrival time for previous packet (in ms using timeGetTime()) */ uint32_t prev_rec_arr_ts; /* rate of previous packet, derived from RTP timestamps (in bits/s) */ float prev_rec_rtp_rate; /* Time sinse the last update of the BN estimate (in ms) */ uint32_t last_update_ts; /* Time sinse the last reduction (in ms) */ uint32_t last_reduction_ts; /* How many times the estimate was update in the beginning */ int32_t count_tot_updates_rec; /* The estimated bottle neck rate from there to here (in bits/s) */ int32_t rec_bw; float rec_bw_inv; float rec_bw_avg; float rec_bw_avg_Q; /* The estimated mean absolute jitter value, as seen on this side (in ms) */ float rec_jitter; float rec_jitter_short_term; float rec_jitter_short_term_abs; float rec_max_delay; float rec_max_delay_avg_Q; /* (assumed) bitrate for headers (bps) */ float rec_header_rate; /* The estimated bottle neck rate from here to there (in bits/s) */ float send_bw_avg; /* The estimated mean absolute jitter value, as seen on the other siee (in ms) */ float send_max_delay_avg; // number of packets received since last update int num_pkts_rec; int num_consec_rec_pkts_over_30k; // flag for marking that a high speed network has been // detected downstream int hsn_detect_rec; int num_consec_snt_pkts_over_30k; // flag for marking that a high speed network has // been detected upstream int hsn_detect_snd; uint32_t start_wait_period; int in_wait_period; int change_to_WB; uint32_t senderTimestamp; uint32_t receiverTimestamp; // enum IsacSamplingRate incomingStreamSampFreq; uint16_t numConsecLatePkts; float consecLatency; int16_t inWaitLatePkts; IsacBandwidthInfo external_bw_info; } BwEstimatorstr; typedef struct { /* boolean, flags if previous packet exceeded B.N. */ int PrevExceed; /* ms */ int ExceedAgo; /* packets left to send in current burst */ int BurstCounter; /* packets */ int InitCounter; /* ms remaining in buffer when next packet will be sent */ double StillBuffered; } RateModel; /* The following strutc is used to store data from encoding, to make it fast and easy to construct a new bitstream with a different Bandwidth estimate. All values (except framelength and minBytes) is double size to handle 60 ms of data. */ typedef struct { /* Used to keep track of if it is first or second part of 60 msec packet */ int startIdx; /* Frame length in samples */ int16_t framelength; /* Pitch Gain */ int pitchGain_index[2]; /* Pitch Lag */ double meanGain[2]; int pitchIndex[PITCH_SUBFRAMES * 2]; /* LPC */ int LPCindex_s[108 * 2]; /* KLT_ORDER_SHAPE = 108 */ int LPCindex_g[12 * 2]; /* KLT_ORDER_GAIN = 12 */ double LPCcoeffs_lo[(ORDERLO + 1) * SUBFRAMES * 2]; double LPCcoeffs_hi[(ORDERHI + 1) * SUBFRAMES * 2]; /* Encode Spec */ int16_t fre[FRAMESAMPLES]; int16_t fim[FRAMESAMPLES]; int16_t AvgPitchGain[2]; /* Used in adaptive mode only */ int minBytes; } IsacSaveEncoderData; typedef struct { int indexLPCShape[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; double lpcGain[SUBFRAMES << 1]; int lpcGainIndex[SUBFRAMES << 1]; Bitstr bitStreamObj; int16_t realFFT[FRAMESAMPLES_HALF]; int16_t imagFFT[FRAMESAMPLES_HALF]; } ISACUBSaveEncDataStruct; typedef struct { Bitstr bitstr_obj; MaskFiltstr maskfiltstr_obj; PreFiltBankstr prefiltbankstr_obj; PitchFiltstr pitchfiltstr_obj; PitchAnalysisStruct pitchanalysisstr_obj; FFTstr fftstr_obj; IsacSaveEncoderData SaveEnc_obj; int buffer_index; int16_t current_framesamples; float data_buffer_float[FRAMESAMPLES_30ms]; int frame_nb; double bottleneck; int16_t new_framelength; double s2nr; /* Maximum allowed number of bits for a 30 msec packet */ int16_t payloadLimitBytes30; /* Maximum allowed number of bits for a 30 msec packet */ int16_t payloadLimitBytes60; /* Maximum allowed number of bits for both 30 and 60 msec packet */ int16_t maxPayloadBytes; /* Maximum allowed rate in bytes per 30 msec packet */ int16_t maxRateInBytes; /*--- If set to 1 iSAC will not adapt the frame-size, if used in channel-adaptive mode. The initial value will be used for all rates. ---*/ int16_t enforceFrameSize; /*----- This records the BWE index the encoder injected into the bit-stream. It will be used in RCU. The same BWE index of main payload will be in the redundant payload. We can not retrieve it from BWE because it is a recursive procedure (WebRtcIsac_GetDownlinkBwJitIndexImpl) and has to be called only once per each encode. -----*/ int16_t lastBWIdx; } ISACLBEncStruct; typedef struct { Bitstr bitstr_obj; MaskFiltstr maskfiltstr_obj; PreFiltBankstr prefiltbankstr_obj; FFTstr fftstr_obj; ISACUBSaveEncDataStruct SaveEnc_obj; int buffer_index; float data_buffer_float[MAX_FRAMESAMPLES + LB_TOTAL_DELAY_SAMPLES]; double bottleneck; /* Maximum allowed number of bits for a 30 msec packet */ // int16_t payloadLimitBytes30; /* Maximum allowed number of bits for both 30 and 60 msec packet */ // int16_t maxPayloadBytes; int16_t maxPayloadSizeBytes; double lastLPCVec[UB_LPC_ORDER]; int16_t numBytesUsed; int16_t lastJitterInfo; } ISACUBEncStruct; typedef struct { Bitstr bitstr_obj; MaskFiltstr maskfiltstr_obj; PostFiltBankstr postfiltbankstr_obj; PitchFiltstr pitchfiltstr_obj; FFTstr fftstr_obj; } ISACLBDecStruct; typedef struct { Bitstr bitstr_obj; MaskFiltstr maskfiltstr_obj; PostFiltBankstr postfiltbankstr_obj; FFTstr fftstr_obj; } ISACUBDecStruct; typedef struct { ISACLBEncStruct ISACencLB_obj; ISACLBDecStruct ISACdecLB_obj; } ISACLBStruct; typedef struct { ISACUBEncStruct ISACencUB_obj; ISACUBDecStruct ISACdecUB_obj; } ISACUBStruct; /* This struct is used to take a snapshot of the entropy coder and LPC gains right before encoding LPC gains. This allows us to go back to that state if we like to limit the payload size. */ typedef struct { /* 6 lower-band & 6 upper-band */ double loFiltGain[SUBFRAMES]; double hiFiltGain[SUBFRAMES]; /* Upper boundary of interval W */ uint32_t W_upper; uint32_t streamval; /* Index to the current position in bytestream */ uint32_t stream_index; uint8_t stream[3]; } transcode_obj; typedef struct { // TODO(kwiberg): The size of these tables could be reduced by storing floats // instead of doubles, and by making use of the identity cos(x) = // sin(x+pi/2). They could also be made global constants that we fill in at // compile time. double costab1[FRAMESAMPLES_HALF]; double sintab1[FRAMESAMPLES_HALF]; double costab2[FRAMESAMPLES_QUARTER]; double sintab2[FRAMESAMPLES_QUARTER]; } TransformTables; typedef struct { // lower-band codec instance ISACLBStruct instLB; // upper-band codec instance ISACUBStruct instUB; // Bandwidth Estimator and model for the rate. BwEstimatorstr bwestimator_obj; RateModel rate_data_obj; double MaxDelay; /* 0 = adaptive; 1 = instantaneous */ int16_t codingMode; // overall bottleneck of the codec int32_t bottleneck; // QMF Filter state int32_t analysisFBState1[FB_STATE_SIZE_WORD32]; int32_t analysisFBState2[FB_STATE_SIZE_WORD32]; int32_t synthesisFBState1[FB_STATE_SIZE_WORD32]; int32_t synthesisFBState2[FB_STATE_SIZE_WORD32]; // Error Code int16_t errorCode; // bandwidth of the encoded audio 8, 12 or 16 kHz enum ISACBandwidth bandwidthKHz; // Sampling rate of audio, encoder and decode, 8 or 16 kHz enum IsacSamplingRate encoderSamplingRateKHz; enum IsacSamplingRate decoderSamplingRateKHz; // Flag to keep track of initializations, lower & upper-band // encoder and decoder. int16_t initFlag; // Flag to to indicate signal bandwidth switch int16_t resetFlag_8kHz; // Maximum allowed rate, measured in Bytes per 30 ms. int16_t maxRateBytesPer30Ms; // Maximum allowed payload-size, measured in Bytes. int16_t maxPayloadSizeBytes; /* The expected sampling rate of the input signal. Valid values are 16000 * and 32000. This is not the operation sampling rate of the codec. */ uint16_t in_sample_rate_hz; // Trig tables for WebRtcIsac_Time2Spec and WebRtcIsac_Spec2time. TransformTables transform_tables; } ISACMainStruct; #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/codecs/isac/main/source/transform.c0000664000175000017500000001033414475643423031033 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include #include "modules/audio_coding/codecs/isac/main/source/settings.h" #include "modules/audio_coding/codecs/isac/main/source/codec.h" #include "modules/audio_coding/codecs/isac/main/source/os_specific_inline.h" #include "modules/third_party/fft/fft.h" void WebRtcIsac_InitTransform(TransformTables* tables) { int k; double fact, phase; fact = PI / (FRAMESAMPLES_HALF); phase = 0.0; for (k = 0; k < FRAMESAMPLES_HALF; k++) { tables->costab1[k] = cos(phase); tables->sintab1[k] = sin(phase); phase += fact; } fact = PI * ((double) (FRAMESAMPLES_HALF - 1)) / ((double) FRAMESAMPLES_HALF); phase = 0.5 * fact; for (k = 0; k < FRAMESAMPLES_QUARTER; k++) { tables->costab2[k] = cos(phase); tables->sintab2[k] = sin(phase); phase += fact; } } void WebRtcIsac_Time2Spec(const TransformTables* tables, double* inre1, double* inre2, int16_t* outreQ7, int16_t* outimQ7, FFTstr* fftstr_obj) { int k; int dims[1]; double tmp1r, tmp1i, xr, xi, yr, yi, fact; double tmpre[FRAMESAMPLES_HALF], tmpim[FRAMESAMPLES_HALF]; dims[0] = FRAMESAMPLES_HALF; /* Multiply with complex exponentials and combine into one complex vector */ fact = 0.5 / sqrt(FRAMESAMPLES_HALF); for (k = 0; k < FRAMESAMPLES_HALF; k++) { tmp1r = tables->costab1[k]; tmp1i = tables->sintab1[k]; tmpre[k] = (inre1[k] * tmp1r + inre2[k] * tmp1i) * fact; tmpim[k] = (inre2[k] * tmp1r - inre1[k] * tmp1i) * fact; } /* Get DFT */ WebRtcIsac_Fftns(1, dims, tmpre, tmpim, -1, 1.0, fftstr_obj); /* Use symmetry to separate into two complex vectors and center frames in time around zero */ for (k = 0; k < FRAMESAMPLES_QUARTER; k++) { xr = tmpre[k] + tmpre[FRAMESAMPLES_HALF - 1 - k]; yi = -tmpre[k] + tmpre[FRAMESAMPLES_HALF - 1 - k]; xi = tmpim[k] - tmpim[FRAMESAMPLES_HALF - 1 - k]; yr = tmpim[k] + tmpim[FRAMESAMPLES_HALF - 1 - k]; tmp1r = tables->costab2[k]; tmp1i = tables->sintab2[k]; outreQ7[k] = (int16_t)WebRtcIsac_lrint((xr * tmp1r - xi * tmp1i) * 128.0); outimQ7[k] = (int16_t)WebRtcIsac_lrint((xr * tmp1i + xi * tmp1r) * 128.0); outreQ7[FRAMESAMPLES_HALF - 1 - k] = (int16_t)WebRtcIsac_lrint((-yr * tmp1i - yi * tmp1r) * 128.0); outimQ7[FRAMESAMPLES_HALF - 1 - k] = (int16_t)WebRtcIsac_lrint((-yr * tmp1r + yi * tmp1i) * 128.0); } } void WebRtcIsac_Spec2time(const TransformTables* tables, double* inre, double* inim, double* outre1, double* outre2, FFTstr* fftstr_obj) { int k; double tmp1r, tmp1i, xr, xi, yr, yi, fact; int dims; dims = FRAMESAMPLES_HALF; for (k = 0; k < FRAMESAMPLES_QUARTER; k++) { /* Move zero in time to beginning of frames */ tmp1r = tables->costab2[k]; tmp1i = tables->sintab2[k]; xr = inre[k] * tmp1r + inim[k] * tmp1i; xi = inim[k] * tmp1r - inre[k] * tmp1i; yr = -inim[FRAMESAMPLES_HALF - 1 - k] * tmp1r - inre[FRAMESAMPLES_HALF - 1 - k] * tmp1i; yi = -inre[FRAMESAMPLES_HALF - 1 - k] * tmp1r + inim[FRAMESAMPLES_HALF - 1 - k] * tmp1i; /* Combine into one vector, z = x + j * y */ outre1[k] = xr - yi; outre1[FRAMESAMPLES_HALF - 1 - k] = xr + yi; outre2[k] = xi + yr; outre2[FRAMESAMPLES_HALF - 1 - k] = -xi + yr; } /* Get IDFT */ WebRtcIsac_Fftns(1, &dims, outre1, outre2, 1, FRAMESAMPLES_HALF, fftstr_obj); /* Demodulate and separate */ fact = sqrt(FRAMESAMPLES_HALF); for (k = 0; k < FRAMESAMPLES_HALF; k++) { tmp1r = tables->costab1[k]; tmp1i = tables->sintab1[k]; xr = (outre1[k] * tmp1r - outre2[k] * tmp1i) * fact; outre2[k] = (outre2[k] * tmp1r + outre1[k] * tmp1i) * fact; outre1[k] = xr; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_coding/meson.build0000664000175000017500000000431114475643423024411 0ustar00arunarunisac_vad_sources = [ 'codecs/isac/main/source/filter_functions.c', 'codecs/isac/main/source/isac_vad.c', 'codecs/isac/main/source/pitch_estimator.c', 'codecs/isac/main/source/pitch_filter.c', ] isac_vad_dep = declare_dependency(sources: isac_vad_sources) webrtc_audio_coding_sources = [ 'codecs/isac/main/source/arith_routines.c', 'codecs/isac/main/source/arith_routines_hist.c', 'codecs/isac/main/source/arith_routines_logist.c', 'codecs/isac/main/source/audio_decoder_isac.cc', 'codecs/isac/main/source/audio_encoder_isac.cc', 'codecs/isac/main/source/bandwidth_estimator.c', 'codecs/isac/main/source/crc.c', 'codecs/isac/main/source/decode_bwe.c', 'codecs/isac/main/source/decode.c', 'codecs/isac/main/source/encode.c', 'codecs/isac/main/source/encode_lpc_swb.c', 'codecs/isac/main/source/entropy_coding.c', 'codecs/isac/main/source/filterbanks.c', 'codecs/isac/main/source/intialize.c', 'codecs/isac/main/source/isac.c', 'codecs/isac/main/source/lattice.c', 'codecs/isac/main/source/lpc_analysis.c', 'codecs/isac/main/source/lpc_gain_swb_tables.c', 'codecs/isac/main/source/lpc_shape_swb12_tables.c', 'codecs/isac/main/source/lpc_shape_swb16_tables.c', 'codecs/isac/main/source/lpc_tables.c', 'codecs/isac/main/source/pitch_gain_tables.c', 'codecs/isac/main/source/pitch_lag_tables.c', 'codecs/isac/main/source/spectrum_ar_model_tables.c', 'codecs/isac/main/source/transform.c', ] libwebrtc_audio_coding = library(ac_project_name, webrtc_audio_coding_sources, dependencies: [base_dep, api_dep, common_audio_dep, system_wrappers_dep, fft_dep, isac_vad_dep] + common_deps, include_directories: webrtc_inc, c_args: common_cflags, cpp_args: common_cxxflags, soversion: ac_minor_version, install: true ) install_headers(['codecs/isac/bandwidth_info.h'], subdir: join_paths(include_subdir, 'modules', 'audio_coding', 'codecs', 'isac') ) install_headers(['codecs/isac/main/source/settings.h'], subdir: join_paths(include_subdir, 'modules', 'audio_coding', 'codecs', 'isac', 'main', 'source') ) install_headers(['codecs/isac/main/include/isac.h'], subdir: join_paths(include_subdir, 'modules', 'audio_coding', 'codecs', 'isac', 'main', 'include') ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/0000775000175000017500000000000014475643423023161 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/BUILD.gn0000664000175000017500000003773514475643423024365 0ustar00arunarun# Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../../webrtc.gni") if (rtc_enable_protobuf) { import("//third_party/protobuf/proto_library.gni") } config("apm_debug_dump") { if (apm_debug_dump) { defines = [ "WEBRTC_APM_DEBUG_DUMP=1" ] } else { defines = [ "WEBRTC_APM_DEBUG_DUMP=0" ] } } rtc_library("config") { visibility = [ ":*" ] sources = [ "include/config.cc", "include/config.h", ] deps = [ "../../rtc_base/system:rtc_export" ] } rtc_library("api") { visibility = [ "*" ] sources = [ "include/audio_processing.cc", "include/audio_processing.h", ] deps = [ ":audio_frame_view", ":audio_processing_statistics", ":config", "../../api:array_view", "../../api:scoped_refptr", "../../api/audio:aec3_config", "../../api/audio:audio_frame_api", "../../api/audio:echo_control", "../../rtc_base:deprecation", "../../rtc_base:rtc_base_approved", "../../rtc_base/system:arch", "../../rtc_base/system:file_wrapper", "../../rtc_base/system:rtc_export", "agc:gain_control_interface", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("audio_frame_proxies") { visibility = [ "*" ] sources = [ "include/audio_frame_proxies.cc", "include/audio_frame_proxies.h", ] deps = [ ":api", ":audio_frame_view", "../../api/audio:audio_frame_api", ] } rtc_library("audio_buffer") { visibility = [ "*" ] configs += [ ":apm_debug_dump" ] sources = [ "audio_buffer.cc", "audio_buffer.h", "splitting_filter.cc", "splitting_filter.h", "three_band_filter_bank.cc", "three_band_filter_bank.h", ] defines = [] deps = [ ":api", "../../api:array_view", "../../common_audio", "../../common_audio:common_audio_c", "../../rtc_base:checks", ] } rtc_library("high_pass_filter") { visibility = [ "*" ] sources = [ "high_pass_filter.cc", "high_pass_filter.h", ] defines = [] deps = [ ":audio_buffer", "../../api:array_view", "../../rtc_base:checks", "utility:cascaded_biquad_filter", ] } rtc_source_set("aec_dump_interface") { visibility = [ "*" ] sources = [ "include/aec_dump.cc", "include/aec_dump.h", ] deps = [ ":api", ":audio_frame_view", "../../rtc_base:deprecation", ] } rtc_library("audio_processing") { visibility = [ "*" ] configs += [ ":apm_debug_dump" ] sources = [ "audio_processing_builder_impl.cc", "audio_processing_impl.cc", "audio_processing_impl.h", "common.h", "echo_control_mobile_impl.cc", "echo_control_mobile_impl.h", "echo_detector/circular_buffer.cc", "echo_detector/circular_buffer.h", "echo_detector/mean_variance_estimator.cc", "echo_detector/mean_variance_estimator.h", "echo_detector/moving_max.cc", "echo_detector/moving_max.h", "echo_detector/normalized_covariance_estimator.cc", "echo_detector/normalized_covariance_estimator.h", "gain_control_impl.cc", "gain_control_impl.h", "gain_controller2.cc", "gain_controller2.h", "level_estimator.cc", "level_estimator.h", "render_queue_item_verifier.h", "residual_echo_detector.cc", "residual_echo_detector.h", "typing_detection.cc", "typing_detection.h", ] defines = [] deps = [ ":aec_dump_interface", ":api", ":apm_logging", ":audio_buffer", ":audio_frame_proxies", ":audio_frame_view", ":audio_processing_statistics", ":config", ":high_pass_filter", ":optionally_built_submodule_creators", ":rms_level", ":voice_detection", "../../api:array_view", "../../api:function_view", "../../api/audio:aec3_config", "../../api/audio:audio_frame_api", "../../api/audio:echo_control", "../../audio/utility:audio_frame_operations", "../../common_audio:common_audio_c", "../../common_audio/third_party/ooura:fft_size_256", "../../rtc_base:checks", "../../rtc_base:deprecation", "../../rtc_base:gtest_prod", "../../rtc_base:ignore_wundef", "../../rtc_base:refcount", "../../rtc_base:safe_minmax", "../../rtc_base:sanitizer", "../../rtc_base/synchronization:mutex", "../../rtc_base/system:rtc_export", "../../system_wrappers", "../../system_wrappers:field_trial", "../../system_wrappers:metrics", "aec3", "aec_dump:aec_dump", "aecm:aecm_core", "agc", "agc:gain_control_interface", "agc:legacy_agc", "agc2:adaptive_digital", "agc2:fixed_digital", "agc2:gain_applier", "ns", "transient:transient_suppressor_api", "vad", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] deps += [ "../../common_audio", "../../common_audio:fir_filter", "../../common_audio:fir_filter_factory", "../../rtc_base:rtc_base_approved", "../../system_wrappers", ] if (rtc_enable_protobuf) { deps += [ "aec_dump:aec_dump_impl" ] } else { deps += [ "aec_dump:null_aec_dump_factory" ] } } rtc_library("voice_detection") { sources = [ "voice_detection.cc", "voice_detection.h", ] deps = [ ":api", ":audio_buffer", "../../api/audio:audio_frame_api", "../../common_audio:common_audio_c", "../../rtc_base:checks", ] } rtc_library("optionally_built_submodule_creators") { sources = [ "optionally_built_submodule_creators.cc", "optionally_built_submodule_creators.h", ] deps = [ "transient:transient_suppressor_api", "transient:transient_suppressor_impl", ] } rtc_source_set("rms_level") { visibility = [ "*" ] sources = [ "rms_level.cc", "rms_level.h", ] deps = [ "../../api:array_view", "../../rtc_base:checks", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("audio_processing_statistics") { visibility = [ "*" ] sources = [ "include/audio_processing_statistics.cc", "include/audio_processing_statistics.h", ] deps = [ "../../rtc_base/system:rtc_export" ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_source_set("audio_frame_view") { sources = [ "include/audio_frame_view.h" ] deps = [ "../../api:array_view" ] } if (rtc_enable_protobuf) { proto_library("audioproc_debug_proto") { sources = [ "debug.proto" ] proto_out_dir = "modules/audio_processing" } } rtc_library("apm_logging") { configs += [ ":apm_debug_dump" ] sources = [ "logging/apm_data_dumper.cc", "logging/apm_data_dumper.h", ] deps = [ "../../api:array_view", "../../common_audio", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", ] defines = [] } if (rtc_include_tests) { rtc_source_set("mocks") { testonly = true sources = [ "include/mock_audio_processing.h" ] deps = [ ":aec_dump_interface", ":api", ":audio_buffer", ":audio_processing", ":audio_processing_statistics", "../../test:test_support", ] } group("audio_processing_tests") { testonly = true deps = [ ":audioproc_test_utils", "transient:click_annotate", "transient:transient_suppression_test", ] if (rtc_enable_protobuf) { deps += [ ":audioproc_unittest_proto", "aec_dump:aec_dump_unittests", "test/conversational_speech", "test/py_quality_assessment", ] } } rtc_library("audio_processing_unittests") { testonly = true configs += [ ":apm_debug_dump" ] sources = [ "audio_buffer_unittest.cc", "audio_frame_view_unittest.cc", "config_unittest.cc", "echo_control_mobile_unittest.cc", "gain_controller2_unittest.cc", "splitting_filter_unittest.cc", "test/fake_recording_device_unittest.cc", ] deps = [ ":analog_mic_simulation", ":api", ":apm_logging", ":audio_buffer", ":audio_frame_view", ":audio_processing", ":audioproc_test_utils", ":config", ":high_pass_filter", ":mocks", ":voice_detection", "../../api:array_view", "../../api:scoped_refptr", "../../api/audio:aec3_config", "../../api/audio:aec3_factory", "../../common_audio", "../../common_audio:common_audio_c", "../../rtc_base", "../../rtc_base:checks", "../../rtc_base:gtest_prod", "../../rtc_base:ignore_wundef", "../../rtc_base:protobuf_utils", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_base_tests_utils", "../../rtc_base:safe_minmax", "../../rtc_base:task_queue_for_test", "../../rtc_base/synchronization:mutex", "../../rtc_base/system:arch", "../../rtc_base/system:file_wrapper", "../../system_wrappers", "../../test:fileutils", "../../test:rtc_expect_death", "../../test:test_support", "../audio_coding:neteq_input_audio_tools", "aec_dump:mock_aec_dump_unittests", "agc:agc_unittests", "agc2:adaptive_digital_unittests", "agc2:biquad_filter_unittests", "agc2:fixed_digital_unittests", "agc2:noise_estimator_unittests", "agc2:rnn_vad_with_level_unittests", "agc2:test_utils", "agc2/rnn_vad:unittests", "test/conversational_speech:unittest", "transient:transient_suppression_unittests", "utility:legacy_delay_estimator_unittest", "utility:pffft_wrapper_unittest", "vad:vad_unittests", "//testing/gtest", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] defines = [] if (rtc_prefer_fixed_point) { defines += [ "WEBRTC_AUDIOPROC_FIXED_PROFILE" ] } else { defines += [ "WEBRTC_AUDIOPROC_FLOAT_PROFILE" ] } if (rtc_enable_protobuf) { defines += [ "WEBRTC_AUDIOPROC_DEBUG_DUMP" ] deps += [ ":audioproc_debug_proto", ":audioproc_protobuf_utils", ":audioproc_test_utils", ":audioproc_unittest_proto", ":optionally_built_submodule_creators", ":rms_level", ":runtime_settings_protobuf_utils", "../../api/audio:audio_frame_api", "../../api/audio:echo_control", "../../rtc_base:rtc_base_tests_utils", "../../rtc_base:rtc_task_queue", "aec_dump", "aec_dump:aec_dump_unittests", ] absl_deps += [ "//third_party/abseil-cpp/absl/flags:flag" ] sources += [ "audio_processing_impl_locking_unittest.cc", "audio_processing_impl_unittest.cc", "audio_processing_unittest.cc", "echo_control_mobile_bit_exact_unittest.cc", "echo_detector/circular_buffer_unittest.cc", "echo_detector/mean_variance_estimator_unittest.cc", "echo_detector/moving_max_unittest.cc", "echo_detector/normalized_covariance_estimator_unittest.cc", "gain_control_unittest.cc", "high_pass_filter_unittest.cc", "level_estimator_unittest.cc", "residual_echo_detector_unittest.cc", "rms_level_unittest.cc", "test/debug_dump_replayer.cc", "test/debug_dump_replayer.h", "test/debug_dump_test.cc", "test/echo_canceller_test_tools.cc", "test/echo_canceller_test_tools.h", "test/echo_canceller_test_tools_unittest.cc", "test/echo_control_mock.h", "test/test_utils.h", "voice_detection_unittest.cc", ] } } rtc_library("audio_processing_perf_tests") { testonly = true configs += [ ":apm_debug_dump" ] sources = [ "audio_processing_performance_unittest.cc" ] deps = [ ":audio_processing", ":audioproc_test_utils", "../../api:array_view", "../../rtc_base:protobuf_utils", "../../rtc_base:rtc_base_approved", "../../system_wrappers", "../../test:perf_test", "../../test:test_support", ] } rtc_library("analog_mic_simulation") { sources = [ "test/fake_recording_device.cc", "test/fake_recording_device.h", ] deps = [ "../../api:array_view", "../../api/audio:audio_frame_api", "../../common_audio", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../../rtc_base:safe_minmax", "agc:gain_map", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } if (rtc_enable_protobuf) { rtc_library("audioproc_f_impl") { testonly = true configs += [ ":apm_debug_dump" ] sources = [ "test/aec_dump_based_simulator.cc", "test/aec_dump_based_simulator.h", "test/api_call_statistics.cc", "test/api_call_statistics.h", "test/audio_processing_simulator.cc", "test/audio_processing_simulator.h", "test/audioproc_float_impl.cc", "test/audioproc_float_impl.h", "test/wav_based_simulator.cc", "test/wav_based_simulator.h", ] deps = [ ":analog_mic_simulation", ":api", ":apm_logging", ":audio_processing", ":audioproc_debug_proto", ":audioproc_protobuf_utils", ":audioproc_test_utils", ":runtime_settings_protobuf_utils", "../../api/audio:aec3_config_json", "../../api/audio:aec3_factory", "../../common_audio", "../../rtc_base:checks", "../../rtc_base:ignore_wundef", "../../rtc_base:protobuf_utils", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_json", "../../rtc_base:task_queue_for_test", "../../rtc_base/system:file_wrapper", "../../system_wrappers", "../../system_wrappers:field_trial", "../../test:test_support", "aec_dump", "aec_dump:aec_dump_impl", "//testing/gtest", ] absl_deps = [ "//third_party/abseil-cpp/absl/flags:flag", "//third_party/abseil-cpp/absl/flags:parse", "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] } # audioproc_f_impl } if (rtc_enable_protobuf) { proto_library("audioproc_unittest_proto") { sources = [ "test/unittest.proto" ] proto_out_dir = "modules/audio_processing/test" } rtc_library("audioproc_protobuf_utils") { sources = [ "test/protobuf_utils.cc", "test/protobuf_utils.h", ] deps = [ ":audioproc_debug_proto", "../../rtc_base:checks", "../../rtc_base:ignore_wundef", "../../rtc_base:protobuf_utils", "../../rtc_base:rtc_base_approved", "../../rtc_base/system:arch", ] } rtc_library("runtime_settings_protobuf_utils") { testonly = true sources = [ "test/runtime_setting_util.cc", "test/runtime_setting_util.h", ] deps = [ ":api", ":audioproc_debug_proto", ":audioproc_protobuf_utils", "../../rtc_base:checks", ] } } } rtc_library("audioproc_test_utils") { visibility = [ "*" ] testonly = true sources = [ "test/audio_buffer_tools.cc", "test/audio_buffer_tools.h", "test/audio_processing_builder_for_testing.cc", "test/audio_processing_builder_for_testing.h", "test/bitexactness_tools.cc", "test/bitexactness_tools.h", "test/performance_timer.cc", "test/performance_timer.h", "test/simulator_buffers.cc", "test/simulator_buffers.h", "test/test_utils.cc", "test/test_utils.h", ] configs += [ ":apm_debug_dump" ] deps = [ ":api", ":audio_buffer", ":audio_processing", "../../api:array_view", "../../api/audio:audio_frame_api", "../../common_audio", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../../rtc_base/system:arch", "../../system_wrappers", "../../test:fileutils", "../../test:test_support", "../audio_coding:neteq_input_audio_tools", "//testing/gtest", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/0000775000175000017500000000000014475643423023774 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/BUILD.gn0000664000175000017500000002364514475643423025173 0ustar00arunarun# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../../../webrtc.gni") rtc_library("aec3") { visibility = [ "*" ] configs += [ "..:apm_debug_dump" ] sources = [ "adaptive_fir_filter.cc", "adaptive_fir_filter_erl.cc", "aec3_common.cc", "aec3_fft.cc", "aec_state.cc", "aec_state.h", "alignment_mixer.cc", "alignment_mixer.h", "api_call_jitter_metrics.cc", "api_call_jitter_metrics.h", "block_buffer.cc", "block_delay_buffer.cc", "block_delay_buffer.h", "block_framer.cc", "block_framer.h", "block_processor.cc", "block_processor.h", "block_processor_metrics.cc", "block_processor_metrics.h", "clockdrift_detector.cc", "clockdrift_detector.h", "coarse_filter_update_gain.cc", "coarse_filter_update_gain.h", "comfort_noise_generator.cc", "comfort_noise_generator.h", "decimator.cc", "decimator.h", "delay_estimate.h", "dominant_nearend_detector.cc", "dominant_nearend_detector.h", "downsampled_render_buffer.cc", "downsampled_render_buffer.h", "echo_audibility.cc", "echo_audibility.h", "echo_canceller3.cc", "echo_canceller3.h", "echo_path_delay_estimator.cc", "echo_path_delay_estimator.h", "echo_path_variability.cc", "echo_path_variability.h", "echo_remover.cc", "echo_remover.h", "echo_remover_metrics.cc", "echo_remover_metrics.h", "erl_estimator.cc", "erl_estimator.h", "erle_estimator.cc", "erle_estimator.h", "fft_buffer.cc", "filter_analyzer.cc", "filter_analyzer.h", "frame_blocker.cc", "frame_blocker.h", "fullband_erle_estimator.cc", "fullband_erle_estimator.h", "matched_filter.cc", "matched_filter_lag_aggregator.cc", "matched_filter_lag_aggregator.h", "moving_average.cc", "moving_average.h", "nearend_detector.h", "refined_filter_update_gain.cc", "refined_filter_update_gain.h", "render_buffer.cc", "render_delay_buffer.cc", "render_delay_buffer.h", "render_delay_controller.cc", "render_delay_controller.h", "render_delay_controller_metrics.cc", "render_delay_controller_metrics.h", "render_signal_analyzer.cc", "render_signal_analyzer.h", "residual_echo_estimator.cc", "residual_echo_estimator.h", "reverb_decay_estimator.cc", "reverb_decay_estimator.h", "reverb_frequency_response.cc", "reverb_frequency_response.h", "reverb_model.cc", "reverb_model.h", "reverb_model_estimator.cc", "reverb_model_estimator.h", "signal_dependent_erle_estimator.cc", "signal_dependent_erle_estimator.h", "spectrum_buffer.cc", "stationarity_estimator.cc", "stationarity_estimator.h", "subband_erle_estimator.cc", "subband_erle_estimator.h", "subband_nearend_detector.cc", "subband_nearend_detector.h", "subtractor.cc", "subtractor.h", "subtractor_output.cc", "subtractor_output.h", "subtractor_output_analyzer.cc", "subtractor_output_analyzer.h", "suppression_filter.cc", "suppression_filter.h", "suppression_gain.cc", "suppression_gain.h", "transparent_mode.cc", "transparent_mode.h", ] defines = [] if (rtc_build_with_neon && current_cpu != "arm64") { suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ] cflags = [ "-mfpu=neon" ] } deps = [ ":adaptive_fir_filter", ":adaptive_fir_filter_erl", ":aec3_common", ":aec3_fft", ":fft_data", ":matched_filter", ":render_buffer", ":vector_math", "..:apm_logging", "..:audio_buffer", "..:high_pass_filter", "../../../api:array_view", "../../../api/audio:aec3_config", "../../../api/audio:echo_control", "../../../common_audio:common_audio_c", "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", "../../../rtc_base:safe_minmax", "../../../rtc_base/experiments:field_trial_parser", "../../../rtc_base/system:arch", "../../../system_wrappers", "../../../system_wrappers:field_trial", "../../../system_wrappers:metrics", "../utility:cascaded_biquad_filter", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] if (current_cpu == "x86" || current_cpu == "x64") { deps += [ ":aec3_avx2" ] } } rtc_source_set("aec3_common") { sources = [ "aec3_common.h" ] } rtc_source_set("aec3_fft") { sources = [ "aec3_fft.h" ] deps = [ ":aec3_common", ":fft_data", "../../../api:array_view", "../../../common_audio/third_party/ooura:fft_size_128", "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", "../../../rtc_base/system:arch", ] } rtc_source_set("render_buffer") { sources = [ "block_buffer.h", "fft_buffer.h", "render_buffer.h", "spectrum_buffer.h", ] deps = [ ":aec3_common", ":fft_data", "../../../api:array_view", "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", "../../../rtc_base/system:arch", ] } rtc_source_set("adaptive_fir_filter") { sources = [ "adaptive_fir_filter.h" ] deps = [ ":aec3_common", ":aec3_fft", ":fft_data", ":render_buffer", "..:apm_logging", "../../../api:array_view", "../../../rtc_base/system:arch", ] } rtc_source_set("adaptive_fir_filter_erl") { sources = [ "adaptive_fir_filter_erl.h" ] deps = [ ":aec3_common", "../../../api:array_view", "../../../rtc_base/system:arch", ] } rtc_source_set("matched_filter") { sources = [ "matched_filter.h" ] deps = [ ":aec3_common", "../../../api:array_view", "../../../rtc_base:rtc_base_approved", "../../../rtc_base/system:arch", ] } rtc_source_set("vector_math") { sources = [ "vector_math.h" ] deps = [ ":aec3_common", "../../../api:array_view", "../../../rtc_base:checks", "../../../rtc_base/system:arch", ] } rtc_source_set("fft_data") { sources = [ "fft_data.h" ] deps = [ ":aec3_common", "../../../api:array_view", "../../../rtc_base/system:arch", ] } if (current_cpu == "x86" || current_cpu == "x64") { rtc_library("aec3_avx2") { configs += [ "..:apm_debug_dump" ] sources = [ "adaptive_fir_filter_avx2.cc", "adaptive_fir_filter_erl_avx2.cc", "fft_data_avx2.cc", "matched_filter_avx2.cc", "vector_math_avx2.cc", ] if (is_win) { cflags = [ "/arch:AVX2" ] } else { cflags = [ "-mavx2", "-mfma", ] } deps = [ ":adaptive_fir_filter", ":adaptive_fir_filter_erl", ":fft_data", ":matched_filter", ":vector_math", "../../../api:array_view", "../../../rtc_base:checks", ] } } if (rtc_include_tests) { rtc_library("aec3_unittests") { testonly = true configs += [ "..:apm_debug_dump" ] sources = [ "mock/mock_block_processor.cc", "mock/mock_block_processor.h", "mock/mock_echo_remover.cc", "mock/mock_echo_remover.h", "mock/mock_render_delay_buffer.cc", "mock/mock_render_delay_buffer.h", "mock/mock_render_delay_controller.cc", "mock/mock_render_delay_controller.h", ] deps = [ ":adaptive_fir_filter", ":adaptive_fir_filter_erl", ":aec3", ":aec3_common", ":aec3_fft", ":fft_data", ":matched_filter", ":render_buffer", ":vector_math", "..:apm_logging", "..:audio_buffer", "..:audio_processing", "..:audio_processing_unittests", "..:high_pass_filter", "../../../api:array_view", "../../../api/audio:aec3_config", "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", "../../../rtc_base:safe_minmax", "../../../rtc_base/system:arch", "../../../system_wrappers", "../../../test:field_trial", "../../../test:test_support", "../utility:cascaded_biquad_filter", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] defines = [] if (rtc_enable_protobuf) { sources += [ "adaptive_fir_filter_erl_unittest.cc", "adaptive_fir_filter_unittest.cc", "aec3_fft_unittest.cc", "aec_state_unittest.cc", "alignment_mixer_unittest.cc", "api_call_jitter_metrics_unittest.cc", "block_delay_buffer_unittest.cc", "block_framer_unittest.cc", "block_processor_metrics_unittest.cc", "block_processor_unittest.cc", "clockdrift_detector_unittest.cc", "coarse_filter_update_gain_unittest.cc", "comfort_noise_generator_unittest.cc", "decimator_unittest.cc", "echo_canceller3_unittest.cc", "echo_path_delay_estimator_unittest.cc", "echo_path_variability_unittest.cc", "echo_remover_metrics_unittest.cc", "echo_remover_unittest.cc", "erl_estimator_unittest.cc", "erle_estimator_unittest.cc", "fft_data_unittest.cc", "filter_analyzer_unittest.cc", "frame_blocker_unittest.cc", "matched_filter_lag_aggregator_unittest.cc", "matched_filter_unittest.cc", "moving_average_unittest.cc", "refined_filter_update_gain_unittest.cc", "render_buffer_unittest.cc", "render_delay_buffer_unittest.cc", "render_delay_controller_metrics_unittest.cc", "render_delay_controller_unittest.cc", "render_signal_analyzer_unittest.cc", "residual_echo_estimator_unittest.cc", "reverb_model_estimator_unittest.cc", "signal_dependent_erle_estimator_unittest.cc", "subtractor_unittest.cc", "suppression_filter_unittest.cc", "suppression_gain_unittest.cc", "vector_math_unittest.cc", ] } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/adaptive_fir_filter.cc0000664000175000017500000006506314475643423030317 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/adaptive_fir_filter.h" // Defines WEBRTC_ARCH_X86_FAMILY, used below. #include "rtc_base/system/arch.h" #if defined(WEBRTC_HAS_NEON) #include #endif #if defined(WEBRTC_ARCH_X86_FAMILY) #include #endif #include #include #include #include "modules/audio_processing/aec3/fft_data.h" #include "rtc_base/checks.h" namespace webrtc { namespace aec3 { // Computes and stores the frequency response of the filter. void ComputeFrequencyResponse( size_t num_partitions, const std::vector>& H, std::vector>* H2) { for (auto& H2_ch : *H2) { H2_ch.fill(0.f); } const size_t num_render_channels = H[0].size(); RTC_DCHECK_EQ(H.size(), H2->capacity()); for (size_t p = 0; p < num_partitions; ++p) { RTC_DCHECK_EQ(kFftLengthBy2Plus1, (*H2)[p].size()); for (size_t ch = 0; ch < num_render_channels; ++ch) { for (size_t j = 0; j < kFftLengthBy2Plus1; ++j) { float tmp = H[p][ch].re[j] * H[p][ch].re[j] + H[p][ch].im[j] * H[p][ch].im[j]; (*H2)[p][j] = std::max((*H2)[p][j], tmp); } } } } #if defined(WEBRTC_HAS_NEON) // Computes and stores the frequency response of the filter. void ComputeFrequencyResponse_Neon( size_t num_partitions, const std::vector>& H, std::vector>* H2) { for (auto& H2_ch : *H2) { H2_ch.fill(0.f); } const size_t num_render_channels = H[0].size(); RTC_DCHECK_EQ(H.size(), H2->capacity()); for (size_t p = 0; p < num_partitions; ++p) { RTC_DCHECK_EQ(kFftLengthBy2Plus1, (*H2)[p].size()); for (size_t ch = 0; ch < num_render_channels; ++ch) { for (size_t j = 0; j < kFftLengthBy2; j += 4) { const float32x4_t re = vld1q_f32(&H[p][ch].re[j]); const float32x4_t im = vld1q_f32(&H[p][ch].im[j]); float32x4_t H2_new = vmulq_f32(re, re); H2_new = vmlaq_f32(H2_new, im, im); float32x4_t H2_p_j = vld1q_f32(&(*H2)[p][j]); H2_p_j = vmaxq_f32(H2_p_j, H2_new); vst1q_f32(&(*H2)[p][j], H2_p_j); } float H2_new = H[p][ch].re[kFftLengthBy2] * H[p][ch].re[kFftLengthBy2] + H[p][ch].im[kFftLengthBy2] * H[p][ch].im[kFftLengthBy2]; (*H2)[p][kFftLengthBy2] = std::max((*H2)[p][kFftLengthBy2], H2_new); } } } #endif #if defined(WEBRTC_ARCH_X86_FAMILY) // Computes and stores the frequency response of the filter. void ComputeFrequencyResponse_Sse2( size_t num_partitions, const std::vector>& H, std::vector>* H2) { for (auto& H2_ch : *H2) { H2_ch.fill(0.f); } const size_t num_render_channels = H[0].size(); RTC_DCHECK_EQ(H.size(), H2->capacity()); // constexpr __mmmask8 kMaxMask = static_cast<__mmmask8>(256u); for (size_t p = 0; p < num_partitions; ++p) { RTC_DCHECK_EQ(kFftLengthBy2Plus1, (*H2)[p].size()); for (size_t ch = 0; ch < num_render_channels; ++ch) { for (size_t j = 0; j < kFftLengthBy2; j += 4) { const __m128 re = _mm_loadu_ps(&H[p][ch].re[j]); const __m128 re2 = _mm_mul_ps(re, re); const __m128 im = _mm_loadu_ps(&H[p][ch].im[j]); const __m128 im2 = _mm_mul_ps(im, im); const __m128 H2_new = _mm_add_ps(re2, im2); __m128 H2_k_j = _mm_loadu_ps(&(*H2)[p][j]); H2_k_j = _mm_max_ps(H2_k_j, H2_new); _mm_storeu_ps(&(*H2)[p][j], H2_k_j); } float H2_new = H[p][ch].re[kFftLengthBy2] * H[p][ch].re[kFftLengthBy2] + H[p][ch].im[kFftLengthBy2] * H[p][ch].im[kFftLengthBy2]; (*H2)[p][kFftLengthBy2] = std::max((*H2)[p][kFftLengthBy2], H2_new); } } } #endif // Adapts the filter partitions as H(t+1)=H(t)+G(t)*conj(X(t)). void AdaptPartitions(const RenderBuffer& render_buffer, const FftData& G, size_t num_partitions, std::vector>* H) { rtc::ArrayView> render_buffer_data = render_buffer.GetFftBuffer(); size_t index = render_buffer.Position(); const size_t num_render_channels = render_buffer_data[index].size(); for (size_t p = 0; p < num_partitions; ++p) { for (size_t ch = 0; ch < num_render_channels; ++ch) { const FftData& X_p_ch = render_buffer_data[index][ch]; FftData& H_p_ch = (*H)[p][ch]; for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { H_p_ch.re[k] += X_p_ch.re[k] * G.re[k] + X_p_ch.im[k] * G.im[k]; H_p_ch.im[k] += X_p_ch.re[k] * G.im[k] - X_p_ch.im[k] * G.re[k]; } } index = index < (render_buffer_data.size() - 1) ? index + 1 : 0; } } #if defined(WEBRTC_HAS_NEON) // Adapts the filter partitions. (Neon variant) void AdaptPartitions_Neon(const RenderBuffer& render_buffer, const FftData& G, size_t num_partitions, std::vector>* H) { rtc::ArrayView> render_buffer_data = render_buffer.GetFftBuffer(); const size_t num_render_channels = render_buffer_data[0].size(); const size_t lim1 = std::min( render_buffer_data.size() - render_buffer.Position(), num_partitions); const size_t lim2 = num_partitions; constexpr size_t kNumFourBinBands = kFftLengthBy2 / 4; size_t X_partition = render_buffer.Position(); size_t limit = lim1; size_t p = 0; do { for (; p < limit; ++p, ++X_partition) { for (size_t ch = 0; ch < num_render_channels; ++ch) { FftData& H_p_ch = (*H)[p][ch]; const FftData& X = render_buffer_data[X_partition][ch]; for (size_t k = 0, n = 0; n < kNumFourBinBands; ++n, k += 4) { const float32x4_t G_re = vld1q_f32(&G.re[k]); const float32x4_t G_im = vld1q_f32(&G.im[k]); const float32x4_t X_re = vld1q_f32(&X.re[k]); const float32x4_t X_im = vld1q_f32(&X.im[k]); const float32x4_t H_re = vld1q_f32(&H_p_ch.re[k]); const float32x4_t H_im = vld1q_f32(&H_p_ch.im[k]); const float32x4_t a = vmulq_f32(X_re, G_re); const float32x4_t e = vmlaq_f32(a, X_im, G_im); const float32x4_t c = vmulq_f32(X_re, G_im); const float32x4_t f = vmlsq_f32(c, X_im, G_re); const float32x4_t g = vaddq_f32(H_re, e); const float32x4_t h = vaddq_f32(H_im, f); vst1q_f32(&H_p_ch.re[k], g); vst1q_f32(&H_p_ch.im[k], h); } } } X_partition = 0; limit = lim2; } while (p < lim2); X_partition = render_buffer.Position(); limit = lim1; p = 0; do { for (; p < limit; ++p, ++X_partition) { for (size_t ch = 0; ch < num_render_channels; ++ch) { FftData& H_p_ch = (*H)[p][ch]; const FftData& X = render_buffer_data[X_partition][ch]; H_p_ch.re[kFftLengthBy2] += X.re[kFftLengthBy2] * G.re[kFftLengthBy2] + X.im[kFftLengthBy2] * G.im[kFftLengthBy2]; H_p_ch.im[kFftLengthBy2] += X.re[kFftLengthBy2] * G.im[kFftLengthBy2] - X.im[kFftLengthBy2] * G.re[kFftLengthBy2]; } } X_partition = 0; limit = lim2; } while (p < lim2); } #endif #if defined(WEBRTC_ARCH_X86_FAMILY) // Adapts the filter partitions. (SSE2 variant) void AdaptPartitions_Sse2(const RenderBuffer& render_buffer, const FftData& G, size_t num_partitions, std::vector>* H) { rtc::ArrayView> render_buffer_data = render_buffer.GetFftBuffer(); const size_t num_render_channels = render_buffer_data[0].size(); const size_t lim1 = std::min( render_buffer_data.size() - render_buffer.Position(), num_partitions); const size_t lim2 = num_partitions; constexpr size_t kNumFourBinBands = kFftLengthBy2 / 4; size_t X_partition = render_buffer.Position(); size_t limit = lim1; size_t p = 0; do { for (; p < limit; ++p, ++X_partition) { for (size_t ch = 0; ch < num_render_channels; ++ch) { FftData& H_p_ch = (*H)[p][ch]; const FftData& X = render_buffer_data[X_partition][ch]; for (size_t k = 0, n = 0; n < kNumFourBinBands; ++n, k += 4) { const __m128 G_re = _mm_loadu_ps(&G.re[k]); const __m128 G_im = _mm_loadu_ps(&G.im[k]); const __m128 X_re = _mm_loadu_ps(&X.re[k]); const __m128 X_im = _mm_loadu_ps(&X.im[k]); const __m128 H_re = _mm_loadu_ps(&H_p_ch.re[k]); const __m128 H_im = _mm_loadu_ps(&H_p_ch.im[k]); const __m128 a = _mm_mul_ps(X_re, G_re); const __m128 b = _mm_mul_ps(X_im, G_im); const __m128 c = _mm_mul_ps(X_re, G_im); const __m128 d = _mm_mul_ps(X_im, G_re); const __m128 e = _mm_add_ps(a, b); const __m128 f = _mm_sub_ps(c, d); const __m128 g = _mm_add_ps(H_re, e); const __m128 h = _mm_add_ps(H_im, f); _mm_storeu_ps(&H_p_ch.re[k], g); _mm_storeu_ps(&H_p_ch.im[k], h); } } } X_partition = 0; limit = lim2; } while (p < lim2); X_partition = render_buffer.Position(); limit = lim1; p = 0; do { for (; p < limit; ++p, ++X_partition) { for (size_t ch = 0; ch < num_render_channels; ++ch) { FftData& H_p_ch = (*H)[p][ch]; const FftData& X = render_buffer_data[X_partition][ch]; H_p_ch.re[kFftLengthBy2] += X.re[kFftLengthBy2] * G.re[kFftLengthBy2] + X.im[kFftLengthBy2] * G.im[kFftLengthBy2]; H_p_ch.im[kFftLengthBy2] += X.re[kFftLengthBy2] * G.im[kFftLengthBy2] - X.im[kFftLengthBy2] * G.re[kFftLengthBy2]; } } X_partition = 0; limit = lim2; } while (p < lim2); } #endif // Produces the filter output. void ApplyFilter(const RenderBuffer& render_buffer, size_t num_partitions, const std::vector>& H, FftData* S) { S->re.fill(0.f); S->im.fill(0.f); rtc::ArrayView> render_buffer_data = render_buffer.GetFftBuffer(); size_t index = render_buffer.Position(); const size_t num_render_channels = render_buffer_data[index].size(); for (size_t p = 0; p < num_partitions; ++p) { RTC_DCHECK_EQ(num_render_channels, H[p].size()); for (size_t ch = 0; ch < num_render_channels; ++ch) { const FftData& X_p_ch = render_buffer_data[index][ch]; const FftData& H_p_ch = H[p][ch]; for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { S->re[k] += X_p_ch.re[k] * H_p_ch.re[k] - X_p_ch.im[k] * H_p_ch.im[k]; S->im[k] += X_p_ch.re[k] * H_p_ch.im[k] + X_p_ch.im[k] * H_p_ch.re[k]; } } index = index < (render_buffer_data.size() - 1) ? index + 1 : 0; } } #if defined(WEBRTC_HAS_NEON) // Produces the filter output (Neon variant). void ApplyFilter_Neon(const RenderBuffer& render_buffer, size_t num_partitions, const std::vector>& H, FftData* S) { // const RenderBuffer& render_buffer, // rtc::ArrayView H, // FftData* S) { RTC_DCHECK_GE(H.size(), H.size() - 1); S->Clear(); rtc::ArrayView> render_buffer_data = render_buffer.GetFftBuffer(); const size_t num_render_channels = render_buffer_data[0].size(); const size_t lim1 = std::min( render_buffer_data.size() - render_buffer.Position(), num_partitions); const size_t lim2 = num_partitions; constexpr size_t kNumFourBinBands = kFftLengthBy2 / 4; size_t X_partition = render_buffer.Position(); size_t p = 0; size_t limit = lim1; do { for (; p < limit; ++p, ++X_partition) { for (size_t ch = 0; ch < num_render_channels; ++ch) { const FftData& H_p_ch = H[p][ch]; const FftData& X = render_buffer_data[X_partition][ch]; for (size_t k = 0, n = 0; n < kNumFourBinBands; ++n, k += 4) { const float32x4_t X_re = vld1q_f32(&X.re[k]); const float32x4_t X_im = vld1q_f32(&X.im[k]); const float32x4_t H_re = vld1q_f32(&H_p_ch.re[k]); const float32x4_t H_im = vld1q_f32(&H_p_ch.im[k]); const float32x4_t S_re = vld1q_f32(&S->re[k]); const float32x4_t S_im = vld1q_f32(&S->im[k]); const float32x4_t a = vmulq_f32(X_re, H_re); const float32x4_t e = vmlsq_f32(a, X_im, H_im); const float32x4_t c = vmulq_f32(X_re, H_im); const float32x4_t f = vmlaq_f32(c, X_im, H_re); const float32x4_t g = vaddq_f32(S_re, e); const float32x4_t h = vaddq_f32(S_im, f); vst1q_f32(&S->re[k], g); vst1q_f32(&S->im[k], h); } } } limit = lim2; X_partition = 0; } while (p < lim2); X_partition = render_buffer.Position(); p = 0; limit = lim1; do { for (; p < limit; ++p, ++X_partition) { for (size_t ch = 0; ch < num_render_channels; ++ch) { const FftData& H_p_ch = H[p][ch]; const FftData& X = render_buffer_data[X_partition][ch]; S->re[kFftLengthBy2] += X.re[kFftLengthBy2] * H_p_ch.re[kFftLengthBy2] - X.im[kFftLengthBy2] * H_p_ch.im[kFftLengthBy2]; S->im[kFftLengthBy2] += X.re[kFftLengthBy2] * H_p_ch.im[kFftLengthBy2] + X.im[kFftLengthBy2] * H_p_ch.re[kFftLengthBy2]; } } limit = lim2; X_partition = 0; } while (p < lim2); } #endif #if defined(WEBRTC_ARCH_X86_FAMILY) // Produces the filter output (SSE2 variant). void ApplyFilter_Sse2(const RenderBuffer& render_buffer, size_t num_partitions, const std::vector>& H, FftData* S) { // const RenderBuffer& render_buffer, // rtc::ArrayView H, // FftData* S) { RTC_DCHECK_GE(H.size(), H.size() - 1); S->re.fill(0.f); S->im.fill(0.f); rtc::ArrayView> render_buffer_data = render_buffer.GetFftBuffer(); const size_t num_render_channels = render_buffer_data[0].size(); const size_t lim1 = std::min( render_buffer_data.size() - render_buffer.Position(), num_partitions); const size_t lim2 = num_partitions; constexpr size_t kNumFourBinBands = kFftLengthBy2 / 4; size_t X_partition = render_buffer.Position(); size_t p = 0; size_t limit = lim1; do { for (; p < limit; ++p, ++X_partition) { for (size_t ch = 0; ch < num_render_channels; ++ch) { const FftData& H_p_ch = H[p][ch]; const FftData& X = render_buffer_data[X_partition][ch]; for (size_t k = 0, n = 0; n < kNumFourBinBands; ++n, k += 4) { const __m128 X_re = _mm_loadu_ps(&X.re[k]); const __m128 X_im = _mm_loadu_ps(&X.im[k]); const __m128 H_re = _mm_loadu_ps(&H_p_ch.re[k]); const __m128 H_im = _mm_loadu_ps(&H_p_ch.im[k]); const __m128 S_re = _mm_loadu_ps(&S->re[k]); const __m128 S_im = _mm_loadu_ps(&S->im[k]); const __m128 a = _mm_mul_ps(X_re, H_re); const __m128 b = _mm_mul_ps(X_im, H_im); const __m128 c = _mm_mul_ps(X_re, H_im); const __m128 d = _mm_mul_ps(X_im, H_re); const __m128 e = _mm_sub_ps(a, b); const __m128 f = _mm_add_ps(c, d); const __m128 g = _mm_add_ps(S_re, e); const __m128 h = _mm_add_ps(S_im, f); _mm_storeu_ps(&S->re[k], g); _mm_storeu_ps(&S->im[k], h); } } } limit = lim2; X_partition = 0; } while (p < lim2); X_partition = render_buffer.Position(); p = 0; limit = lim1; do { for (; p < limit; ++p, ++X_partition) { for (size_t ch = 0; ch < num_render_channels; ++ch) { const FftData& H_p_ch = H[p][ch]; const FftData& X = render_buffer_data[X_partition][ch]; S->re[kFftLengthBy2] += X.re[kFftLengthBy2] * H_p_ch.re[kFftLengthBy2] - X.im[kFftLengthBy2] * H_p_ch.im[kFftLengthBy2]; S->im[kFftLengthBy2] += X.re[kFftLengthBy2] * H_p_ch.im[kFftLengthBy2] + X.im[kFftLengthBy2] * H_p_ch.re[kFftLengthBy2]; } } limit = lim2; X_partition = 0; } while (p < lim2); } #endif } // namespace aec3 namespace { // Ensures that the newly added filter partitions after a size increase are set // to zero. void ZeroFilter(size_t old_size, size_t new_size, std::vector>* H) { RTC_DCHECK_GE(H->size(), old_size); RTC_DCHECK_GE(H->size(), new_size); for (size_t p = old_size; p < new_size; ++p) { RTC_DCHECK_EQ((*H)[p].size(), (*H)[0].size()); for (size_t ch = 0; ch < (*H)[0].size(); ++ch) { (*H)[p][ch].Clear(); } } } } // namespace AdaptiveFirFilter::AdaptiveFirFilter(size_t max_size_partitions, size_t initial_size_partitions, size_t size_change_duration_blocks, size_t num_render_channels, Aec3Optimization optimization, ApmDataDumper* data_dumper) : data_dumper_(data_dumper), fft_(), optimization_(optimization), num_render_channels_(num_render_channels), max_size_partitions_(max_size_partitions), size_change_duration_blocks_( static_cast(size_change_duration_blocks)), current_size_partitions_(initial_size_partitions), target_size_partitions_(initial_size_partitions), old_target_size_partitions_(initial_size_partitions), H_(max_size_partitions_, std::vector(num_render_channels_)) { RTC_DCHECK(data_dumper_); RTC_DCHECK_GE(max_size_partitions, initial_size_partitions); RTC_DCHECK_LT(0, size_change_duration_blocks_); one_by_size_change_duration_blocks_ = 1.f / size_change_duration_blocks_; ZeroFilter(0, max_size_partitions_, &H_); SetSizePartitions(current_size_partitions_, true); } AdaptiveFirFilter::~AdaptiveFirFilter() = default; void AdaptiveFirFilter::HandleEchoPathChange() { // TODO(peah): Check the value and purpose of the code below. ZeroFilter(current_size_partitions_, max_size_partitions_, &H_); } void AdaptiveFirFilter::SetSizePartitions(size_t size, bool immediate_effect) { RTC_DCHECK_EQ(max_size_partitions_, H_.capacity()); RTC_DCHECK_LE(size, max_size_partitions_); target_size_partitions_ = std::min(max_size_partitions_, size); if (immediate_effect) { size_t old_size_partitions_ = current_size_partitions_; current_size_partitions_ = old_target_size_partitions_ = target_size_partitions_; ZeroFilter(old_size_partitions_, current_size_partitions_, &H_); partition_to_constrain_ = std::min(partition_to_constrain_, current_size_partitions_ - 1); size_change_counter_ = 0; } else { size_change_counter_ = size_change_duration_blocks_; } } void AdaptiveFirFilter::UpdateSize() { RTC_DCHECK_GE(size_change_duration_blocks_, size_change_counter_); size_t old_size_partitions_ = current_size_partitions_; if (size_change_counter_ > 0) { --size_change_counter_; auto average = [](float from, float to, float from_weight) { return from * from_weight + to * (1.f - from_weight); }; float change_factor = size_change_counter_ * one_by_size_change_duration_blocks_; current_size_partitions_ = average(old_target_size_partitions_, target_size_partitions_, change_factor); partition_to_constrain_ = std::min(partition_to_constrain_, current_size_partitions_ - 1); } else { current_size_partitions_ = old_target_size_partitions_ = target_size_partitions_; } ZeroFilter(old_size_partitions_, current_size_partitions_, &H_); RTC_DCHECK_LE(0, size_change_counter_); } void AdaptiveFirFilter::Filter(const RenderBuffer& render_buffer, FftData* S) const { RTC_DCHECK(S); switch (optimization_) { #if defined(WEBRTC_ARCH_X86_FAMILY) case Aec3Optimization::kSse2: aec3::ApplyFilter_Sse2(render_buffer, current_size_partitions_, H_, S); break; case Aec3Optimization::kAvx2: aec3::ApplyFilter_Avx2(render_buffer, current_size_partitions_, H_, S); break; #endif #if defined(WEBRTC_HAS_NEON) case Aec3Optimization::kNeon: aec3::ApplyFilter_Neon(render_buffer, current_size_partitions_, H_, S); break; #endif default: aec3::ApplyFilter(render_buffer, current_size_partitions_, H_, S); } } void AdaptiveFirFilter::Adapt(const RenderBuffer& render_buffer, const FftData& G) { // Adapt the filter and update the filter size. AdaptAndUpdateSize(render_buffer, G); // Constrain the filter partitions in a cyclic manner. Constrain(); } void AdaptiveFirFilter::Adapt(const RenderBuffer& render_buffer, const FftData& G, std::vector* impulse_response) { // Adapt the filter and update the filter size. AdaptAndUpdateSize(render_buffer, G); // Constrain the filter partitions in a cyclic manner. ConstrainAndUpdateImpulseResponse(impulse_response); } void AdaptiveFirFilter::ComputeFrequencyResponse( std::vector>* H2) const { RTC_DCHECK_GE(max_size_partitions_, H2->capacity()); H2->resize(current_size_partitions_); switch (optimization_) { #if defined(WEBRTC_ARCH_X86_FAMILY) case Aec3Optimization::kSse2: aec3::ComputeFrequencyResponse_Sse2(current_size_partitions_, H_, H2); break; case Aec3Optimization::kAvx2: aec3::ComputeFrequencyResponse_Avx2(current_size_partitions_, H_, H2); break; #endif #if defined(WEBRTC_HAS_NEON) case Aec3Optimization::kNeon: aec3::ComputeFrequencyResponse_Neon(current_size_partitions_, H_, H2); break; #endif default: aec3::ComputeFrequencyResponse(current_size_partitions_, H_, H2); } } void AdaptiveFirFilter::AdaptAndUpdateSize(const RenderBuffer& render_buffer, const FftData& G) { // Update the filter size if needed. UpdateSize(); // Adapt the filter. switch (optimization_) { #if defined(WEBRTC_ARCH_X86_FAMILY) case Aec3Optimization::kSse2: aec3::AdaptPartitions_Sse2(render_buffer, G, current_size_partitions_, &H_); break; case Aec3Optimization::kAvx2: aec3::AdaptPartitions_Avx2(render_buffer, G, current_size_partitions_, &H_); break; #endif #if defined(WEBRTC_HAS_NEON) case Aec3Optimization::kNeon: aec3::AdaptPartitions_Neon(render_buffer, G, current_size_partitions_, &H_); break; #endif default: aec3::AdaptPartitions(render_buffer, G, current_size_partitions_, &H_); } } // Constrains the partition of the frequency domain filter to be limited in // time via setting the relevant time-domain coefficients to zero and updates // the corresponding values in an externally stored impulse response estimate. void AdaptiveFirFilter::ConstrainAndUpdateImpulseResponse( std::vector* impulse_response) { RTC_DCHECK_EQ(GetTimeDomainLength(max_size_partitions_), impulse_response->capacity()); impulse_response->resize(GetTimeDomainLength(current_size_partitions_)); std::array h; impulse_response->resize(GetTimeDomainLength(current_size_partitions_)); std::fill( impulse_response->begin() + partition_to_constrain_ * kFftLengthBy2, impulse_response->begin() + (partition_to_constrain_ + 1) * kFftLengthBy2, 0.f); for (size_t ch = 0; ch < num_render_channels_; ++ch) { fft_.Ifft(H_[partition_to_constrain_][ch], &h); static constexpr float kScale = 1.0f / kFftLengthBy2; std::for_each(h.begin(), h.begin() + kFftLengthBy2, [](float& a) { a *= kScale; }); std::fill(h.begin() + kFftLengthBy2, h.end(), 0.f); if (ch == 0) { std::copy( h.begin(), h.begin() + kFftLengthBy2, impulse_response->begin() + partition_to_constrain_ * kFftLengthBy2); } else { for (size_t k = 0, j = partition_to_constrain_ * kFftLengthBy2; k < kFftLengthBy2; ++k, ++j) { if (fabsf((*impulse_response)[j]) < fabsf(h[k])) { (*impulse_response)[j] = h[k]; } } } fft_.Fft(&h, &H_[partition_to_constrain_][ch]); } partition_to_constrain_ = partition_to_constrain_ < (current_size_partitions_ - 1) ? partition_to_constrain_ + 1 : 0; } // Constrains the a partiton of the frequency domain filter to be limited in // time via setting the relevant time-domain coefficients to zero. void AdaptiveFirFilter::Constrain() { std::array h; for (size_t ch = 0; ch < num_render_channels_; ++ch) { fft_.Ifft(H_[partition_to_constrain_][ch], &h); static constexpr float kScale = 1.0f / kFftLengthBy2; std::for_each(h.begin(), h.begin() + kFftLengthBy2, [](float& a) { a *= kScale; }); std::fill(h.begin() + kFftLengthBy2, h.end(), 0.f); fft_.Fft(&h, &H_[partition_to_constrain_][ch]); } partition_to_constrain_ = partition_to_constrain_ < (current_size_partitions_ - 1) ? partition_to_constrain_ + 1 : 0; } void AdaptiveFirFilter::ScaleFilter(float factor) { for (auto& H_p : H_) { for (auto& H_p_ch : H_p) { for (auto& re : H_p_ch.re) { re *= factor; } for (auto& im : H_p_ch.im) { im *= factor; } } } } // Set the filter coefficients. void AdaptiveFirFilter::SetFilter(size_t num_partitions, const std::vector>& H) { const size_t min_num_partitions = std::min(current_size_partitions_, num_partitions); for (size_t p = 0; p < min_num_partitions; ++p) { RTC_DCHECK_EQ(H_[p].size(), H[p].size()); RTC_DCHECK_EQ(num_render_channels_, H_[p].size()); for (size_t ch = 0; ch < num_render_channels_; ++ch) { std::copy(H[p][ch].re.begin(), H[p][ch].re.end(), H_[p][ch].re.begin()); std::copy(H[p][ch].im.begin(), H[p][ch].im.end(), H_[p][ch].im.begin()); } } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/adaptive_fir_filter.h0000664000175000017500000001552514475643423030157 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_ADAPTIVE_FIR_FILTER_H_ #define MODULES_AUDIO_PROCESSING_AEC3_ADAPTIVE_FIR_FILTER_H_ #include #include #include #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/aec3_fft.h" #include "modules/audio_processing/aec3/fft_data.h" #include "modules/audio_processing/aec3/render_buffer.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/system/arch.h" namespace webrtc { namespace aec3 { // Computes and stores the frequency response of the filter. void ComputeFrequencyResponse( size_t num_partitions, const std::vector>& H, std::vector>* H2); #if defined(WEBRTC_HAS_NEON) void ComputeFrequencyResponse_Neon( size_t num_partitions, const std::vector>& H, std::vector>* H2); #endif #if defined(WEBRTC_ARCH_X86_FAMILY) void ComputeFrequencyResponse_Sse2( size_t num_partitions, const std::vector>& H, std::vector>* H2); void ComputeFrequencyResponse_Avx2( size_t num_partitions, const std::vector>& H, std::vector>* H2); #endif // Adapts the filter partitions. void AdaptPartitions(const RenderBuffer& render_buffer, const FftData& G, size_t num_partitions, std::vector>* H); #if defined(WEBRTC_HAS_NEON) void AdaptPartitions_Neon(const RenderBuffer& render_buffer, const FftData& G, size_t num_partitions, std::vector>* H); #endif #if defined(WEBRTC_ARCH_X86_FAMILY) void AdaptPartitions_Sse2(const RenderBuffer& render_buffer, const FftData& G, size_t num_partitions, std::vector>* H); void AdaptPartitions_Avx2(const RenderBuffer& render_buffer, const FftData& G, size_t num_partitions, std::vector>* H); #endif // Produces the filter output. void ApplyFilter(const RenderBuffer& render_buffer, size_t num_partitions, const std::vector>& H, FftData* S); #if defined(WEBRTC_HAS_NEON) void ApplyFilter_Neon(const RenderBuffer& render_buffer, size_t num_partitions, const std::vector>& H, FftData* S); #endif #if defined(WEBRTC_ARCH_X86_FAMILY) void ApplyFilter_Sse2(const RenderBuffer& render_buffer, size_t num_partitions, const std::vector>& H, FftData* S); void ApplyFilter_Avx2(const RenderBuffer& render_buffer, size_t num_partitions, const std::vector>& H, FftData* S); #endif } // namespace aec3 // Provides a frequency domain adaptive filter functionality. class AdaptiveFirFilter { public: AdaptiveFirFilter(size_t max_size_partitions, size_t initial_size_partitions, size_t size_change_duration_blocks, size_t num_render_channels, Aec3Optimization optimization, ApmDataDumper* data_dumper); ~AdaptiveFirFilter(); AdaptiveFirFilter(const AdaptiveFirFilter&) = delete; AdaptiveFirFilter& operator=(const AdaptiveFirFilter&) = delete; // Produces the output of the filter. void Filter(const RenderBuffer& render_buffer, FftData* S) const; // Adapts the filter and updates an externally stored impulse response // estimate. void Adapt(const RenderBuffer& render_buffer, const FftData& G, std::vector* impulse_response); // Adapts the filter. void Adapt(const RenderBuffer& render_buffer, const FftData& G); // Receives reports that known echo path changes have occured and adjusts // the filter adaptation accordingly. void HandleEchoPathChange(); // Returns the filter size. size_t SizePartitions() const { return current_size_partitions_; } // Sets the filter size. void SetSizePartitions(size_t size, bool immediate_effect); // Computes the frequency responses for the filter partitions. void ComputeFrequencyResponse( std::vector>* H2) const; // Returns the maximum number of partitions for the filter. size_t max_filter_size_partitions() const { return max_size_partitions_; } void DumpFilter(const char* name_frequency_domain) { for (size_t p = 0; p < max_size_partitions_; ++p) { data_dumper_->DumpRaw(name_frequency_domain, H_[p][0].re); data_dumper_->DumpRaw(name_frequency_domain, H_[p][0].im); } } // Scale the filter impulse response and spectrum by a factor. void ScaleFilter(float factor); // Set the filter coefficients. void SetFilter(size_t num_partitions, const std::vector>& H); // Gets the filter coefficients. const std::vector>& GetFilter() const { return H_; } private: // Adapts the filter and updates the filter size. void AdaptAndUpdateSize(const RenderBuffer& render_buffer, const FftData& G); // Constrain the filter partitions in a cyclic manner. void Constrain(); // Constrains the filter in a cyclic manner and updates the corresponding // values in the supplied impulse response. void ConstrainAndUpdateImpulseResponse(std::vector* impulse_response); // Gradually Updates the current filter size towards the target size. void UpdateSize(); ApmDataDumper* const data_dumper_; const Aec3Fft fft_; const Aec3Optimization optimization_; const size_t num_render_channels_; const size_t max_size_partitions_; const int size_change_duration_blocks_; float one_by_size_change_duration_blocks_; size_t current_size_partitions_; size_t target_size_partitions_; size_t old_target_size_partitions_; int size_change_counter_ = 0; std::vector> H_; size_t partition_to_constrain_ = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_ADAPTIVE_FIR_FILTER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_avx2.cc0000664000175000017500000001574214475643423031256 0ustar00arunarun/* * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/adaptive_fir_filter.h" #include #include "rtc_base/checks.h" namespace webrtc { namespace aec3 { // Computes and stores the frequency response of the filter. void ComputeFrequencyResponse_Avx2( size_t num_partitions, const std::vector>& H, std::vector>* H2) { for (auto& H2_ch : *H2) { H2_ch.fill(0.f); } const size_t num_render_channels = H[0].size(); RTC_DCHECK_EQ(H.size(), H2->capacity()); for (size_t p = 0; p < num_partitions; ++p) { RTC_DCHECK_EQ(kFftLengthBy2Plus1, (*H2)[p].size()); for (size_t ch = 0; ch < num_render_channels; ++ch) { for (size_t j = 0; j < kFftLengthBy2; j += 8) { __m256 re = _mm256_loadu_ps(&H[p][ch].re[j]); __m256 re2 = _mm256_mul_ps(re, re); __m256 im = _mm256_loadu_ps(&H[p][ch].im[j]); re2 = _mm256_fmadd_ps(im, im, re2); __m256 H2_k_j = _mm256_loadu_ps(&(*H2)[p][j]); H2_k_j = _mm256_max_ps(H2_k_j, re2); _mm256_storeu_ps(&(*H2)[p][j], H2_k_j); } float H2_new = H[p][ch].re[kFftLengthBy2] * H[p][ch].re[kFftLengthBy2] + H[p][ch].im[kFftLengthBy2] * H[p][ch].im[kFftLengthBy2]; (*H2)[p][kFftLengthBy2] = std::max((*H2)[p][kFftLengthBy2], H2_new); } } } // Adapts the filter partitions. void AdaptPartitions_Avx2(const RenderBuffer& render_buffer, const FftData& G, size_t num_partitions, std::vector>* H) { rtc::ArrayView> render_buffer_data = render_buffer.GetFftBuffer(); const size_t num_render_channels = render_buffer_data[0].size(); const size_t lim1 = std::min( render_buffer_data.size() - render_buffer.Position(), num_partitions); const size_t lim2 = num_partitions; constexpr size_t kNumEightBinBands = kFftLengthBy2 / 8; size_t X_partition = render_buffer.Position(); size_t limit = lim1; size_t p = 0; do { for (; p < limit; ++p, ++X_partition) { for (size_t ch = 0; ch < num_render_channels; ++ch) { FftData& H_p_ch = (*H)[p][ch]; const FftData& X = render_buffer_data[X_partition][ch]; for (size_t k = 0, n = 0; n < kNumEightBinBands; ++n, k += 8) { const __m256 G_re = _mm256_loadu_ps(&G.re[k]); const __m256 G_im = _mm256_loadu_ps(&G.im[k]); const __m256 X_re = _mm256_loadu_ps(&X.re[k]); const __m256 X_im = _mm256_loadu_ps(&X.im[k]); const __m256 H_re = _mm256_loadu_ps(&H_p_ch.re[k]); const __m256 H_im = _mm256_loadu_ps(&H_p_ch.im[k]); const __m256 a = _mm256_mul_ps(X_re, G_re); const __m256 b = _mm256_mul_ps(X_im, G_im); const __m256 c = _mm256_mul_ps(X_re, G_im); const __m256 d = _mm256_mul_ps(X_im, G_re); const __m256 e = _mm256_add_ps(a, b); const __m256 f = _mm256_sub_ps(c, d); const __m256 g = _mm256_add_ps(H_re, e); const __m256 h = _mm256_add_ps(H_im, f); _mm256_storeu_ps(&H_p_ch.re[k], g); _mm256_storeu_ps(&H_p_ch.im[k], h); } } } X_partition = 0; limit = lim2; } while (p < lim2); X_partition = render_buffer.Position(); limit = lim1; p = 0; do { for (; p < limit; ++p, ++X_partition) { for (size_t ch = 0; ch < num_render_channels; ++ch) { FftData& H_p_ch = (*H)[p][ch]; const FftData& X = render_buffer_data[X_partition][ch]; H_p_ch.re[kFftLengthBy2] += X.re[kFftLengthBy2] * G.re[kFftLengthBy2] + X.im[kFftLengthBy2] * G.im[kFftLengthBy2]; H_p_ch.im[kFftLengthBy2] += X.re[kFftLengthBy2] * G.im[kFftLengthBy2] - X.im[kFftLengthBy2] * G.re[kFftLengthBy2]; } } X_partition = 0; limit = lim2; } while (p < lim2); } // Produces the filter output (AVX2 variant). void ApplyFilter_Avx2(const RenderBuffer& render_buffer, size_t num_partitions, const std::vector>& H, FftData* S) { RTC_DCHECK_GE(H.size(), H.size() - 1); S->re.fill(0.f); S->im.fill(0.f); rtc::ArrayView> render_buffer_data = render_buffer.GetFftBuffer(); const size_t num_render_channels = render_buffer_data[0].size(); const size_t lim1 = std::min( render_buffer_data.size() - render_buffer.Position(), num_partitions); const size_t lim2 = num_partitions; constexpr size_t kNumEightBinBands = kFftLengthBy2 / 8; size_t X_partition = render_buffer.Position(); size_t p = 0; size_t limit = lim1; do { for (; p < limit; ++p, ++X_partition) { for (size_t ch = 0; ch < num_render_channels; ++ch) { const FftData& H_p_ch = H[p][ch]; const FftData& X = render_buffer_data[X_partition][ch]; for (size_t k = 0, n = 0; n < kNumEightBinBands; ++n, k += 8) { const __m256 X_re = _mm256_loadu_ps(&X.re[k]); const __m256 X_im = _mm256_loadu_ps(&X.im[k]); const __m256 H_re = _mm256_loadu_ps(&H_p_ch.re[k]); const __m256 H_im = _mm256_loadu_ps(&H_p_ch.im[k]); const __m256 S_re = _mm256_loadu_ps(&S->re[k]); const __m256 S_im = _mm256_loadu_ps(&S->im[k]); const __m256 a = _mm256_mul_ps(X_re, H_re); const __m256 b = _mm256_mul_ps(X_im, H_im); const __m256 c = _mm256_mul_ps(X_re, H_im); const __m256 d = _mm256_mul_ps(X_im, H_re); const __m256 e = _mm256_sub_ps(a, b); const __m256 f = _mm256_add_ps(c, d); const __m256 g = _mm256_add_ps(S_re, e); const __m256 h = _mm256_add_ps(S_im, f); _mm256_storeu_ps(&S->re[k], g); _mm256_storeu_ps(&S->im[k], h); } } } limit = lim2; X_partition = 0; } while (p < lim2); X_partition = render_buffer.Position(); p = 0; limit = lim1; do { for (; p < limit; ++p, ++X_partition) { for (size_t ch = 0; ch < num_render_channels; ++ch) { const FftData& H_p_ch = H[p][ch]; const FftData& X = render_buffer_data[X_partition][ch]; S->re[kFftLengthBy2] += X.re[kFftLengthBy2] * H_p_ch.re[kFftLengthBy2] - X.im[kFftLengthBy2] * H_p_ch.im[kFftLengthBy2]; S->im[kFftLengthBy2] += X.re[kFftLengthBy2] * H_p_ch.im[kFftLengthBy2] + X.im[kFftLengthBy2] * H_p_ch.re[kFftLengthBy2]; } } limit = lim2; X_partition = 0; } while (p < lim2); } } // namespace aec3 } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl.cc0000664000175000017500000000614014475643423031150 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/adaptive_fir_filter_erl.h" #include #include #if defined(WEBRTC_HAS_NEON) #include #endif #if defined(WEBRTC_ARCH_X86_FAMILY) #include #endif namespace webrtc { namespace aec3 { // Computes and stores the echo return loss estimate of the filter, which is the // sum of the partition frequency responses. void ErlComputer(const std::vector>& H2, rtc::ArrayView erl) { std::fill(erl.begin(), erl.end(), 0.f); for (auto& H2_j : H2) { std::transform(H2_j.begin(), H2_j.end(), erl.begin(), erl.begin(), std::plus()); } } #if defined(WEBRTC_HAS_NEON) // Computes and stores the echo return loss estimate of the filter, which is the // sum of the partition frequency responses. void ErlComputer_NEON( const std::vector>& H2, rtc::ArrayView erl) { std::fill(erl.begin(), erl.end(), 0.f); for (auto& H2_j : H2) { for (size_t k = 0; k < kFftLengthBy2; k += 4) { const float32x4_t H2_j_k = vld1q_f32(&H2_j[k]); float32x4_t erl_k = vld1q_f32(&erl[k]); erl_k = vaddq_f32(erl_k, H2_j_k); vst1q_f32(&erl[k], erl_k); } erl[kFftLengthBy2] += H2_j[kFftLengthBy2]; } } #endif #if defined(WEBRTC_ARCH_X86_FAMILY) // Computes and stores the echo return loss estimate of the filter, which is the // sum of the partition frequency responses. void ErlComputer_SSE2( const std::vector>& H2, rtc::ArrayView erl) { std::fill(erl.begin(), erl.end(), 0.f); for (auto& H2_j : H2) { for (size_t k = 0; k < kFftLengthBy2; k += 4) { const __m128 H2_j_k = _mm_loadu_ps(&H2_j[k]); __m128 erl_k = _mm_loadu_ps(&erl[k]); erl_k = _mm_add_ps(erl_k, H2_j_k); _mm_storeu_ps(&erl[k], erl_k); } erl[kFftLengthBy2] += H2_j[kFftLengthBy2]; } } #endif } // namespace aec3 void ComputeErl(const Aec3Optimization& optimization, const std::vector>& H2, rtc::ArrayView erl) { RTC_DCHECK_EQ(kFftLengthBy2Plus1, erl.size()); // Update the frequency response and echo return loss for the filter. switch (optimization) { #if defined(WEBRTC_ARCH_X86_FAMILY) case Aec3Optimization::kSse2: aec3::ErlComputer_SSE2(H2, erl); break; case Aec3Optimization::kAvx2: aec3::ErlComputer_AVX2(H2, erl); break; #endif #if defined(WEBRTC_HAS_NEON) case Aec3Optimization::kNeon: aec3::ErlComputer_NEON(H2, erl); break; #endif default: aec3::ErlComputer(H2, erl); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl.h0000664000175000017500000000341614475643423031015 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_ADAPTIVE_FIR_FILTER_ERL_H_ #define MODULES_AUDIO_PROCESSING_AEC3_ADAPTIVE_FIR_FILTER_ERL_H_ #include #include #include #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "rtc_base/system/arch.h" namespace webrtc { namespace aec3 { // Computes and stores the echo return loss estimate of the filter, which is the // sum of the partition frequency responses. void ErlComputer(const std::vector>& H2, rtc::ArrayView erl); #if defined(WEBRTC_HAS_NEON) void ErlComputer_NEON( const std::vector>& H2, rtc::ArrayView erl); #endif #if defined(WEBRTC_ARCH_X86_FAMILY) void ErlComputer_SSE2( const std::vector>& H2, rtc::ArrayView erl); void ErlComputer_AVX2( const std::vector>& H2, rtc::ArrayView erl); #endif } // namespace aec3 // Computes the echo return loss based on a frequency response. void ComputeErl(const Aec3Optimization& optimization, const std::vector>& H2, rtc::ArrayView erl); } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_ADAPTIVE_FIR_FILTER_ERL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl_avx2.cc0000664000175000017500000000226214475643423032111 0ustar00arunarun/* * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/adaptive_fir_filter_erl.h" #include namespace webrtc { namespace aec3 { // Computes and stores the echo return loss estimate of the filter, which is the // sum of the partition frequency responses. void ErlComputer_AVX2( const std::vector>& H2, rtc::ArrayView erl) { std::fill(erl.begin(), erl.end(), 0.f); for (auto& H2_j : H2) { for (size_t k = 0; k < kFftLengthBy2; k += 8) { const __m256 H2_j_k = _mm256_loadu_ps(&H2_j[k]); __m256 erl_k = _mm256_loadu_ps(&erl[k]); erl_k = _mm256_add_ps(erl_k, H2_j_k); _mm256_storeu_ps(&erl[k], erl_k); } erl[kFftLengthBy2] += H2_j[kFftLengthBy2]; } } } // namespace aec3 } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/aec3_common.cc0000664000175000017500000000314614475643423026472 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/aec3_common.h" #include #include "rtc_base/checks.h" #include "rtc_base/system/arch.h" #include "system_wrappers/include/cpu_features_wrapper.h" namespace webrtc { Aec3Optimization DetectOptimization() { #if defined(WEBRTC_ARCH_X86_FAMILY) if (GetCPUInfo(kAVX2) != 0) { return Aec3Optimization::kAvx2; } else if (GetCPUInfo(kSSE2) != 0) { return Aec3Optimization::kSse2; } #endif #if defined(WEBRTC_HAS_NEON) return Aec3Optimization::kNeon; #endif return Aec3Optimization::kNone; } float FastApproxLog2f(const float in) { RTC_DCHECK_GT(in, .0f); // Read and interpret float as uint32_t and then cast to float. // This is done to extract the exponent (bits 30 - 23). // "Right shift" of the exponent is then performed by multiplying // with the constant (1/2^23). Finally, we subtract a constant to // remove the bias (https://en.wikipedia.org/wiki/Exponent_bias). union { float dummy; uint32_t a; } x = {in}; float out = x.a; out *= 1.1920929e-7f; // 1/2^23 out -= 126.942695f; // Remove bias. return out; } float Log2TodB(const float in_log2) { return 3.0102999566398121 * in_log2; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/aec3_common.h0000664000175000017500000001015614475643423026333 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_AEC3_COMMON_H_ #define MODULES_AUDIO_PROCESSING_AEC3_AEC3_COMMON_H_ #include namespace webrtc { #ifdef _MSC_VER /* visual c++ */ #define ALIGN16_BEG __declspec(align(16)) #define ALIGN16_END #else /* gcc or icc */ #define ALIGN16_BEG #define ALIGN16_END __attribute__((aligned(16))) #endif enum class Aec3Optimization { kNone, kSse2, kAvx2, kNeon }; constexpr int kNumBlocksPerSecond = 250; constexpr int kMetricsReportingIntervalBlocks = 10 * kNumBlocksPerSecond; constexpr int kMetricsComputationBlocks = 7; constexpr int kMetricsCollectionBlocks = kMetricsReportingIntervalBlocks - kMetricsComputationBlocks; constexpr size_t kFftLengthBy2 = 64; constexpr size_t kFftLengthBy2Plus1 = kFftLengthBy2 + 1; constexpr size_t kFftLengthBy2Minus1 = kFftLengthBy2 - 1; constexpr size_t kFftLength = 2 * kFftLengthBy2; constexpr size_t kFftLengthBy2Log2 = 6; constexpr int kRenderTransferQueueSizeFrames = 100; constexpr size_t kMaxNumBands = 3; constexpr size_t kFrameSize = 160; constexpr size_t kSubFrameLength = kFrameSize / 2; constexpr size_t kBlockSize = kFftLengthBy2; constexpr size_t kBlockSizeLog2 = kFftLengthBy2Log2; constexpr size_t kExtendedBlockSize = 2 * kFftLengthBy2; constexpr size_t kMatchedFilterWindowSizeSubBlocks = 32; constexpr size_t kMatchedFilterAlignmentShiftSizeSubBlocks = kMatchedFilterWindowSizeSubBlocks * 3 / 4; // TODO(peah): Integrate this with how it is done inside audio_processing_impl. constexpr size_t NumBandsForRate(int sample_rate_hz) { return static_cast(sample_rate_hz / 16000); } constexpr bool ValidFullBandRate(int sample_rate_hz) { return sample_rate_hz == 16000 || sample_rate_hz == 32000 || sample_rate_hz == 48000; } constexpr int GetTimeDomainLength(int filter_length_blocks) { return filter_length_blocks * kFftLengthBy2; } constexpr size_t GetDownSampledBufferSize(size_t down_sampling_factor, size_t num_matched_filters) { return kBlockSize / down_sampling_factor * (kMatchedFilterAlignmentShiftSizeSubBlocks * num_matched_filters + kMatchedFilterWindowSizeSubBlocks + 1); } constexpr size_t GetRenderDelayBufferSize(size_t down_sampling_factor, size_t num_matched_filters, size_t filter_length_blocks) { return GetDownSampledBufferSize(down_sampling_factor, num_matched_filters) / (kBlockSize / down_sampling_factor) + filter_length_blocks + 1; } // Detects what kind of optimizations to use for the code. Aec3Optimization DetectOptimization(); // Computes the log2 of the input in a fast an approximate manner. float FastApproxLog2f(const float in); // Returns dB from a power quantity expressed in log2. float Log2TodB(const float in_log2); static_assert(1 << kBlockSizeLog2 == kBlockSize, "Proper number of shifts for blocksize"); static_assert(1 << kFftLengthBy2Log2 == kFftLengthBy2, "Proper number of shifts for the fft length"); static_assert(1 == NumBandsForRate(16000), "Number of bands for 16 kHz"); static_assert(2 == NumBandsForRate(32000), "Number of bands for 32 kHz"); static_assert(3 == NumBandsForRate(48000), "Number of bands for 48 kHz"); static_assert(ValidFullBandRate(16000), "Test that 16 kHz is a valid sample rate"); static_assert(ValidFullBandRate(32000), "Test that 32 kHz is a valid sample rate"); static_assert(ValidFullBandRate(48000), "Test that 48 kHz is a valid sample rate"); static_assert(!ValidFullBandRate(8001), "Test that 8001 Hz is not a valid sample rate"); } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_AEC3_COMMON_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/aec3_fft.cc0000664000175000017500000001430414475643423025757 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/aec3_fft.h" #include #include #include #include "rtc_base/checks.h" #include "system_wrappers/include/cpu_features_wrapper.h" namespace webrtc { namespace { const float kHanning64[kFftLengthBy2] = { 0.f, 0.00248461f, 0.00991376f, 0.0222136f, 0.03926189f, 0.06088921f, 0.08688061f, 0.11697778f, 0.15088159f, 0.1882551f, 0.22872687f, 0.27189467f, 0.31732949f, 0.36457977f, 0.41317591f, 0.46263495f, 0.51246535f, 0.56217185f, 0.61126047f, 0.65924333f, 0.70564355f, 0.75f, 0.79187184f, 0.83084292f, 0.86652594f, 0.89856625f, 0.92664544f, 0.95048443f, 0.96984631f, 0.98453864f, 0.99441541f, 0.99937846f, 0.99937846f, 0.99441541f, 0.98453864f, 0.96984631f, 0.95048443f, 0.92664544f, 0.89856625f, 0.86652594f, 0.83084292f, 0.79187184f, 0.75f, 0.70564355f, 0.65924333f, 0.61126047f, 0.56217185f, 0.51246535f, 0.46263495f, 0.41317591f, 0.36457977f, 0.31732949f, 0.27189467f, 0.22872687f, 0.1882551f, 0.15088159f, 0.11697778f, 0.08688061f, 0.06088921f, 0.03926189f, 0.0222136f, 0.00991376f, 0.00248461f, 0.f}; // Hanning window from Matlab command win = sqrt(hanning(128)). const float kSqrtHanning128[kFftLength] = { 0.00000000000000f, 0.02454122852291f, 0.04906767432742f, 0.07356456359967f, 0.09801714032956f, 0.12241067519922f, 0.14673047445536f, 0.17096188876030f, 0.19509032201613f, 0.21910124015687f, 0.24298017990326f, 0.26671275747490f, 0.29028467725446f, 0.31368174039889f, 0.33688985339222f, 0.35989503653499f, 0.38268343236509f, 0.40524131400499f, 0.42755509343028f, 0.44961132965461f, 0.47139673682600f, 0.49289819222978f, 0.51410274419322f, 0.53499761988710f, 0.55557023301960f, 0.57580819141785f, 0.59569930449243f, 0.61523159058063f, 0.63439328416365f, 0.65317284295378f, 0.67155895484702f, 0.68954054473707f, 0.70710678118655f, 0.72424708295147f, 0.74095112535496f, 0.75720884650648f, 0.77301045336274f, 0.78834642762661f, 0.80320753148064f, 0.81758481315158f, 0.83146961230255f, 0.84485356524971f, 0.85772861000027f, 0.87008699110871f, 0.88192126434835f, 0.89322430119552f, 0.90398929312344f, 0.91420975570353f, 0.92387953251129f, 0.93299279883474f, 0.94154406518302f, 0.94952818059304f, 0.95694033573221f, 0.96377606579544f, 0.97003125319454f, 0.97570213003853f, 0.98078528040323f, 0.98527764238894f, 0.98917650996478f, 0.99247953459871f, 0.99518472667220f, 0.99729045667869f, 0.99879545620517f, 0.99969881869620f, 1.00000000000000f, 0.99969881869620f, 0.99879545620517f, 0.99729045667869f, 0.99518472667220f, 0.99247953459871f, 0.98917650996478f, 0.98527764238894f, 0.98078528040323f, 0.97570213003853f, 0.97003125319454f, 0.96377606579544f, 0.95694033573221f, 0.94952818059304f, 0.94154406518302f, 0.93299279883474f, 0.92387953251129f, 0.91420975570353f, 0.90398929312344f, 0.89322430119552f, 0.88192126434835f, 0.87008699110871f, 0.85772861000027f, 0.84485356524971f, 0.83146961230255f, 0.81758481315158f, 0.80320753148064f, 0.78834642762661f, 0.77301045336274f, 0.75720884650648f, 0.74095112535496f, 0.72424708295147f, 0.70710678118655f, 0.68954054473707f, 0.67155895484702f, 0.65317284295378f, 0.63439328416365f, 0.61523159058063f, 0.59569930449243f, 0.57580819141785f, 0.55557023301960f, 0.53499761988710f, 0.51410274419322f, 0.49289819222978f, 0.47139673682600f, 0.44961132965461f, 0.42755509343028f, 0.40524131400499f, 0.38268343236509f, 0.35989503653499f, 0.33688985339222f, 0.31368174039889f, 0.29028467725446f, 0.26671275747490f, 0.24298017990326f, 0.21910124015687f, 0.19509032201613f, 0.17096188876030f, 0.14673047445536f, 0.12241067519922f, 0.09801714032956f, 0.07356456359967f, 0.04906767432742f, 0.02454122852291f}; bool IsSse2Available() { #if defined(WEBRTC_ARCH_X86_FAMILY) return GetCPUInfo(kSSE2) != 0; #else return false; #endif } } // namespace Aec3Fft::Aec3Fft() : ooura_fft_(IsSse2Available()) {} // TODO(peah): Change x to be std::array once the rest of the code allows this. void Aec3Fft::ZeroPaddedFft(rtc::ArrayView x, Window window, FftData* X) const { RTC_DCHECK(X); RTC_DCHECK_EQ(kFftLengthBy2, x.size()); std::array fft; std::fill(fft.begin(), fft.begin() + kFftLengthBy2, 0.f); switch (window) { case Window::kRectangular: std::copy(x.begin(), x.end(), fft.begin() + kFftLengthBy2); break; case Window::kHanning: std::transform(x.begin(), x.end(), std::begin(kHanning64), fft.begin() + kFftLengthBy2, [](float a, float b) { return a * b; }); break; case Window::kSqrtHanning: RTC_NOTREACHED(); break; default: RTC_NOTREACHED(); } Fft(&fft, X); } void Aec3Fft::PaddedFft(rtc::ArrayView x, rtc::ArrayView x_old, Window window, FftData* X) const { RTC_DCHECK(X); RTC_DCHECK_EQ(kFftLengthBy2, x.size()); RTC_DCHECK_EQ(kFftLengthBy2, x_old.size()); std::array fft; switch (window) { case Window::kRectangular: std::copy(x_old.begin(), x_old.end(), fft.begin()); std::copy(x.begin(), x.end(), fft.begin() + x_old.size()); break; case Window::kHanning: RTC_NOTREACHED(); break; case Window::kSqrtHanning: std::transform(x_old.begin(), x_old.end(), std::begin(kSqrtHanning128), fft.begin(), std::multiplies()); std::transform(x.begin(), x.end(), std::begin(kSqrtHanning128) + x_old.size(), fft.begin() + x_old.size(), std::multiplies()); break; default: RTC_NOTREACHED(); } Fft(&fft, X); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/aec3_fft.h0000664000175000017500000000455414475643423025627 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_AEC3_FFT_H_ #define MODULES_AUDIO_PROCESSING_AEC3_AEC3_FFT_H_ #include #include "api/array_view.h" #include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/fft_data.h" #include "rtc_base/checks.h" #include "rtc_base/constructor_magic.h" namespace webrtc { // Wrapper class that provides 128 point real valued FFT functionality with the // FftData type. class Aec3Fft { public: enum class Window { kRectangular, kHanning, kSqrtHanning }; Aec3Fft(); // Computes the FFT. Note that both the input and output are modified. void Fft(std::array* x, FftData* X) const { RTC_DCHECK(x); RTC_DCHECK(X); ooura_fft_.Fft(x->data()); X->CopyFromPackedArray(*x); } // Computes the inverse Fft. void Ifft(const FftData& X, std::array* x) const { RTC_DCHECK(x); X.CopyToPackedArray(x); ooura_fft_.InverseFft(x->data()); } // Windows the input using a Hanning window, and then adds padding of // kFftLengthBy2 initial zeros before computing the Fft. void ZeroPaddedFft(rtc::ArrayView x, Window window, FftData* X) const; // Concatenates the kFftLengthBy2 values long x and x_old before computing the // Fft. After that, x is copied to x_old. void PaddedFft(rtc::ArrayView x, rtc::ArrayView x_old, FftData* X) const { PaddedFft(x, x_old, Window::kRectangular, X); } // Padded Fft using a time-domain window. void PaddedFft(rtc::ArrayView x, rtc::ArrayView x_old, Window window, FftData* X) const; private: const OouraFft ooura_fft_; RTC_DISALLOW_COPY_AND_ASSIGN(Aec3Fft); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_AEC3_FFT_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/aec_state.cc0000664000175000017500000004456014475643423026244 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/aec_state.h" #include #include #include #include #include "absl/types/optional.h" #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/atomic_ops.h" #include "rtc_base/checks.h" #include "system_wrappers/include/field_trial.h" namespace webrtc { namespace { bool DeactivateInitialStateResetAtEchoPathChange() { return field_trial::IsEnabled( "WebRTC-Aec3DeactivateInitialStateResetKillSwitch"); } bool FullResetAtEchoPathChange() { return !field_trial::IsEnabled("WebRTC-Aec3AecStateFullResetKillSwitch"); } bool SubtractorAnalyzerResetAtEchoPathChange() { return !field_trial::IsEnabled( "WebRTC-Aec3AecStateSubtractorAnalyzerResetKillSwitch"); } void ComputeAvgRenderReverb( const SpectrumBuffer& spectrum_buffer, int delay_blocks, float reverb_decay, ReverbModel* reverb_model, rtc::ArrayView reverb_power_spectrum) { RTC_DCHECK(reverb_model); const size_t num_render_channels = spectrum_buffer.buffer[0].size(); int idx_at_delay = spectrum_buffer.OffsetIndex(spectrum_buffer.read, delay_blocks); int idx_past = spectrum_buffer.IncIndex(idx_at_delay); std::array X2_data; rtc::ArrayView X2; if (num_render_channels > 1) { auto average_channels = [](size_t num_render_channels, rtc::ArrayView> spectrum_band_0, rtc::ArrayView render_power) { std::fill(render_power.begin(), render_power.end(), 0.f); for (size_t ch = 0; ch < num_render_channels; ++ch) { for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { render_power[k] += spectrum_band_0[ch][k]; } } const float normalizer = 1.f / num_render_channels; for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { render_power[k] *= normalizer; } }; average_channels(num_render_channels, spectrum_buffer.buffer[idx_past], X2_data); reverb_model->UpdateReverbNoFreqShaping( X2_data, /*power_spectrum_scaling=*/1.0f, reverb_decay); average_channels(num_render_channels, spectrum_buffer.buffer[idx_at_delay], X2_data); X2 = X2_data; } else { reverb_model->UpdateReverbNoFreqShaping( spectrum_buffer.buffer[idx_past][/*channel=*/0], /*power_spectrum_scaling=*/1.0f, reverb_decay); X2 = spectrum_buffer.buffer[idx_at_delay][/*channel=*/0]; } rtc::ArrayView reverb_power = reverb_model->reverb(); for (size_t k = 0; k < X2.size(); ++k) { reverb_power_spectrum[k] = X2[k] + reverb_power[k]; } } } // namespace int AecState::instance_count_ = 0; void AecState::GetResidualEchoScaling( rtc::ArrayView residual_scaling) const { bool filter_has_had_time_to_converge; if (config_.filter.conservative_initial_phase) { filter_has_had_time_to_converge = strong_not_saturated_render_blocks_ >= 1.5f * kNumBlocksPerSecond; } else { filter_has_had_time_to_converge = strong_not_saturated_render_blocks_ >= 0.8f * kNumBlocksPerSecond; } echo_audibility_.GetResidualEchoScaling(filter_has_had_time_to_converge, residual_scaling); } absl::optional AecState::ErleUncertainty() const { if (SaturatedEcho()) { return 1.f; } return absl::nullopt; } AecState::AecState(const EchoCanceller3Config& config, size_t num_capture_channels) : data_dumper_( new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), config_(config), num_capture_channels_(num_capture_channels), deactivate_initial_state_reset_at_echo_path_change_( DeactivateInitialStateResetAtEchoPathChange()), full_reset_at_echo_path_change_(FullResetAtEchoPathChange()), subtractor_analyzer_reset_at_echo_path_change_( SubtractorAnalyzerResetAtEchoPathChange()), initial_state_(config_), delay_state_(config_, num_capture_channels_), transparent_state_(TransparentMode::Create(config_)), filter_quality_state_(config_, num_capture_channels_), erl_estimator_(2 * kNumBlocksPerSecond), erle_estimator_(2 * kNumBlocksPerSecond, config_, num_capture_channels_), filter_analyzer_(config_, num_capture_channels_), echo_audibility_( config_.echo_audibility.use_stationarity_properties_at_init), reverb_model_estimator_(config_, num_capture_channels_), subtractor_output_analyzer_(num_capture_channels_) {} AecState::~AecState() = default; void AecState::HandleEchoPathChange( const EchoPathVariability& echo_path_variability) { const auto full_reset = [&]() { filter_analyzer_.Reset(); capture_signal_saturation_ = false; strong_not_saturated_render_blocks_ = 0; blocks_with_active_render_ = 0; if (!deactivate_initial_state_reset_at_echo_path_change_) { initial_state_.Reset(); } if (transparent_state_) { transparent_state_->Reset(); } erle_estimator_.Reset(true); erl_estimator_.Reset(); filter_quality_state_.Reset(); }; // TODO(peah): Refine the reset scheme according to the type of gain and // delay adjustment. if (full_reset_at_echo_path_change_ && echo_path_variability.delay_change != EchoPathVariability::DelayAdjustment::kNone) { full_reset(); } else if (echo_path_variability.gain_change) { erle_estimator_.Reset(false); } if (subtractor_analyzer_reset_at_echo_path_change_) { subtractor_output_analyzer_.HandleEchoPathChange(); } } void AecState::Update( const absl::optional& external_delay, rtc::ArrayView>> adaptive_filter_frequency_responses, rtc::ArrayView> adaptive_filter_impulse_responses, const RenderBuffer& render_buffer, rtc::ArrayView> E2_refined, rtc::ArrayView> Y2, rtc::ArrayView subtractor_output) { RTC_DCHECK_EQ(num_capture_channels_, Y2.size()); RTC_DCHECK_EQ(num_capture_channels_, subtractor_output.size()); RTC_DCHECK_EQ(num_capture_channels_, adaptive_filter_frequency_responses.size()); RTC_DCHECK_EQ(num_capture_channels_, adaptive_filter_impulse_responses.size()); // Analyze the filter outputs and filters. bool any_filter_converged; bool all_filters_diverged; subtractor_output_analyzer_.Update(subtractor_output, &any_filter_converged, &all_filters_diverged); bool any_filter_consistent; float max_echo_path_gain; filter_analyzer_.Update(adaptive_filter_impulse_responses, render_buffer, &any_filter_consistent, &max_echo_path_gain); // Estimate the direct path delay of the filter. if (config_.filter.use_linear_filter) { delay_state_.Update(filter_analyzer_.FilterDelaysBlocks(), external_delay, strong_not_saturated_render_blocks_); } const std::vector>& aligned_render_block = render_buffer.Block(-delay_state_.MinDirectPathFilterDelay())[0]; // Update render counters. bool active_render = false; for (size_t ch = 0; ch < aligned_render_block.size(); ++ch) { const float render_energy = std::inner_product( aligned_render_block[ch].begin(), aligned_render_block[ch].end(), aligned_render_block[ch].begin(), 0.f); if (render_energy > (config_.render_levels.active_render_limit * config_.render_levels.active_render_limit) * kFftLengthBy2) { active_render = true; break; } } blocks_with_active_render_ += active_render ? 1 : 0; strong_not_saturated_render_blocks_ += active_render && !SaturatedCapture() ? 1 : 0; std::array avg_render_spectrum_with_reverb; ComputeAvgRenderReverb(render_buffer.GetSpectrumBuffer(), delay_state_.MinDirectPathFilterDelay(), ReverbDecay(), &avg_render_reverb_, avg_render_spectrum_with_reverb); if (config_.echo_audibility.use_stationarity_properties) { // Update the echo audibility evaluator. echo_audibility_.Update(render_buffer, avg_render_reverb_.reverb(), delay_state_.MinDirectPathFilterDelay(), delay_state_.ExternalDelayReported()); } // Update the ERL and ERLE measures. if (initial_state_.TransitionTriggered()) { erle_estimator_.Reset(false); } erle_estimator_.Update(render_buffer, adaptive_filter_frequency_responses, avg_render_spectrum_with_reverb, Y2, E2_refined, subtractor_output_analyzer_.ConvergedFilters()); erl_estimator_.Update( subtractor_output_analyzer_.ConvergedFilters(), render_buffer.Spectrum(delay_state_.MinDirectPathFilterDelay()), Y2); // Detect and flag echo saturation. if (config_.ep_strength.echo_can_saturate) { saturation_detector_.Update(aligned_render_block, SaturatedCapture(), UsableLinearEstimate(), subtractor_output, max_echo_path_gain); } else { RTC_DCHECK(!saturation_detector_.SaturatedEcho()); } // Update the decision on whether to use the initial state parameter set. initial_state_.Update(active_render, SaturatedCapture()); // Detect whether the transparent mode should be activated. if (transparent_state_) { transparent_state_->Update(delay_state_.MinDirectPathFilterDelay(), any_filter_consistent, any_filter_converged, all_filters_diverged, active_render, SaturatedCapture()); } // Analyze the quality of the filter. filter_quality_state_.Update(active_render, TransparentModeActive(), SaturatedCapture(), external_delay, any_filter_converged); // Update the reverb estimate. const bool stationary_block = config_.echo_audibility.use_stationarity_properties && echo_audibility_.IsBlockStationary(); reverb_model_estimator_.Update( filter_analyzer_.GetAdjustedFilters(), adaptive_filter_frequency_responses, erle_estimator_.GetInstLinearQualityEstimates(), delay_state_.DirectPathFilterDelays(), filter_quality_state_.UsableLinearFilterOutputs(), stationary_block); erle_estimator_.Dump(data_dumper_); reverb_model_estimator_.Dump(data_dumper_.get()); data_dumper_->DumpRaw("aec3_active_render", active_render); data_dumper_->DumpRaw("aec3_erl", Erl()); data_dumper_->DumpRaw("aec3_erl_time_domain", ErlTimeDomain()); data_dumper_->DumpRaw("aec3_erle", Erle()[0]); data_dumper_->DumpRaw("aec3_usable_linear_estimate", UsableLinearEstimate()); data_dumper_->DumpRaw("aec3_transparent_mode", TransparentModeActive()); data_dumper_->DumpRaw("aec3_filter_delay", filter_analyzer_.MinFilterDelayBlocks()); data_dumper_->DumpRaw("aec3_any_filter_consistent", any_filter_consistent); data_dumper_->DumpRaw("aec3_initial_state", initial_state_.InitialStateActive()); data_dumper_->DumpRaw("aec3_capture_saturation", SaturatedCapture()); data_dumper_->DumpRaw("aec3_echo_saturation", SaturatedEcho()); data_dumper_->DumpRaw("aec3_any_filter_converged", any_filter_converged); data_dumper_->DumpRaw("aec3_all_filters_diverged", all_filters_diverged); data_dumper_->DumpRaw("aec3_external_delay_avaliable", external_delay ? 1 : 0); data_dumper_->DumpRaw("aec3_filter_tail_freq_resp_est", GetReverbFrequencyResponse()); } AecState::InitialState::InitialState(const EchoCanceller3Config& config) : conservative_initial_phase_(config.filter.conservative_initial_phase), initial_state_seconds_(config.filter.initial_state_seconds) { Reset(); } void AecState::InitialState::InitialState::Reset() { initial_state_ = true; strong_not_saturated_render_blocks_ = 0; } void AecState::InitialState::InitialState::Update(bool active_render, bool saturated_capture) { strong_not_saturated_render_blocks_ += active_render && !saturated_capture ? 1 : 0; // Flag whether the initial state is still active. bool prev_initial_state = initial_state_; if (conservative_initial_phase_) { initial_state_ = strong_not_saturated_render_blocks_ < 5 * kNumBlocksPerSecond; } else { initial_state_ = strong_not_saturated_render_blocks_ < initial_state_seconds_ * kNumBlocksPerSecond; } // Flag whether the transition from the initial state has started. transition_triggered_ = !initial_state_ && prev_initial_state; } AecState::FilterDelay::FilterDelay(const EchoCanceller3Config& config, size_t num_capture_channels) : delay_headroom_blocks_(config.delay.delay_headroom_samples / kBlockSize), filter_delays_blocks_(num_capture_channels, delay_headroom_blocks_), min_filter_delay_(delay_headroom_blocks_) {} void AecState::FilterDelay::Update( rtc::ArrayView analyzer_filter_delay_estimates_blocks, const absl::optional& external_delay, size_t blocks_with_proper_filter_adaptation) { // Update the delay based on the external delay. if (external_delay && (!external_delay_ || external_delay_->delay != external_delay->delay)) { external_delay_ = external_delay; external_delay_reported_ = true; } // Override the estimated delay if it is not certain that the filter has had // time to converge. const bool delay_estimator_may_not_have_converged = blocks_with_proper_filter_adaptation < 2 * kNumBlocksPerSecond; if (delay_estimator_may_not_have_converged && external_delay_) { const int delay_guess = delay_headroom_blocks_; std::fill(filter_delays_blocks_.begin(), filter_delays_blocks_.end(), delay_guess); } else { RTC_DCHECK_EQ(filter_delays_blocks_.size(), analyzer_filter_delay_estimates_blocks.size()); std::copy(analyzer_filter_delay_estimates_blocks.begin(), analyzer_filter_delay_estimates_blocks.end(), filter_delays_blocks_.begin()); } min_filter_delay_ = *std::min_element(filter_delays_blocks_.begin(), filter_delays_blocks_.end()); } AecState::FilteringQualityAnalyzer::FilteringQualityAnalyzer( const EchoCanceller3Config& config, size_t num_capture_channels) : use_linear_filter_(config.filter.use_linear_filter), usable_linear_filter_estimates_(num_capture_channels, false) {} void AecState::FilteringQualityAnalyzer::Reset() { std::fill(usable_linear_filter_estimates_.begin(), usable_linear_filter_estimates_.end(), false); overall_usable_linear_estimates_ = false; filter_update_blocks_since_reset_ = 0; } void AecState::FilteringQualityAnalyzer::Update( bool active_render, bool transparent_mode, bool saturated_capture, const absl::optional& external_delay, bool any_filter_converged) { // Update blocks counter. const bool filter_update = active_render && !saturated_capture; filter_update_blocks_since_reset_ += filter_update ? 1 : 0; filter_update_blocks_since_start_ += filter_update ? 1 : 0; // Store convergence flag when observed. convergence_seen_ = convergence_seen_ || any_filter_converged; // Verify requirements for achieving a decent filter. The requirements for // filter adaptation at call startup are more restrictive than after an // in-call reset. const bool sufficient_data_to_converge_at_startup = filter_update_blocks_since_start_ > kNumBlocksPerSecond * 0.4f; const bool sufficient_data_to_converge_at_reset = sufficient_data_to_converge_at_startup && filter_update_blocks_since_reset_ > kNumBlocksPerSecond * 0.2f; // The linear filter can only be used if it has had time to converge. overall_usable_linear_estimates_ = sufficient_data_to_converge_at_startup && sufficient_data_to_converge_at_reset; // The linear filter can only be used if an external delay or convergence have // been identified overall_usable_linear_estimates_ = overall_usable_linear_estimates_ && (external_delay || convergence_seen_); // If transparent mode is on, deactivate usign the linear filter. overall_usable_linear_estimates_ = overall_usable_linear_estimates_ && !transparent_mode; if (use_linear_filter_) { std::fill(usable_linear_filter_estimates_.begin(), usable_linear_filter_estimates_.end(), overall_usable_linear_estimates_); } } void AecState::SaturationDetector::Update( rtc::ArrayView> x, bool saturated_capture, bool usable_linear_estimate, rtc::ArrayView subtractor_output, float echo_path_gain) { saturated_echo_ = false; if (!saturated_capture) { return; } if (usable_linear_estimate) { constexpr float kSaturationThreshold = 20000.f; for (size_t ch = 0; ch < subtractor_output.size(); ++ch) { saturated_echo_ = saturated_echo_ || (subtractor_output[ch].s_refined_max_abs > kSaturationThreshold || subtractor_output[ch].s_coarse_max_abs > kSaturationThreshold); } } else { float max_sample = 0.f; for (auto& channel : x) { for (float sample : channel) { max_sample = std::max(max_sample, fabsf(sample)); } } const float kMargin = 10.f; float peak_echo_amplitude = max_sample * echo_path_gain * kMargin; saturated_echo_ = saturated_echo_ || peak_echo_amplitude > 32000; } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/aec_state.h0000664000175000017500000002546614475643423026112 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_AEC_STATE_H_ #define MODULES_AUDIO_PROCESSING_AEC3_AEC_STATE_H_ #include #include #include #include #include "absl/types/optional.h" #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/delay_estimate.h" #include "modules/audio_processing/aec3/echo_audibility.h" #include "modules/audio_processing/aec3/echo_path_variability.h" #include "modules/audio_processing/aec3/erl_estimator.h" #include "modules/audio_processing/aec3/erle_estimator.h" #include "modules/audio_processing/aec3/filter_analyzer.h" #include "modules/audio_processing/aec3/render_buffer.h" #include "modules/audio_processing/aec3/reverb_model_estimator.h" #include "modules/audio_processing/aec3/subtractor_output.h" #include "modules/audio_processing/aec3/subtractor_output_analyzer.h" #include "modules/audio_processing/aec3/transparent_mode.h" namespace webrtc { class ApmDataDumper; // Handles the state and the conditions for the echo removal functionality. class AecState { public: AecState(const EchoCanceller3Config& config, size_t num_capture_channels); ~AecState(); // Returns whether the echo subtractor can be used to determine the residual // echo. bool UsableLinearEstimate() const { return filter_quality_state_.LinearFilterUsable() && config_.filter.use_linear_filter; } // Returns whether the echo subtractor output should be used as output. bool UseLinearFilterOutput() const { return filter_quality_state_.LinearFilterUsable() && config_.filter.use_linear_filter; } // Returns whether the render signal is currently active. bool ActiveRender() const { return blocks_with_active_render_ > 200; } // Returns the appropriate scaling of the residual echo to match the // audibility. void GetResidualEchoScaling(rtc::ArrayView residual_scaling) const; // Returns whether the stationary properties of the signals are used in the // aec. bool UseStationarityProperties() const { return config_.echo_audibility.use_stationarity_properties; } // Returns the ERLE. rtc::ArrayView> Erle() const { return erle_estimator_.Erle(); } // Returns an offset to apply to the estimation of the residual echo // computation. Returning nullopt means that no offset should be used, while // any other value will be applied as a multiplier to the estimated residual // echo. absl::optional ErleUncertainty() const; // Returns the fullband ERLE estimate in log2 units. float FullBandErleLog2() const { return erle_estimator_.FullbandErleLog2(); } // Returns the ERL. const std::array& Erl() const { return erl_estimator_.Erl(); } // Returns the time-domain ERL. float ErlTimeDomain() const { return erl_estimator_.ErlTimeDomain(); } // Returns the delay estimate based on the linear filter. int MinDirectPathFilterDelay() const { return delay_state_.MinDirectPathFilterDelay(); } // Returns whether the capture signal is saturated. bool SaturatedCapture() const { return capture_signal_saturation_; } // Returns whether the echo signal is saturated. bool SaturatedEcho() const { return saturation_detector_.SaturatedEcho(); } // Updates the capture signal saturation. void UpdateCaptureSaturation(bool capture_signal_saturation) { capture_signal_saturation_ = capture_signal_saturation; } // Returns whether the transparent mode is active bool TransparentModeActive() const { return transparent_state_ && transparent_state_->Active(); } // Takes appropriate action at an echo path change. void HandleEchoPathChange(const EchoPathVariability& echo_path_variability); // Returns the decay factor for the echo reverberation. float ReverbDecay() const { return reverb_model_estimator_.ReverbDecay(); } // Return the frequency response of the reverberant echo. rtc::ArrayView GetReverbFrequencyResponse() const { return reverb_model_estimator_.GetReverbFrequencyResponse(); } // Returns whether the transition for going out of the initial stated has // been triggered. bool TransitionTriggered() const { return initial_state_.TransitionTriggered(); } // Updates the aec state. // TODO(bugs.webrtc.org/10913): Compute multi-channel ERL. void Update( const absl::optional& external_delay, rtc::ArrayView>> adaptive_filter_frequency_responses, rtc::ArrayView> adaptive_filter_impulse_responses, const RenderBuffer& render_buffer, rtc::ArrayView> E2_refined, rtc::ArrayView> Y2, rtc::ArrayView subtractor_output); // Returns filter length in blocks. int FilterLengthBlocks() const { // All filters have the same length, so arbitrarily return channel 0 length. return filter_analyzer_.FilterLengthBlocks(); } private: static int instance_count_; std::unique_ptr data_dumper_; const EchoCanceller3Config config_; const size_t num_capture_channels_; const bool deactivate_initial_state_reset_at_echo_path_change_; const bool full_reset_at_echo_path_change_; const bool subtractor_analyzer_reset_at_echo_path_change_; // Class for controlling the transition from the intial state, which in turn // controls when the filter parameters for the initial state should be used. class InitialState { public: explicit InitialState(const EchoCanceller3Config& config); // Resets the state to again begin in the initial state. void Reset(); // Updates the state based on new data. void Update(bool active_render, bool saturated_capture); // Returns whether the initial state is active or not. bool InitialStateActive() const { return initial_state_; } // Returns that the transition from the initial state has was started. bool TransitionTriggered() const { return transition_triggered_; } private: const bool conservative_initial_phase_; const float initial_state_seconds_; bool transition_triggered_ = false; bool initial_state_ = true; size_t strong_not_saturated_render_blocks_ = 0; } initial_state_; // Class for choosing the direct-path delay relative to the beginning of the // filter, as well as any other data related to the delay used within // AecState. class FilterDelay { public: FilterDelay(const EchoCanceller3Config& config, size_t num_capture_channels); // Returns whether an external delay has been reported to the AecState (from // the delay estimator). bool ExternalDelayReported() const { return external_delay_reported_; } // Returns the delay in blocks relative to the beginning of the filter that // corresponds to the direct path of the echo. rtc::ArrayView DirectPathFilterDelays() const { return filter_delays_blocks_; } // Returns the minimum delay among the direct path delays relative to the // beginning of the filter int MinDirectPathFilterDelay() const { return min_filter_delay_; } // Updates the delay estimates based on new data. void Update( rtc::ArrayView analyzer_filter_delay_estimates_blocks, const absl::optional& external_delay, size_t blocks_with_proper_filter_adaptation); private: const int delay_headroom_blocks_; bool external_delay_reported_ = false; std::vector filter_delays_blocks_; int min_filter_delay_; absl::optional external_delay_; } delay_state_; // Classifier for toggling transparent mode when there is no echo. std::unique_ptr transparent_state_; // Class for analyzing how well the linear filter is, and can be expected to, // perform on the current signals. The purpose of this is for using to // select the echo suppression functionality as well as the input to the echo // suppressor. class FilteringQualityAnalyzer { public: FilteringQualityAnalyzer(const EchoCanceller3Config& config, size_t num_capture_channels); // Returns whether the linear filter can be used for the echo // canceller output. bool LinearFilterUsable() const { return overall_usable_linear_estimates_; } // Returns whether an individual filter output can be used for the echo // canceller output. const std::vector& UsableLinearFilterOutputs() const { return usable_linear_filter_estimates_; } // Resets the state of the analyzer. void Reset(); // Updates the analysis based on new data. void Update(bool active_render, bool transparent_mode, bool saturated_capture, const absl::optional& external_delay, bool any_filter_converged); private: const bool use_linear_filter_; bool overall_usable_linear_estimates_ = false; size_t filter_update_blocks_since_reset_ = 0; size_t filter_update_blocks_since_start_ = 0; bool convergence_seen_ = false; std::vector usable_linear_filter_estimates_; } filter_quality_state_; // Class for detecting whether the echo is to be considered to be // saturated. class SaturationDetector { public: // Returns whether the echo is to be considered saturated. bool SaturatedEcho() const { return saturated_echo_; } // Updates the detection decision based on new data. void Update(rtc::ArrayView> x, bool saturated_capture, bool usable_linear_estimate, rtc::ArrayView subtractor_output, float echo_path_gain); private: bool saturated_echo_ = false; } saturation_detector_; ErlEstimator erl_estimator_; ErleEstimator erle_estimator_; size_t strong_not_saturated_render_blocks_ = 0; size_t blocks_with_active_render_ = 0; bool capture_signal_saturation_ = false; FilterAnalyzer filter_analyzer_; EchoAudibility echo_audibility_; ReverbModelEstimator reverb_model_estimator_; ReverbModel avg_render_reverb_; SubtractorOutputAnalyzer subtractor_output_analyzer_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_AEC_STATE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/alignment_mixer.cc0000664000175000017500000001256514475643423027476 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/alignment_mixer.h" #include #include "rtc_base/checks.h" namespace webrtc { namespace { AlignmentMixer::MixingVariant ChooseMixingVariant(bool downmix, bool adaptive_selection, int num_channels) { RTC_DCHECK(!(adaptive_selection && downmix)); RTC_DCHECK_LT(0, num_channels); if (num_channels == 1) { return AlignmentMixer::MixingVariant::kFixed; } if (downmix) { return AlignmentMixer::MixingVariant::kDownmix; } if (adaptive_selection) { return AlignmentMixer::MixingVariant::kAdaptive; } return AlignmentMixer::MixingVariant::kFixed; } } // namespace AlignmentMixer::AlignmentMixer( size_t num_channels, const EchoCanceller3Config::Delay::AlignmentMixing& config) : AlignmentMixer(num_channels, config.downmix, config.adaptive_selection, config.activity_power_threshold, config.prefer_first_two_channels) {} AlignmentMixer::AlignmentMixer(size_t num_channels, bool downmix, bool adaptive_selection, float activity_power_threshold, bool prefer_first_two_channels) : num_channels_(num_channels), one_by_num_channels_(1.f / num_channels_), excitation_energy_threshold_(kBlockSize * activity_power_threshold), prefer_first_two_channels_(prefer_first_two_channels), selection_variant_( ChooseMixingVariant(downmix, adaptive_selection, num_channels_)) { if (selection_variant_ == MixingVariant::kAdaptive) { std::fill(strong_block_counters_.begin(), strong_block_counters_.end(), 0); cumulative_energies_.resize(num_channels_); std::fill(cumulative_energies_.begin(), cumulative_energies_.end(), 0.f); } } void AlignmentMixer::ProduceOutput(rtc::ArrayView> x, rtc::ArrayView y) { RTC_DCHECK_EQ(x.size(), num_channels_); if (selection_variant_ == MixingVariant::kDownmix) { Downmix(x, y); return; } int ch = selection_variant_ == MixingVariant::kFixed ? 0 : SelectChannel(x); RTC_DCHECK_GE(x.size(), ch); std::copy(x[ch].begin(), x[ch].end(), y.begin()); } void AlignmentMixer::Downmix(rtc::ArrayView> x, rtc::ArrayView y) const { RTC_DCHECK_EQ(x.size(), num_channels_); RTC_DCHECK_GE(num_channels_, 2); std::copy(x[0].begin(), x[0].end(), y.begin()); for (size_t ch = 1; ch < num_channels_; ++ch) { for (size_t i = 0; i < kBlockSize; ++i) { y[i] += x[ch][i]; } } for (size_t i = 0; i < kBlockSize; ++i) { y[i] *= one_by_num_channels_; } } int AlignmentMixer::SelectChannel(rtc::ArrayView> x) { RTC_DCHECK_EQ(x.size(), num_channels_); RTC_DCHECK_GE(num_channels_, 2); RTC_DCHECK_EQ(cumulative_energies_.size(), num_channels_); constexpr size_t kBlocksToChooseLeftOrRight = static_cast(0.5f * kNumBlocksPerSecond); const bool good_signal_in_left_or_right = prefer_first_two_channels_ && (strong_block_counters_[0] > kBlocksToChooseLeftOrRight || strong_block_counters_[1] > kBlocksToChooseLeftOrRight); const int num_ch_to_analyze = good_signal_in_left_or_right ? 2 : num_channels_; constexpr int kNumBlocksBeforeEnergySmoothing = 60 * kNumBlocksPerSecond; ++block_counter_; for (int ch = 0; ch < num_ch_to_analyze; ++ch) { RTC_DCHECK_EQ(x[ch].size(), kBlockSize); float x2_sum = 0.f; for (size_t i = 0; i < kBlockSize; ++i) { x2_sum += x[ch][i] * x[ch][i]; } if (ch < 2 && x2_sum > excitation_energy_threshold_) { ++strong_block_counters_[ch]; } if (block_counter_ <= kNumBlocksBeforeEnergySmoothing) { cumulative_energies_[ch] += x2_sum; } else { constexpr float kSmoothing = 1.f / (10 * kNumBlocksPerSecond); cumulative_energies_[ch] += kSmoothing * (x2_sum - cumulative_energies_[ch]); } } // Normalize the energies to allow the energy computations to from now be // based on smoothing. if (block_counter_ == kNumBlocksBeforeEnergySmoothing) { constexpr float kOneByNumBlocksBeforeEnergySmoothing = 1.f / kNumBlocksBeforeEnergySmoothing; for (int ch = 0; ch < num_ch_to_analyze; ++ch) { cumulative_energies_[ch] *= kOneByNumBlocksBeforeEnergySmoothing; } } int strongest_ch = 0; for (int ch = 0; ch < num_ch_to_analyze; ++ch) { if (cumulative_energies_[ch] > cumulative_energies_[strongest_ch]) { strongest_ch = ch; } } if ((good_signal_in_left_or_right && selected_channel_ > 1) || cumulative_energies_[strongest_ch] > 2.f * cumulative_energies_[selected_channel_]) { selected_channel_ = strongest_ch; } return selected_channel_; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/alignment_mixer.h0000664000175000017500000000403414475643423027330 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_ALIGNMENT_MIXER_H_ #define MODULES_AUDIO_PROCESSING_AEC3_ALIGNMENT_MIXER_H_ #include #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" namespace webrtc { // Performs channel conversion to mono for the purpose of providing a decent // mono input for the delay estimation. This is achieved by analyzing all // incoming channels and produce one single channel output. class AlignmentMixer { public: AlignmentMixer(size_t num_channels, const EchoCanceller3Config::Delay::AlignmentMixing& config); AlignmentMixer(size_t num_channels, bool downmix, bool adaptive_selection, float excitation_limit, bool prefer_first_two_channels); void ProduceOutput(rtc::ArrayView> x, rtc::ArrayView y); enum class MixingVariant { kDownmix, kAdaptive, kFixed }; private: const size_t num_channels_; const float one_by_num_channels_; const float excitation_energy_threshold_; const bool prefer_first_two_channels_; const MixingVariant selection_variant_; std::array strong_block_counters_; std::vector cumulative_energies_; int selected_channel_ = 0; size_t block_counter_ = 0; void Downmix(const rtc::ArrayView> x, rtc::ArrayView y) const; int SelectChannel(rtc::ArrayView> x); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_ALIGNMENT_MIXER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/api_call_jitter_metrics.cc0000664000175000017500000001002514475643423031154 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/api_call_jitter_metrics.h" #include #include #include "modules/audio_processing/aec3/aec3_common.h" #include "system_wrappers/include/metrics.h" namespace webrtc { namespace { bool TimeToReportMetrics(int frames_since_last_report) { constexpr int kNumFramesPerSecond = 100; constexpr int kReportingIntervalFrames = 10 * kNumFramesPerSecond; return frames_since_last_report == kReportingIntervalFrames; } } // namespace ApiCallJitterMetrics::Jitter::Jitter() : max_(0), min_(std::numeric_limits::max()) {} void ApiCallJitterMetrics::Jitter::Update(int num_api_calls_in_a_row) { min_ = std::min(min_, num_api_calls_in_a_row); max_ = std::max(max_, num_api_calls_in_a_row); } void ApiCallJitterMetrics::Jitter::Reset() { min_ = std::numeric_limits::max(); max_ = 0; } void ApiCallJitterMetrics::Reset() { render_jitter_.Reset(); capture_jitter_.Reset(); num_api_calls_in_a_row_ = 0; frames_since_last_report_ = 0; last_call_was_render_ = false; proper_call_observed_ = false; } void ApiCallJitterMetrics::ReportRenderCall() { if (!last_call_was_render_) { // If the previous call was a capture and a proper call has been observed // (containing both render and capture data), storing the last number of // capture calls into the metrics. if (proper_call_observed_) { capture_jitter_.Update(num_api_calls_in_a_row_); } // Reset the call counter to start counting render calls. num_api_calls_in_a_row_ = 0; } ++num_api_calls_in_a_row_; last_call_was_render_ = true; } void ApiCallJitterMetrics::ReportCaptureCall() { if (last_call_was_render_) { // If the previous call was a render and a proper call has been observed // (containing both render and capture data), storing the last number of // render calls into the metrics. if (proper_call_observed_) { render_jitter_.Update(num_api_calls_in_a_row_); } // Reset the call counter to start counting capture calls. num_api_calls_in_a_row_ = 0; // If this statement is reached, at least one render and one capture call // have been observed. proper_call_observed_ = true; } ++num_api_calls_in_a_row_; last_call_was_render_ = false; // Only report and update jitter metrics for when a proper call, containing // both render and capture data, has been observed. if (proper_call_observed_ && TimeToReportMetrics(++frames_since_last_report_)) { // Report jitter, where the base basic unit is frames. constexpr int kMaxJitterToReport = 50; // Report max and min jitter for render and capture, in units of 20 ms. RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.MaxRenderJitter", std::min(kMaxJitterToReport, render_jitter().max()), 1, kMaxJitterToReport, kMaxJitterToReport); RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.MinRenderJitter", std::min(kMaxJitterToReport, render_jitter().min()), 1, kMaxJitterToReport, kMaxJitterToReport); RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.MaxCaptureJitter", std::min(kMaxJitterToReport, capture_jitter().max()), 1, kMaxJitterToReport, kMaxJitterToReport); RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.MinCaptureJitter", std::min(kMaxJitterToReport, capture_jitter().min()), 1, kMaxJitterToReport, kMaxJitterToReport); frames_since_last_report_ = 0; Reset(); } } bool ApiCallJitterMetrics::WillReportMetricsAtNextCapture() const { return TimeToReportMetrics(frames_since_last_report_ + 1); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/api_call_jitter_metrics.h0000664000175000017500000000314114475643423031017 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_API_CALL_JITTER_METRICS_H_ #define MODULES_AUDIO_PROCESSING_AEC3_API_CALL_JITTER_METRICS_H_ namespace webrtc { // Stores data for reporting metrics on the API call jitter. class ApiCallJitterMetrics { public: class Jitter { public: Jitter(); void Update(int num_api_calls_in_a_row); void Reset(); int min() const { return min_; } int max() const { return max_; } private: int max_; int min_; }; ApiCallJitterMetrics() { Reset(); } // Update metrics for render API call. void ReportRenderCall(); // Update and periodically report metrics for capture API call. void ReportCaptureCall(); // Methods used only for testing. const Jitter& render_jitter() const { return render_jitter_; } const Jitter& capture_jitter() const { return capture_jitter_; } bool WillReportMetricsAtNextCapture() const; private: void Reset(); Jitter render_jitter_; Jitter capture_jitter_; int num_api_calls_in_a_row_ = 0; int frames_since_last_report_ = 0; bool last_call_was_render_ = false; bool proper_call_observed_ = false; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_API_CALL_JITTER_METRICS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/block_buffer.cc0000664000175000017500000000227614475643423026735 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/block_buffer.h" #include namespace webrtc { BlockBuffer::BlockBuffer(size_t size, size_t num_bands, size_t num_channels, size_t frame_length) : size(static_cast(size)), buffer(size, std::vector>>( num_bands, std::vector>( num_channels, std::vector(frame_length, 0.f)))) { for (auto& block : buffer) { for (auto& band : block) { for (auto& channel : band) { std::fill(channel.begin(), channel.end(), 0.f); } } } } BlockBuffer::~BlockBuffer() = default; } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/block_buffer.h0000664000175000017500000000362414475643423026575 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_BLOCK_BUFFER_H_ #define MODULES_AUDIO_PROCESSING_AEC3_BLOCK_BUFFER_H_ #include #include #include "rtc_base/checks.h" namespace webrtc { // Struct for bundling a circular buffer of two dimensional vector objects // together with the read and write indices. struct BlockBuffer { BlockBuffer(size_t size, size_t num_bands, size_t num_channels, size_t frame_length); ~BlockBuffer(); int IncIndex(int index) const { RTC_DCHECK_EQ(buffer.size(), static_cast(size)); return index < size - 1 ? index + 1 : 0; } int DecIndex(int index) const { RTC_DCHECK_EQ(buffer.size(), static_cast(size)); return index > 0 ? index - 1 : size - 1; } int OffsetIndex(int index, int offset) const { RTC_DCHECK_EQ(buffer.size(), static_cast(size)); RTC_DCHECK_GE(size, offset); return (size + index + offset) % size; } void UpdateWriteIndex(int offset) { write = OffsetIndex(write, offset); } void IncWriteIndex() { write = IncIndex(write); } void DecWriteIndex() { write = DecIndex(write); } void UpdateReadIndex(int offset) { read = OffsetIndex(read, offset); } void IncReadIndex() { read = IncIndex(read); } void DecReadIndex() { read = DecIndex(read); } const int size; std::vector>>> buffer; int write = 0; int read = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_BLOCK_BUFFER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/block_delay_buffer.cc0000664000175000017500000000367314475643423030115 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/block_delay_buffer.h" #include "api/array_view.h" #include "rtc_base/checks.h" namespace webrtc { BlockDelayBuffer::BlockDelayBuffer(size_t num_channels, size_t num_bands, size_t frame_length, size_t delay_samples) : frame_length_(frame_length), delay_(delay_samples), buf_(num_channels, std::vector>(num_bands, std::vector(delay_, 0.f))) {} BlockDelayBuffer::~BlockDelayBuffer() = default; void BlockDelayBuffer::DelaySignal(AudioBuffer* frame) { RTC_DCHECK_EQ(buf_.size(), frame->num_channels()); if (delay_ == 0) { return; } const size_t num_bands = buf_[0].size(); const size_t num_channels = buf_.size(); const size_t i_start = last_insert_; size_t i = 0; for (size_t ch = 0; ch < num_channels; ++ch) { RTC_DCHECK_EQ(buf_[ch].size(), frame->num_bands()); RTC_DCHECK_EQ(buf_[ch].size(), num_bands); rtc::ArrayView frame_ch(frame->split_bands(ch), num_bands); for (size_t band = 0; band < num_bands; ++band) { RTC_DCHECK_EQ(delay_, buf_[ch][band].size()); i = i_start; for (size_t k = 0; k < frame_length_; ++k) { const float tmp = buf_[ch][band][i]; buf_[ch][band][i] = frame_ch[band][k]; frame_ch[band][k] = tmp; i = i < delay_ - 1 ? i + 1 : 0; } } } last_insert_ = i; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/block_delay_buffer.h0000664000175000017500000000243514475643423027752 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_BLOCK_DELAY_BUFFER_H_ #define MODULES_AUDIO_PROCESSING_AEC3_BLOCK_DELAY_BUFFER_H_ #include #include #include "modules/audio_processing/audio_buffer.h" namespace webrtc { // Class for applying a fixed delay to the samples in a signal partitioned using // the audiobuffer band-splitting scheme. class BlockDelayBuffer { public: BlockDelayBuffer(size_t num_channels, size_t num_bands, size_t frame_length, size_t delay_samples); ~BlockDelayBuffer(); // Delays the samples by the specified delay. void DelaySignal(AudioBuffer* frame); private: const size_t frame_length_; const size_t delay_; std::vector>> buf_; size_t last_insert_ = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_BLOCK_DELAY_BUFFER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/block_framer.cc0000664000175000017500000000653214475643423026737 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/block_framer.h" #include #include "modules/audio_processing/aec3/aec3_common.h" #include "rtc_base/checks.h" namespace webrtc { BlockFramer::BlockFramer(size_t num_bands, size_t num_channels) : num_bands_(num_bands), num_channels_(num_channels), buffer_(num_bands_, std::vector>( num_channels, std::vector(kBlockSize, 0.f))) { RTC_DCHECK_LT(0, num_bands); RTC_DCHECK_LT(0, num_channels); } BlockFramer::~BlockFramer() = default; // All the constants are chosen so that the buffer is either empty or has enough // samples for InsertBlockAndExtractSubFrame to produce a frame. In order to // achieve this, the InsertBlockAndExtractSubFrame and InsertBlock methods need // to be called in the correct order. void BlockFramer::InsertBlock( const std::vector>>& block) { RTC_DCHECK_EQ(num_bands_, block.size()); for (size_t band = 0; band < num_bands_; ++band) { RTC_DCHECK_EQ(num_channels_, block[band].size()); for (size_t channel = 0; channel < num_channels_; ++channel) { RTC_DCHECK_EQ(kBlockSize, block[band][channel].size()); RTC_DCHECK_EQ(0, buffer_[band][channel].size()); buffer_[band][channel].insert(buffer_[band][channel].begin(), block[band][channel].begin(), block[band][channel].end()); } } } void BlockFramer::InsertBlockAndExtractSubFrame( const std::vector>>& block, std::vector>>* sub_frame) { RTC_DCHECK(sub_frame); RTC_DCHECK_EQ(num_bands_, block.size()); RTC_DCHECK_EQ(num_bands_, sub_frame->size()); for (size_t band = 0; band < num_bands_; ++band) { RTC_DCHECK_EQ(num_channels_, block[band].size()); RTC_DCHECK_EQ(num_channels_, (*sub_frame)[0].size()); for (size_t channel = 0; channel < num_channels_; ++channel) { RTC_DCHECK_LE(kSubFrameLength, buffer_[band][channel].size() + kBlockSize); RTC_DCHECK_EQ(kBlockSize, block[band][channel].size()); RTC_DCHECK_GE(kBlockSize, buffer_[band][channel].size()); RTC_DCHECK_EQ(kSubFrameLength, (*sub_frame)[band][channel].size()); const int samples_to_frame = kSubFrameLength - buffer_[band][channel].size(); std::copy(buffer_[band][channel].begin(), buffer_[band][channel].end(), (*sub_frame)[band][channel].begin()); std::copy( block[band][channel].begin(), block[band][channel].begin() + samples_to_frame, (*sub_frame)[band][channel].begin() + buffer_[band][channel].size()); buffer_[band][channel].clear(); buffer_[band][channel].insert( buffer_[band][channel].begin(), block[band][channel].begin() + samples_to_frame, block[band][channel].end()); } } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/block_framer.h0000664000175000017500000000353614475643423026602 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_BLOCK_FRAMER_H_ #define MODULES_AUDIO_PROCESSING_AEC3_BLOCK_FRAMER_H_ #include #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" namespace webrtc { // Class for producing frames consisting of 2 subframes of 80 samples each // from 64 sample blocks. The class is designed to work together with the // FrameBlocker class which performs the reverse conversion. Used together with // that, this class produces output frames are the same rate as frames are // received by the FrameBlocker class. Note that the internal buffers will // overrun if any other rate of packets insertion is used. class BlockFramer { public: BlockFramer(size_t num_bands, size_t num_channels); ~BlockFramer(); BlockFramer(const BlockFramer&) = delete; BlockFramer& operator=(const BlockFramer&) = delete; // Adds a 64 sample block into the data that will form the next output frame. void InsertBlock(const std::vector>>& block); // Adds a 64 sample block and extracts an 80 sample subframe. void InsertBlockAndExtractSubFrame( const std::vector>>& block, std::vector>>* sub_frame); private: const size_t num_bands_; const size_t num_channels_; std::vector>> buffer_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_BLOCK_FRAMER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/block_processor.cc0000664000175000017500000002644014475643423027502 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/block_processor.h" #include #include #include #include #include "absl/types/optional.h" #include "api/audio/echo_canceller3_config.h" #include "api/audio/echo_control.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/block_processor_metrics.h" #include "modules/audio_processing/aec3/delay_estimate.h" #include "modules/audio_processing/aec3/echo_path_variability.h" #include "modules/audio_processing/aec3/echo_remover.h" #include "modules/audio_processing/aec3/render_delay_buffer.h" #include "modules/audio_processing/aec3/render_delay_controller.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/atomic_ops.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" namespace webrtc { namespace { enum class BlockProcessorApiCall { kCapture, kRender }; class BlockProcessorImpl final : public BlockProcessor { public: BlockProcessorImpl(const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels, size_t num_capture_channels, std::unique_ptr render_buffer, std::unique_ptr delay_controller, std::unique_ptr echo_remover); BlockProcessorImpl() = delete; ~BlockProcessorImpl() override; void ProcessCapture( bool echo_path_gain_change, bool capture_signal_saturation, std::vector>>* linear_output, std::vector>>* capture_block) override; void BufferRender( const std::vector>>& block) override; void UpdateEchoLeakageStatus(bool leakage_detected) override; void GetMetrics(EchoControl::Metrics* metrics) const override; void SetAudioBufferDelay(int delay_ms) override; private: static int instance_count_; std::unique_ptr data_dumper_; const EchoCanceller3Config config_; bool capture_properly_started_ = false; bool render_properly_started_ = false; const size_t sample_rate_hz_; std::unique_ptr render_buffer_; std::unique_ptr delay_controller_; std::unique_ptr echo_remover_; BlockProcessorMetrics metrics_; RenderDelayBuffer::BufferingEvent render_event_; size_t capture_call_counter_ = 0; absl::optional estimated_delay_; }; int BlockProcessorImpl::instance_count_ = 0; BlockProcessorImpl::BlockProcessorImpl( const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels, size_t num_capture_channels, std::unique_ptr render_buffer, std::unique_ptr delay_controller, std::unique_ptr echo_remover) : data_dumper_( new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), config_(config), sample_rate_hz_(sample_rate_hz), render_buffer_(std::move(render_buffer)), delay_controller_(std::move(delay_controller)), echo_remover_(std::move(echo_remover)), render_event_(RenderDelayBuffer::BufferingEvent::kNone) { RTC_DCHECK(ValidFullBandRate(sample_rate_hz_)); } BlockProcessorImpl::~BlockProcessorImpl() = default; void BlockProcessorImpl::ProcessCapture( bool echo_path_gain_change, bool capture_signal_saturation, std::vector>>* linear_output, std::vector>>* capture_block) { RTC_DCHECK(capture_block); RTC_DCHECK_EQ(NumBandsForRate(sample_rate_hz_), capture_block->size()); RTC_DCHECK_EQ(kBlockSize, (*capture_block)[0][0].size()); capture_call_counter_++; data_dumper_->DumpRaw("aec3_processblock_call_order", static_cast(BlockProcessorApiCall::kCapture)); data_dumper_->DumpWav("aec3_processblock_capture_input", kBlockSize, &(*capture_block)[0][0][0], 16000, 1); if (render_properly_started_) { if (!capture_properly_started_) { capture_properly_started_ = true; render_buffer_->Reset(); if (delay_controller_) delay_controller_->Reset(true); } } else { // If no render data has yet arrived, do not process the capture signal. render_buffer_->HandleSkippedCaptureProcessing(); return; } EchoPathVariability echo_path_variability( echo_path_gain_change, EchoPathVariability::DelayAdjustment::kNone, false); if (render_event_ == RenderDelayBuffer::BufferingEvent::kRenderOverrun && render_properly_started_) { echo_path_variability.delay_change = EchoPathVariability::DelayAdjustment::kBufferFlush; if (delay_controller_) delay_controller_->Reset(true); RTC_LOG(LS_WARNING) << "Reset due to render buffer overrun at block " << capture_call_counter_; } render_event_ = RenderDelayBuffer::BufferingEvent::kNone; // Update the render buffers with any newly arrived render blocks and prepare // the render buffers for reading the render data corresponding to the current // capture block. RenderDelayBuffer::BufferingEvent buffer_event = render_buffer_->PrepareCaptureProcessing(); // Reset the delay controller at render buffer underrun. if (buffer_event == RenderDelayBuffer::BufferingEvent::kRenderUnderrun) { if (delay_controller_) delay_controller_->Reset(false); } data_dumper_->DumpWav("aec3_processblock_capture_input2", kBlockSize, &(*capture_block)[0][0][0], 16000, 1); bool has_delay_estimator = !config_.delay.use_external_delay_estimator; if (has_delay_estimator) { RTC_DCHECK(delay_controller_); // Compute and apply the render delay required to achieve proper signal // alignment. estimated_delay_ = delay_controller_->GetDelay( render_buffer_->GetDownsampledRenderBuffer(), render_buffer_->Delay(), (*capture_block)[0]); if (estimated_delay_) { bool delay_change = render_buffer_->AlignFromDelay(estimated_delay_->delay); if (delay_change) { rtc::LoggingSeverity log_level = config_.delay.log_warning_on_delay_changes ? rtc::LS_WARNING : rtc::LS_INFO; RTC_LOG_V(log_level) << "Delay changed to " << estimated_delay_->delay << " at block " << capture_call_counter_; echo_path_variability.delay_change = EchoPathVariability::DelayAdjustment::kNewDetectedDelay; } } echo_path_variability.clock_drift = delay_controller_->HasClockdrift(); } else { render_buffer_->AlignFromExternalDelay(); } // Remove the echo from the capture signal. if (has_delay_estimator || render_buffer_->HasReceivedBufferDelay()) { echo_remover_->ProcessCapture( echo_path_variability, capture_signal_saturation, estimated_delay_, render_buffer_->GetRenderBuffer(), linear_output, capture_block); } // Update the metrics. metrics_.UpdateCapture(false); } void BlockProcessorImpl::BufferRender( const std::vector>>& block) { RTC_DCHECK_EQ(NumBandsForRate(sample_rate_hz_), block.size()); RTC_DCHECK_EQ(kBlockSize, block[0][0].size()); data_dumper_->DumpRaw("aec3_processblock_call_order", static_cast(BlockProcessorApiCall::kRender)); data_dumper_->DumpWav("aec3_processblock_render_input", kBlockSize, &block[0][0][0], 16000, 1); data_dumper_->DumpWav("aec3_processblock_render_input2", kBlockSize, &block[0][0][0], 16000, 1); render_event_ = render_buffer_->Insert(block); metrics_.UpdateRender(render_event_ != RenderDelayBuffer::BufferingEvent::kNone); render_properly_started_ = true; if (delay_controller_) delay_controller_->LogRenderCall(); } void BlockProcessorImpl::UpdateEchoLeakageStatus(bool leakage_detected) { echo_remover_->UpdateEchoLeakageStatus(leakage_detected); } void BlockProcessorImpl::GetMetrics(EchoControl::Metrics* metrics) const { echo_remover_->GetMetrics(metrics); constexpr int block_size_ms = 4; absl::optional delay = render_buffer_->Delay(); metrics->delay_ms = delay ? static_cast(*delay) * block_size_ms : 0; } void BlockProcessorImpl::SetAudioBufferDelay(int delay_ms) { render_buffer_->SetAudioBufferDelay(delay_ms); } } // namespace BlockProcessor* BlockProcessor::Create(const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels, size_t num_capture_channels) { std::unique_ptr render_buffer( RenderDelayBuffer::Create(config, sample_rate_hz, num_render_channels)); std::unique_ptr delay_controller; if (!config.delay.use_external_delay_estimator) { delay_controller.reset(RenderDelayController::Create(config, sample_rate_hz, num_capture_channels)); } std::unique_ptr echo_remover(EchoRemover::Create( config, sample_rate_hz, num_render_channels, num_capture_channels)); return Create(config, sample_rate_hz, num_render_channels, num_capture_channels, std::move(render_buffer), std::move(delay_controller), std::move(echo_remover)); } BlockProcessor* BlockProcessor::Create( const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels, size_t num_capture_channels, std::unique_ptr render_buffer) { std::unique_ptr delay_controller; if (!config.delay.use_external_delay_estimator) { delay_controller.reset(RenderDelayController::Create(config, sample_rate_hz, num_capture_channels)); } std::unique_ptr echo_remover(EchoRemover::Create( config, sample_rate_hz, num_render_channels, num_capture_channels)); return Create(config, sample_rate_hz, num_render_channels, num_capture_channels, std::move(render_buffer), std::move(delay_controller), std::move(echo_remover)); } BlockProcessor* BlockProcessor::Create( const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels, size_t num_capture_channels, std::unique_ptr render_buffer, std::unique_ptr delay_controller, std::unique_ptr echo_remover) { return new BlockProcessorImpl(config, sample_rate_hz, num_render_channels, num_capture_channels, std::move(render_buffer), std::move(delay_controller), std::move(echo_remover)); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/block_processor.h0000664000175000017500000000535314475643423027344 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_BLOCK_PROCESSOR_H_ #define MODULES_AUDIO_PROCESSING_AEC3_BLOCK_PROCESSOR_H_ #include #include #include #include "api/audio/echo_canceller3_config.h" #include "api/audio/echo_control.h" #include "modules/audio_processing/aec3/echo_remover.h" #include "modules/audio_processing/aec3/render_delay_buffer.h" #include "modules/audio_processing/aec3/render_delay_controller.h" namespace webrtc { // Class for performing echo cancellation on 64 sample blocks of audio data. class BlockProcessor { public: static BlockProcessor* Create(const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels, size_t num_capture_channels); // Only used for testing purposes. static BlockProcessor* Create( const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels, size_t num_capture_channels, std::unique_ptr render_buffer); static BlockProcessor* Create( const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels, size_t num_capture_channels, std::unique_ptr render_buffer, std::unique_ptr delay_controller, std::unique_ptr echo_remover); virtual ~BlockProcessor() = default; // Get current metrics. virtual void GetMetrics(EchoControl::Metrics* metrics) const = 0; // Provides an optional external estimate of the audio buffer delay. virtual void SetAudioBufferDelay(int delay_ms) = 0; // Processes a block of capture data. virtual void ProcessCapture( bool echo_path_gain_change, bool capture_signal_saturation, std::vector>>* linear_output, std::vector>>* capture_block) = 0; // Buffers a block of render data supplied by a FrameBlocker object. virtual void BufferRender( const std::vector>>& render_block) = 0; // Reports whether echo leakage has been detected in the echo canceller // output. virtual void UpdateEchoLeakageStatus(bool leakage_detected) = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_BLOCK_PROCESSOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/block_processor_metrics.cc0000664000175000017500000000572714475643423031235 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/block_processor_metrics.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "rtc_base/checks.h" #include "system_wrappers/include/metrics.h" namespace webrtc { namespace { enum class RenderUnderrunCategory { kNone, kFew, kSeveral, kMany, kConstant, kNumCategories }; enum class RenderOverrunCategory { kNone, kFew, kSeveral, kMany, kConstant, kNumCategories }; } // namespace void BlockProcessorMetrics::UpdateCapture(bool underrun) { ++capture_block_counter_; if (underrun) { ++render_buffer_underruns_; } if (capture_block_counter_ == kMetricsReportingIntervalBlocks) { metrics_reported_ = true; RenderUnderrunCategory underrun_category; if (render_buffer_underruns_ == 0) { underrun_category = RenderUnderrunCategory::kNone; } else if (render_buffer_underruns_ > (capture_block_counter_ >> 1)) { underrun_category = RenderUnderrunCategory::kConstant; } else if (render_buffer_underruns_ > 100) { underrun_category = RenderUnderrunCategory::kMany; } else if (render_buffer_underruns_ > 10) { underrun_category = RenderUnderrunCategory::kSeveral; } else { underrun_category = RenderUnderrunCategory::kFew; } RTC_HISTOGRAM_ENUMERATION( "WebRTC.Audio.EchoCanceller.RenderUnderruns", static_cast(underrun_category), static_cast(RenderUnderrunCategory::kNumCategories)); RenderOverrunCategory overrun_category; if (render_buffer_overruns_ == 0) { overrun_category = RenderOverrunCategory::kNone; } else if (render_buffer_overruns_ > (buffer_render_calls_ >> 1)) { overrun_category = RenderOverrunCategory::kConstant; } else if (render_buffer_overruns_ > 100) { overrun_category = RenderOverrunCategory::kMany; } else if (render_buffer_overruns_ > 10) { overrun_category = RenderOverrunCategory::kSeveral; } else { overrun_category = RenderOverrunCategory::kFew; } RTC_HISTOGRAM_ENUMERATION( "WebRTC.Audio.EchoCanceller.RenderOverruns", static_cast(overrun_category), static_cast(RenderOverrunCategory::kNumCategories)); ResetMetrics(); capture_block_counter_ = 0; } else { metrics_reported_ = false; } } void BlockProcessorMetrics::UpdateRender(bool overrun) { ++buffer_render_calls_; if (overrun) { ++render_buffer_overruns_; } } void BlockProcessorMetrics::ResetMetrics() { render_buffer_underruns_ = 0; render_buffer_overruns_ = 0; buffer_render_calls_ = 0; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/block_processor_metrics.h0000664000175000017500000000262014475643423031064 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_BLOCK_PROCESSOR_METRICS_H_ #define MODULES_AUDIO_PROCESSING_AEC3_BLOCK_PROCESSOR_METRICS_H_ #include "rtc_base/constructor_magic.h" namespace webrtc { // Handles the reporting of metrics for the block_processor. class BlockProcessorMetrics { public: BlockProcessorMetrics() = default; // Updates the metric with new capture data. void UpdateCapture(bool underrun); // Updates the metric with new render data. void UpdateRender(bool overrun); // Returns true if the metrics have just been reported, otherwise false. bool MetricsReported() { return metrics_reported_; } private: // Resets the metrics. void ResetMetrics(); int capture_block_counter_ = 0; bool metrics_reported_ = false; int render_buffer_underruns_ = 0; int render_buffer_overruns_ = 0; int buffer_render_calls_ = 0; RTC_DISALLOW_COPY_AND_ASSIGN(BlockProcessorMetrics); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_BLOCK_PROCESSOR_METRICS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/clockdrift_detector.cc0000664000175000017500000000374714475643423030333 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/clockdrift_detector.h" namespace webrtc { ClockdriftDetector::ClockdriftDetector() : level_(Level::kNone), stability_counter_(0) { delay_history_.fill(0); } ClockdriftDetector::~ClockdriftDetector() = default; void ClockdriftDetector::Update(int delay_estimate) { if (delay_estimate == delay_history_[0]) { // Reset clockdrift level if delay estimate is stable for 7500 blocks (30 // seconds). if (++stability_counter_ > 7500) level_ = Level::kNone; return; } stability_counter_ = 0; const int d1 = delay_history_[0] - delay_estimate; const int d2 = delay_history_[1] - delay_estimate; const int d3 = delay_history_[2] - delay_estimate; // Patterns recognized as positive clockdrift: // [x-3], x-2, x-1, x. // [x-3], x-1, x-2, x. const bool probable_drift_up = (d1 == -1 && d2 == -2) || (d1 == -2 && d2 == -1); const bool drift_up = probable_drift_up && d3 == -3; // Patterns recognized as negative clockdrift: // [x+3], x+2, x+1, x. // [x+3], x+1, x+2, x. const bool probable_drift_down = (d1 == 1 && d2 == 2) || (d1 == 2 && d2 == 1); const bool drift_down = probable_drift_down && d3 == 3; // Set clockdrift level. if (drift_up || drift_down) { level_ = Level::kVerified; } else if ((probable_drift_up || probable_drift_down) && level_ == Level::kNone) { level_ = Level::kProbable; } // Shift delay history one step. delay_history_[2] = delay_history_[1]; delay_history_[1] = delay_history_[0]; delay_history_[0] = delay_estimate; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/clockdrift_detector.h0000664000175000017500000000220614475643423030162 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_CLOCKDRIFT_DETECTOR_H_ #define MODULES_AUDIO_PROCESSING_AEC3_CLOCKDRIFT_DETECTOR_H_ #include #include namespace webrtc { class ApmDataDumper; struct DownsampledRenderBuffer; struct EchoCanceller3Config; // Detects clockdrift by analyzing the estimated delay. class ClockdriftDetector { public: enum class Level { kNone, kProbable, kVerified, kNumCategories }; ClockdriftDetector(); ~ClockdriftDetector(); void Update(int delay_estimate); Level ClockdriftLevel() const { return level_; } private: std::array delay_history_; Level level_; size_t stability_counter_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_CLOCKDRIFT_DETECTOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/coarse_filter_update_gain.cc0000664000175000017500000000624414475643423031472 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/coarse_filter_update_gain.h" #include #include #include "rtc_base/checks.h" namespace webrtc { CoarseFilterUpdateGain::CoarseFilterUpdateGain( const EchoCanceller3Config::Filter::CoarseConfiguration& config, size_t config_change_duration_blocks) : config_change_duration_blocks_( static_cast(config_change_duration_blocks)) { SetConfig(config, true); RTC_DCHECK_LT(0, config_change_duration_blocks_); one_by_config_change_duration_blocks_ = 1.f / config_change_duration_blocks_; } void CoarseFilterUpdateGain::HandleEchoPathChange() { poor_signal_excitation_counter_ = 0; call_counter_ = 0; } void CoarseFilterUpdateGain::Compute( const std::array& render_power, const RenderSignalAnalyzer& render_signal_analyzer, const FftData& E_coarse, size_t size_partitions, bool saturated_capture_signal, FftData* G) { RTC_DCHECK(G); ++call_counter_; UpdateCurrentConfig(); if (render_signal_analyzer.PoorSignalExcitation()) { poor_signal_excitation_counter_ = 0; } // Do not update the filter if the render is not sufficiently excited. if (++poor_signal_excitation_counter_ < size_partitions || saturated_capture_signal || call_counter_ <= size_partitions) { G->re.fill(0.f); G->im.fill(0.f); return; } // Compute mu. std::array mu; const auto& X2 = render_power; for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { if (X2[k] > current_config_.noise_gate) { mu[k] = current_config_.rate / X2[k]; } else { mu[k] = 0.f; } } // Avoid updating the filter close to narrow bands in the render signals. render_signal_analyzer.MaskRegionsAroundNarrowBands(&mu); // G = mu * E * X2. for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { G->re[k] = mu[k] * E_coarse.re[k]; G->im[k] = mu[k] * E_coarse.im[k]; } } void CoarseFilterUpdateGain::UpdateCurrentConfig() { RTC_DCHECK_GE(config_change_duration_blocks_, config_change_counter_); if (config_change_counter_ > 0) { if (--config_change_counter_ > 0) { auto average = [](float from, float to, float from_weight) { return from * from_weight + to * (1.f - from_weight); }; float change_factor = config_change_counter_ * one_by_config_change_duration_blocks_; current_config_.rate = average(old_target_config_.rate, target_config_.rate, change_factor); current_config_.noise_gate = average(old_target_config_.noise_gate, target_config_.noise_gate, change_factor); } else { current_config_ = old_target_config_ = target_config_; } } RTC_DCHECK_LE(0, config_change_counter_); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/coarse_filter_update_gain.h0000664000175000017500000000503614475643423031332 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_COARSE_FILTER_UPDATE_GAIN_H_ #define MODULES_AUDIO_PROCESSING_AEC3_COARSE_FILTER_UPDATE_GAIN_H_ #include #include #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/fft_data.h" #include "modules/audio_processing/aec3/render_signal_analyzer.h" namespace webrtc { // Provides functionality for computing the fixed gain for the coarse filter. class CoarseFilterUpdateGain { public: explicit CoarseFilterUpdateGain( const EchoCanceller3Config::Filter::CoarseConfiguration& config, size_t config_change_duration_blocks); // Takes action in the case of a known echo path change. void HandleEchoPathChange(); // Computes the gain. void Compute(const std::array& render_power, const RenderSignalAnalyzer& render_signal_analyzer, const FftData& E_coarse, size_t size_partitions, bool saturated_capture_signal, FftData* G); // Sets a new config. void SetConfig( const EchoCanceller3Config::Filter::CoarseConfiguration& config, bool immediate_effect) { if (immediate_effect) { old_target_config_ = current_config_ = target_config_ = config; config_change_counter_ = 0; } else { old_target_config_ = current_config_; target_config_ = config; config_change_counter_ = config_change_duration_blocks_; } } private: EchoCanceller3Config::Filter::CoarseConfiguration current_config_; EchoCanceller3Config::Filter::CoarseConfiguration target_config_; EchoCanceller3Config::Filter::CoarseConfiguration old_target_config_; const int config_change_duration_blocks_; float one_by_config_change_duration_blocks_; // TODO(peah): Check whether this counter should instead be initialized to a // large value. size_t poor_signal_excitation_counter_ = 0; size_t call_counter_ = 0; int config_change_counter_ = 0; void UpdateCurrentConfig(); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_COARSE_FILTER_UPDATE_GAIN_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/comfort_noise_generator.cc0000664000175000017500000001510214475643423031216 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/comfort_noise_generator.h" // Defines WEBRTC_ARCH_X86_FAMILY, used below. #include "rtc_base/system/arch.h" #if defined(WEBRTC_ARCH_X86_FAMILY) #include #endif #include #include #include #include #include #include #include "common_audio/signal_processing/include/signal_processing_library.h" #include "modules/audio_processing/aec3/vector_math.h" #include "rtc_base/checks.h" namespace webrtc { namespace { // Computes the noise floor value that matches a WGN input of noise_floor_dbfs. float GetNoiseFloorFactor(float noise_floor_dbfs) { // kdBfsNormalization = 20.f*log10(32768.f). constexpr float kdBfsNormalization = 90.30899869919436f; return 64.f * powf(10.f, (kdBfsNormalization + noise_floor_dbfs) * 0.1f); } // Table of sqrt(2) * sin(2*pi*i/32). constexpr float kSqrt2Sin[32] = { +0.0000000f, +0.2758994f, +0.5411961f, +0.7856950f, +1.0000000f, +1.1758756f, +1.3065630f, +1.3870398f, +1.4142136f, +1.3870398f, +1.3065630f, +1.1758756f, +1.0000000f, +0.7856950f, +0.5411961f, +0.2758994f, +0.0000000f, -0.2758994f, -0.5411961f, -0.7856950f, -1.0000000f, -1.1758756f, -1.3065630f, -1.3870398f, -1.4142136f, -1.3870398f, -1.3065630f, -1.1758756f, -1.0000000f, -0.7856950f, -0.5411961f, -0.2758994f}; void GenerateComfortNoise(Aec3Optimization optimization, const std::array& N2, uint32_t* seed, FftData* lower_band_noise, FftData* upper_band_noise) { FftData* N_low = lower_band_noise; FftData* N_high = upper_band_noise; // Compute square root spectrum. std::array N; std::copy(N2.begin(), N2.end(), N.begin()); aec3::VectorMath(optimization).Sqrt(N); // Compute the noise level for the upper bands. constexpr float kOneByNumBands = 1.f / (kFftLengthBy2Plus1 / 2 + 1); constexpr int kFftLengthBy2Plus1By2 = kFftLengthBy2Plus1 / 2; const float high_band_noise_level = std::accumulate(N.begin() + kFftLengthBy2Plus1By2, N.end(), 0.f) * kOneByNumBands; // The analysis and synthesis windowing cause loss of power when // cross-fading the noise where frames are completely uncorrelated // (generated with random phase), hence the factor sqrt(2). // This is not the case for the speech signal where the input is overlapping // (strong correlation). N_low->re[0] = N_low->re[kFftLengthBy2] = N_high->re[0] = N_high->re[kFftLengthBy2] = 0.f; for (size_t k = 1; k < kFftLengthBy2; k++) { constexpr int kIndexMask = 32 - 1; // Generate a random 31-bit integer. seed[0] = (seed[0] * 69069 + 1) & (0x80000000 - 1); // Convert to a 5-bit index. int i = seed[0] >> 26; // y = sqrt(2) * sin(a) const float x = kSqrt2Sin[i]; // x = sqrt(2) * cos(a) = sqrt(2) * sin(a + pi/2) const float y = kSqrt2Sin[(i + 8) & kIndexMask]; // Form low-frequency noise via spectral shaping. N_low->re[k] = N[k] * x; N_low->im[k] = N[k] * y; // Form the high-frequency noise via simple levelling. N_high->re[k] = high_band_noise_level * x; N_high->im[k] = high_band_noise_level * y; } } } // namespace ComfortNoiseGenerator::ComfortNoiseGenerator(const EchoCanceller3Config& config, Aec3Optimization optimization, size_t num_capture_channels) : optimization_(optimization), seed_(42), num_capture_channels_(num_capture_channels), noise_floor_(GetNoiseFloorFactor(config.comfort_noise.noise_floor_dbfs)), N2_initial_( std::make_unique>>( num_capture_channels_)), Y2_smoothed_(num_capture_channels_), N2_(num_capture_channels_) { for (size_t ch = 0; ch < num_capture_channels_; ++ch) { (*N2_initial_)[ch].fill(0.f); Y2_smoothed_[ch].fill(0.f); N2_[ch].fill(1.0e6f); } } ComfortNoiseGenerator::~ComfortNoiseGenerator() = default; void ComfortNoiseGenerator::Compute( bool saturated_capture, rtc::ArrayView> capture_spectrum, rtc::ArrayView lower_band_noise, rtc::ArrayView upper_band_noise) { const auto& Y2 = capture_spectrum; if (!saturated_capture) { // Smooth Y2. for (size_t ch = 0; ch < num_capture_channels_; ++ch) { std::transform(Y2_smoothed_[ch].begin(), Y2_smoothed_[ch].end(), Y2[ch].begin(), Y2_smoothed_[ch].begin(), [](float a, float b) { return a + 0.1f * (b - a); }); } if (N2_counter_ > 50) { // Update N2 from Y2_smoothed. for (size_t ch = 0; ch < num_capture_channels_; ++ch) { std::transform(N2_[ch].begin(), N2_[ch].end(), Y2_smoothed_[ch].begin(), N2_[ch].begin(), [](float a, float b) { return b < a ? (0.9f * b + 0.1f * a) * 1.0002f : a * 1.0002f; }); } } if (N2_initial_) { if (++N2_counter_ == 1000) { N2_initial_.reset(); } else { // Compute the N2_initial from N2. for (size_t ch = 0; ch < num_capture_channels_; ++ch) { std::transform(N2_[ch].begin(), N2_[ch].end(), (*N2_initial_)[ch].begin(), (*N2_initial_)[ch].begin(), [](float a, float b) { return a > b ? b + 0.001f * (a - b) : a; }); } } } for (size_t ch = 0; ch < num_capture_channels_; ++ch) { for (auto& n : N2_[ch]) { n = std::max(n, noise_floor_); } if (N2_initial_) { for (auto& n : (*N2_initial_)[ch]) { n = std::max(n, noise_floor_); } } } } // Choose N2 estimate to use. const auto& N2 = N2_initial_ ? (*N2_initial_) : N2_; for (size_t ch = 0; ch < num_capture_channels_; ++ch) { GenerateComfortNoise(optimization_, N2[ch], &seed_, &lower_band_noise[ch], &upper_band_noise[ch]); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/comfort_noise_generator.h0000664000175000017500000000523514475643423031066 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_COMFORT_NOISE_GENERATOR_H_ #define MODULES_AUDIO_PROCESSING_AEC3_COMFORT_NOISE_GENERATOR_H_ #include #include #include #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/aec_state.h" #include "modules/audio_processing/aec3/fft_data.h" #include "rtc_base/constructor_magic.h" #include "rtc_base/system/arch.h" namespace webrtc { namespace aec3 { #if defined(WEBRTC_ARCH_X86_FAMILY) void EstimateComfortNoise_SSE2(const std::array& N2, uint32_t* seed, FftData* lower_band_noise, FftData* upper_band_noise); #endif void EstimateComfortNoise(const std::array& N2, uint32_t* seed, FftData* lower_band_noise, FftData* upper_band_noise); } // namespace aec3 // Generates the comfort noise. class ComfortNoiseGenerator { public: ComfortNoiseGenerator(const EchoCanceller3Config& config, Aec3Optimization optimization, size_t num_capture_channels); ComfortNoiseGenerator() = delete; ~ComfortNoiseGenerator(); ComfortNoiseGenerator(const ComfortNoiseGenerator&) = delete; // Computes the comfort noise. void Compute(bool saturated_capture, rtc::ArrayView> capture_spectrum, rtc::ArrayView lower_band_noise, rtc::ArrayView upper_band_noise); // Returns the estimate of the background noise spectrum. rtc::ArrayView> NoiseSpectrum() const { return N2_; } private: const Aec3Optimization optimization_; uint32_t seed_; const size_t num_capture_channels_; const float noise_floor_; std::unique_ptr>> N2_initial_; std::vector> Y2_smoothed_; std::vector> N2_; int N2_counter_ = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_COMFORT_NOISE_GENERATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/decimator.cc0000664000175000017500000000734714475643423026265 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/decimator.h" #include #include #include "modules/audio_processing/aec3/aec3_common.h" #include "rtc_base/checks.h" namespace webrtc { namespace { // signal.butter(2, 3400/8000.0, 'lowpass', analog=False) const std::vector GetLowPassFilterDS2() { return std::vector{ {{-1.f, 0.f}, {0.13833231f, 0.40743176f}, 0.22711796393486466f}, {{-1.f, 0.f}, {0.13833231f, 0.40743176f}, 0.22711796393486466f}, {{-1.f, 0.f}, {0.13833231f, 0.40743176f}, 0.22711796393486466f}}; } // signal.ellip(6, 1, 40, 1800/8000, btype='lowpass', analog=False) const std::vector GetLowPassFilterDS4() { return std::vector{ {{-0.08873842f, 0.99605496f}, {0.75916227f, 0.23841065f}, 0.26250696827f}, {{0.62273832f, 0.78243018f}, {0.74892112f, 0.5410152f}, 0.26250696827f}, {{0.71107693f, 0.70311421f}, {0.74895534f, 0.63924616f}, 0.26250696827f}}; } // signal.cheby1(1, 6, [1000/8000, 2000/8000], btype='bandpass', analog=False) const std::vector GetBandPassFilterDS8() { return std::vector{ {{1.f, 0.f}, {0.7601815f, 0.46423542f}, 0.10330478266505948f, true}, {{1.f, 0.f}, {0.7601815f, 0.46423542f}, 0.10330478266505948f, true}, {{1.f, 0.f}, {0.7601815f, 0.46423542f}, 0.10330478266505948f, true}, {{1.f, 0.f}, {0.7601815f, 0.46423542f}, 0.10330478266505948f, true}, {{1.f, 0.f}, {0.7601815f, 0.46423542f}, 0.10330478266505948f, true}}; } // signal.butter(2, 1000/8000.0, 'highpass', analog=False) const std::vector GetHighPassFilter() { return std::vector{ {{1.f, 0.f}, {0.72712179f, 0.21296904f}, 0.7570763753338849f}}; } const std::vector GetPassThroughFilter() { return std::vector{}; } } // namespace Decimator::Decimator(size_t down_sampling_factor) : down_sampling_factor_(down_sampling_factor), anti_aliasing_filter_(down_sampling_factor_ == 4 ? GetLowPassFilterDS4() : (down_sampling_factor_ == 8 ? GetBandPassFilterDS8() : GetLowPassFilterDS2())), noise_reduction_filter_(down_sampling_factor_ == 8 ? GetPassThroughFilter() : GetHighPassFilter()) { RTC_DCHECK(down_sampling_factor_ == 2 || down_sampling_factor_ == 4 || down_sampling_factor_ == 8); } void Decimator::Decimate(rtc::ArrayView in, rtc::ArrayView out) { RTC_DCHECK_EQ(kBlockSize, in.size()); RTC_DCHECK_EQ(kBlockSize / down_sampling_factor_, out.size()); std::array x; // Limit the frequency content of the signal to avoid aliasing. anti_aliasing_filter_.Process(in, x); // Reduce the impact of near-end noise. noise_reduction_filter_.Process(x); // Downsample the signal. for (size_t j = 0, k = 0; j < out.size(); ++j, k += down_sampling_factor_) { RTC_DCHECK_GT(kBlockSize, k); out[j] = x[k]; } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/decimator.h0000664000175000017500000000236514475643423026122 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_DECIMATOR_H_ #define MODULES_AUDIO_PROCESSING_AEC3_DECIMATOR_H_ #include #include #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/utility/cascaded_biquad_filter.h" #include "rtc_base/constructor_magic.h" namespace webrtc { // Provides functionality for decimating a signal. class Decimator { public: explicit Decimator(size_t down_sampling_factor); // Downsamples the signal. void Decimate(rtc::ArrayView in, rtc::ArrayView out); private: const size_t down_sampling_factor_; CascadedBiQuadFilter anti_aliasing_filter_; CascadedBiQuadFilter noise_reduction_filter_; RTC_DISALLOW_COPY_AND_ASSIGN(Decimator); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_DECIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/delay_estimate.h0000664000175000017500000000164414475643423027143 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_DELAY_ESTIMATE_H_ #define MODULES_AUDIO_PROCESSING_AEC3_DELAY_ESTIMATE_H_ namespace webrtc { // Stores delay_estimates. struct DelayEstimate { enum class Quality { kCoarse, kRefined }; DelayEstimate(Quality quality, size_t delay) : quality(quality), delay(delay) {} Quality quality; size_t delay; size_t blocks_since_last_change = 0; size_t blocks_since_last_update = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_DELAY_ESTIMATE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/dominant_nearend_detector.cc0000664000175000017500000000576114475643423031512 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/dominant_nearend_detector.h" #include namespace webrtc { DominantNearendDetector::DominantNearendDetector( const EchoCanceller3Config::Suppressor::DominantNearendDetection& config, size_t num_capture_channels) : enr_threshold_(config.enr_threshold), enr_exit_threshold_(config.enr_exit_threshold), snr_threshold_(config.snr_threshold), hold_duration_(config.hold_duration), trigger_threshold_(config.trigger_threshold), use_during_initial_phase_(config.use_during_initial_phase), num_capture_channels_(num_capture_channels), trigger_counters_(num_capture_channels_), hold_counters_(num_capture_channels_) {} void DominantNearendDetector::Update( rtc::ArrayView> nearend_spectrum, rtc::ArrayView> residual_echo_spectrum, rtc::ArrayView> comfort_noise_spectrum, bool initial_state) { nearend_state_ = false; auto low_frequency_energy = [](rtc::ArrayView spectrum) { RTC_DCHECK_LE(16, spectrum.size()); return std::accumulate(spectrum.begin() + 1, spectrum.begin() + 16, 0.f); }; for (size_t ch = 0; ch < num_capture_channels_; ++ch) { const float ne_sum = low_frequency_energy(nearend_spectrum[ch]); const float echo_sum = low_frequency_energy(residual_echo_spectrum[ch]); const float noise_sum = low_frequency_energy(comfort_noise_spectrum[ch]); // Detect strong active nearend if the nearend is sufficiently stronger than // the echo and the nearend noise. if ((!initial_state || use_during_initial_phase_) && echo_sum < enr_threshold_ * ne_sum && ne_sum > snr_threshold_ * noise_sum) { if (++trigger_counters_[ch] >= trigger_threshold_) { // After a period of strong active nearend activity, flag nearend mode. hold_counters_[ch] = hold_duration_; trigger_counters_[ch] = trigger_threshold_; } } else { // Forget previously detected strong active nearend activity. trigger_counters_[ch] = std::max(0, trigger_counters_[ch] - 1); } // Exit nearend-state early at strong echo. if (echo_sum > enr_exit_threshold_ * ne_sum && echo_sum > snr_threshold_ * noise_sum) { hold_counters_[ch] = 0; } // Remain in any nearend mode for a certain duration. hold_counters_[ch] = std::max(0, hold_counters_[ch] - 1); nearend_state_ = nearend_state_ || hold_counters_[ch] > 0; } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/dominant_nearend_detector.h0000664000175000017500000000377114475643423031353 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_DOMINANT_NEAREND_DETECTOR_H_ #define MODULES_AUDIO_PROCESSING_AEC3_DOMINANT_NEAREND_DETECTOR_H_ #include #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/nearend_detector.h" namespace webrtc { // Class for selecting whether the suppressor is in the nearend or echo state. class DominantNearendDetector : public NearendDetector { public: DominantNearendDetector( const EchoCanceller3Config::Suppressor::DominantNearendDetection& config, size_t num_capture_channels); // Returns whether the current state is the nearend state. bool IsNearendState() const override { return nearend_state_; } // Updates the state selection based on latest spectral estimates. void Update(rtc::ArrayView> nearend_spectrum, rtc::ArrayView> residual_echo_spectrum, rtc::ArrayView> comfort_noise_spectrum, bool initial_state) override; private: const float enr_threshold_; const float enr_exit_threshold_; const float snr_threshold_; const int hold_duration_; const int trigger_threshold_; const bool use_during_initial_phase_; const size_t num_capture_channels_; bool nearend_state_ = false; std::vector trigger_counters_; std::vector hold_counters_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_DOMINANT_NEAREND_DETECTOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/downsampled_render_buffer.cc0000664000175000017500000000151514475643423031512 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/downsampled_render_buffer.h" #include namespace webrtc { DownsampledRenderBuffer::DownsampledRenderBuffer(size_t downsampled_buffer_size) : size(static_cast(downsampled_buffer_size)), buffer(downsampled_buffer_size, 0.f) { std::fill(buffer.begin(), buffer.end(), 0.f); } DownsampledRenderBuffer::~DownsampledRenderBuffer() = default; } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/downsampled_render_buffer.h0000664000175000017500000000347414475643423031362 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_DOWNSAMPLED_RENDER_BUFFER_H_ #define MODULES_AUDIO_PROCESSING_AEC3_DOWNSAMPLED_RENDER_BUFFER_H_ #include #include #include "rtc_base/checks.h" namespace webrtc { // Holds the circular buffer of the downsampled render data. struct DownsampledRenderBuffer { explicit DownsampledRenderBuffer(size_t downsampled_buffer_size); ~DownsampledRenderBuffer(); int IncIndex(int index) const { RTC_DCHECK_EQ(buffer.size(), static_cast(size)); return index < size - 1 ? index + 1 : 0; } int DecIndex(int index) const { RTC_DCHECK_EQ(buffer.size(), static_cast(size)); return index > 0 ? index - 1 : size - 1; } int OffsetIndex(int index, int offset) const { RTC_DCHECK_GE(buffer.size(), offset); RTC_DCHECK_EQ(buffer.size(), static_cast(size)); return (size + index + offset) % size; } void UpdateWriteIndex(int offset) { write = OffsetIndex(write, offset); } void IncWriteIndex() { write = IncIndex(write); } void DecWriteIndex() { write = DecIndex(write); } void UpdateReadIndex(int offset) { read = OffsetIndex(read, offset); } void IncReadIndex() { read = IncIndex(read); } void DecReadIndex() { read = DecIndex(read); } const int size; std::vector buffer; int write = 0; int read = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_DOWNSAMPLED_RENDER_BUFFER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/echo_audibility.cc0000664000175000017500000001040614475643423027441 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/echo_audibility.h" #include #include #include #include #include "api/array_view.h" #include "modules/audio_processing/aec3/block_buffer.h" #include "modules/audio_processing/aec3/spectrum_buffer.h" #include "modules/audio_processing/aec3/stationarity_estimator.h" namespace webrtc { EchoAudibility::EchoAudibility(bool use_render_stationarity_at_init) : use_render_stationarity_at_init_(use_render_stationarity_at_init) { Reset(); } EchoAudibility::~EchoAudibility() = default; void EchoAudibility::Update(const RenderBuffer& render_buffer, rtc::ArrayView average_reverb, int delay_blocks, bool external_delay_seen) { UpdateRenderNoiseEstimator(render_buffer.GetSpectrumBuffer(), render_buffer.GetBlockBuffer(), external_delay_seen); if (external_delay_seen || use_render_stationarity_at_init_) { UpdateRenderStationarityFlags(render_buffer, average_reverb, delay_blocks); } } void EchoAudibility::Reset() { render_stationarity_.Reset(); non_zero_render_seen_ = false; render_spectrum_write_prev_ = absl::nullopt; } void EchoAudibility::UpdateRenderStationarityFlags( const RenderBuffer& render_buffer, rtc::ArrayView average_reverb, int min_channel_delay_blocks) { const SpectrumBuffer& spectrum_buffer = render_buffer.GetSpectrumBuffer(); int idx_at_delay = spectrum_buffer.OffsetIndex(spectrum_buffer.read, min_channel_delay_blocks); int num_lookahead = render_buffer.Headroom() - min_channel_delay_blocks + 1; num_lookahead = std::max(0, num_lookahead); render_stationarity_.UpdateStationarityFlags(spectrum_buffer, average_reverb, idx_at_delay, num_lookahead); } void EchoAudibility::UpdateRenderNoiseEstimator( const SpectrumBuffer& spectrum_buffer, const BlockBuffer& block_buffer, bool external_delay_seen) { if (!render_spectrum_write_prev_) { render_spectrum_write_prev_ = spectrum_buffer.write; render_block_write_prev_ = block_buffer.write; return; } int render_spectrum_write_current = spectrum_buffer.write; if (!non_zero_render_seen_ && !external_delay_seen) { non_zero_render_seen_ = !IsRenderTooLow(block_buffer); } if (non_zero_render_seen_) { for (int idx = render_spectrum_write_prev_.value(); idx != render_spectrum_write_current; idx = spectrum_buffer.DecIndex(idx)) { render_stationarity_.UpdateNoiseEstimator(spectrum_buffer.buffer[idx]); } } render_spectrum_write_prev_ = render_spectrum_write_current; } bool EchoAudibility::IsRenderTooLow(const BlockBuffer& block_buffer) { const int num_render_channels = static_cast(block_buffer.buffer[0][0].size()); bool too_low = false; const int render_block_write_current = block_buffer.write; if (render_block_write_current == render_block_write_prev_) { too_low = true; } else { for (int idx = render_block_write_prev_; idx != render_block_write_current; idx = block_buffer.IncIndex(idx)) { float max_abs_over_channels = 0.f; for (int ch = 0; ch < num_render_channels; ++ch) { auto block = block_buffer.buffer[idx][0][ch]; auto r = std::minmax_element(block.cbegin(), block.cend()); float max_abs_channel = std::max(std::fabs(*r.first), std::fabs(*r.second)); max_abs_over_channels = std::max(max_abs_over_channels, max_abs_channel); } if (max_abs_over_channels < 10.f) { too_low = true; // Discards all blocks if one of them is too low. break; } } } render_block_write_prev_ = render_block_write_current; return too_low; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/echo_audibility.h0000664000175000017500000000613114475643423027303 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_ECHO_AUDIBILITY_H_ #define MODULES_AUDIO_PROCESSING_AEC3_ECHO_AUDIBILITY_H_ #include #include "absl/types/optional.h" #include "api/array_view.h" #include "modules/audio_processing/aec3/block_buffer.h" #include "modules/audio_processing/aec3/render_buffer.h" #include "modules/audio_processing/aec3/spectrum_buffer.h" #include "modules/audio_processing/aec3/stationarity_estimator.h" #include "rtc_base/constructor_magic.h" namespace webrtc { class EchoAudibility { public: explicit EchoAudibility(bool use_render_stationarity_at_init); ~EchoAudibility(); EchoAudibility(const EchoAudibility&) = delete; EchoAudibility& operator=(const EchoAudibility&) = delete; // Feed new render data to the echo audibility estimator. void Update(const RenderBuffer& render_buffer, rtc::ArrayView average_reverb, int min_channel_delay_blocks, bool external_delay_seen); // Get the residual echo scaling. void GetResidualEchoScaling(bool filter_has_had_time_to_converge, rtc::ArrayView residual_scaling) const { for (size_t band = 0; band < residual_scaling.size(); ++band) { if (render_stationarity_.IsBandStationary(band) && (filter_has_had_time_to_converge || use_render_stationarity_at_init_)) { residual_scaling[band] = 0.f; } else { residual_scaling[band] = 1.0f; } } } // Returns true if the current render block is estimated as stationary. bool IsBlockStationary() const { return render_stationarity_.IsBlockStationary(); } private: // Reset the EchoAudibility class. void Reset(); // Updates the render stationarity flags for the current frame. void UpdateRenderStationarityFlags(const RenderBuffer& render_buffer, rtc::ArrayView average_reverb, int delay_blocks); // Updates the noise estimator with the new render data since the previous // call to this method. void UpdateRenderNoiseEstimator(const SpectrumBuffer& spectrum_buffer, const BlockBuffer& block_buffer, bool external_delay_seen); // Returns a bool being true if the render signal contains just close to zero // values. bool IsRenderTooLow(const BlockBuffer& block_buffer); absl::optional render_spectrum_write_prev_; int render_block_write_prev_; bool non_zero_render_seen_; const bool use_render_stationarity_at_init_; StationarityEstimator render_stationarity_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_ECHO_AUDIBILITY_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/echo_canceller3.cc0000664000175000017500000011116114475643423027315 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/echo_canceller3.h" #include #include #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/high_pass_filter.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/atomic_ops.h" #include "rtc_base/experiments/field_trial_parser.h" #include "rtc_base/logging.h" #include "system_wrappers/include/field_trial.h" namespace webrtc { namespace { enum class EchoCanceller3ApiCall { kCapture, kRender }; bool DetectSaturation(rtc::ArrayView y) { for (auto y_k : y) { if (y_k >= 32700.0f || y_k <= -32700.0f) { return true; } } return false; } // Retrieves a value from a field trial if it is available. If no value is // present, the default value is returned. If the retrieved value is beyond the // specified limits, the default value is returned instead. void RetrieveFieldTrialValue(const char* trial_name, float min, float max, float* value_to_update) { const std::string field_trial_str = field_trial::FindFullName(trial_name); FieldTrialParameter field_trial_param(/*key=*/"", *value_to_update); ParseFieldTrial({&field_trial_param}, field_trial_str); float field_trial_value = static_cast(field_trial_param.Get()); if (field_trial_value >= min && field_trial_value <= max) { *value_to_update = field_trial_value; } } void RetrieveFieldTrialValue(const char* trial_name, int min, int max, int* value_to_update) { const std::string field_trial_str = field_trial::FindFullName(trial_name); FieldTrialParameter field_trial_param(/*key=*/"", *value_to_update); ParseFieldTrial({&field_trial_param}, field_trial_str); float field_trial_value = field_trial_param.Get(); if (field_trial_value >= min && field_trial_value <= max) { *value_to_update = field_trial_value; } } void FillSubFrameView( AudioBuffer* frame, size_t sub_frame_index, std::vector>>* sub_frame_view) { RTC_DCHECK_GE(1, sub_frame_index); RTC_DCHECK_LE(0, sub_frame_index); RTC_DCHECK_EQ(frame->num_bands(), sub_frame_view->size()); RTC_DCHECK_EQ(frame->num_channels(), (*sub_frame_view)[0].size()); for (size_t band = 0; band < sub_frame_view->size(); ++band) { for (size_t channel = 0; channel < (*sub_frame_view)[0].size(); ++channel) { (*sub_frame_view)[band][channel] = rtc::ArrayView( &frame->split_bands(channel)[band][sub_frame_index * kSubFrameLength], kSubFrameLength); } } } void FillSubFrameView( std::vector>>* frame, size_t sub_frame_index, std::vector>>* sub_frame_view) { RTC_DCHECK_GE(1, sub_frame_index); RTC_DCHECK_EQ(frame->size(), sub_frame_view->size()); RTC_DCHECK_EQ((*frame)[0].size(), (*sub_frame_view)[0].size()); for (size_t band = 0; band < frame->size(); ++band) { for (size_t channel = 0; channel < (*frame)[band].size(); ++channel) { (*sub_frame_view)[band][channel] = rtc::ArrayView( &(*frame)[band][channel][sub_frame_index * kSubFrameLength], kSubFrameLength); } } } void ProcessCaptureFrameContent( AudioBuffer* linear_output, AudioBuffer* capture, bool level_change, bool saturated_microphone_signal, size_t sub_frame_index, FrameBlocker* capture_blocker, BlockFramer* linear_output_framer, BlockFramer* output_framer, BlockProcessor* block_processor, std::vector>>* linear_output_block, std::vector>>* linear_output_sub_frame_view, std::vector>>* capture_block, std::vector>>* capture_sub_frame_view) { FillSubFrameView(capture, sub_frame_index, capture_sub_frame_view); if (linear_output) { RTC_DCHECK(linear_output_framer); RTC_DCHECK(linear_output_block); RTC_DCHECK(linear_output_sub_frame_view); FillSubFrameView(linear_output, sub_frame_index, linear_output_sub_frame_view); } capture_blocker->InsertSubFrameAndExtractBlock(*capture_sub_frame_view, capture_block); block_processor->ProcessCapture(level_change, saturated_microphone_signal, linear_output_block, capture_block); output_framer->InsertBlockAndExtractSubFrame(*capture_block, capture_sub_frame_view); if (linear_output) { RTC_DCHECK(linear_output_framer); linear_output_framer->InsertBlockAndExtractSubFrame( *linear_output_block, linear_output_sub_frame_view); } } void ProcessRemainingCaptureFrameContent( bool level_change, bool saturated_microphone_signal, FrameBlocker* capture_blocker, BlockFramer* linear_output_framer, BlockFramer* output_framer, BlockProcessor* block_processor, std::vector>>* linear_output_block, std::vector>>* block) { if (!capture_blocker->IsBlockAvailable()) { return; } capture_blocker->ExtractBlock(block); block_processor->ProcessCapture(level_change, saturated_microphone_signal, linear_output_block, block); output_framer->InsertBlock(*block); if (linear_output_framer) { RTC_DCHECK(linear_output_block); linear_output_framer->InsertBlock(*linear_output_block); } } void BufferRenderFrameContent( std::vector>>* render_frame, size_t sub_frame_index, FrameBlocker* render_blocker, BlockProcessor* block_processor, std::vector>>* block, std::vector>>* sub_frame_view) { FillSubFrameView(render_frame, sub_frame_index, sub_frame_view); render_blocker->InsertSubFrameAndExtractBlock(*sub_frame_view, block); block_processor->BufferRender(*block); } void BufferRemainingRenderFrameContent( FrameBlocker* render_blocker, BlockProcessor* block_processor, std::vector>>* block) { if (!render_blocker->IsBlockAvailable()) { return; } render_blocker->ExtractBlock(block); block_processor->BufferRender(*block); } void CopyBufferIntoFrame(const AudioBuffer& buffer, size_t num_bands, size_t num_channels, std::vector>>* frame) { RTC_DCHECK_EQ(num_bands, frame->size()); RTC_DCHECK_EQ(num_channels, (*frame)[0].size()); RTC_DCHECK_EQ(AudioBuffer::kSplitBandSize, (*frame)[0][0].size()); for (size_t band = 0; band < num_bands; ++band) { for (size_t channel = 0; channel < num_channels; ++channel) { rtc::ArrayView buffer_view( &buffer.split_bands_const(channel)[band][0], AudioBuffer::kSplitBandSize); std::copy(buffer_view.begin(), buffer_view.end(), (*frame)[band][channel].begin()); } } } } // namespace // TODO(webrtc:5298): Move this to a separate file. EchoCanceller3Config AdjustConfig(const EchoCanceller3Config& config) { EchoCanceller3Config adjusted_cfg = config; if (field_trial::IsEnabled("WebRTC-Aec3AntiHowlingMinimizationKillSwitch")) { adjusted_cfg.suppressor.high_bands_suppression .anti_howling_activation_threshold = 25.f; adjusted_cfg.suppressor.high_bands_suppression.anti_howling_gain = 0.01f; } if (field_trial::IsEnabled("WebRTC-Aec3UseShortConfigChangeDuration")) { adjusted_cfg.filter.config_change_duration_blocks = 10; } if (field_trial::IsEnabled("WebRTC-Aec3UseZeroInitialStateDuration")) { adjusted_cfg.filter.initial_state_seconds = 0.f; } else if (field_trial::IsEnabled( "WebRTC-Aec3UseDot1SecondsInitialStateDuration")) { adjusted_cfg.filter.initial_state_seconds = .1f; } else if (field_trial::IsEnabled( "WebRTC-Aec3UseDot2SecondsInitialStateDuration")) { adjusted_cfg.filter.initial_state_seconds = .2f; } else if (field_trial::IsEnabled( "WebRTC-Aec3UseDot3SecondsInitialStateDuration")) { adjusted_cfg.filter.initial_state_seconds = .3f; } else if (field_trial::IsEnabled( "WebRTC-Aec3UseDot6SecondsInitialStateDuration")) { adjusted_cfg.filter.initial_state_seconds = .6f; } else if (field_trial::IsEnabled( "WebRTC-Aec3UseDot9SecondsInitialStateDuration")) { adjusted_cfg.filter.initial_state_seconds = .9f; } else if (field_trial::IsEnabled( "WebRTC-Aec3Use1Dot2SecondsInitialStateDuration")) { adjusted_cfg.filter.initial_state_seconds = 1.2f; } else if (field_trial::IsEnabled( "WebRTC-Aec3Use1Dot6SecondsInitialStateDuration")) { adjusted_cfg.filter.initial_state_seconds = 1.6f; } else if (field_trial::IsEnabled( "WebRTC-Aec3Use2Dot0SecondsInitialStateDuration")) { adjusted_cfg.filter.initial_state_seconds = 2.0f; } if (field_trial::IsEnabled("WebRTC-Aec3EchoSaturationDetectionKillSwitch")) { adjusted_cfg.ep_strength.echo_can_saturate = false; } if (field_trial::IsEnabled("WebRTC-Aec3UseDot2ReverbDefaultLen")) { adjusted_cfg.ep_strength.default_len = 0.2f; } else if (field_trial::IsEnabled("WebRTC-Aec3UseDot3ReverbDefaultLen")) { adjusted_cfg.ep_strength.default_len = 0.3f; } else if (field_trial::IsEnabled("WebRTC-Aec3UseDot4ReverbDefaultLen")) { adjusted_cfg.ep_strength.default_len = 0.4f; } else if (field_trial::IsEnabled("WebRTC-Aec3UseDot5ReverbDefaultLen")) { adjusted_cfg.ep_strength.default_len = 0.5f; } else if (field_trial::IsEnabled("WebRTC-Aec3UseDot6ReverbDefaultLen")) { adjusted_cfg.ep_strength.default_len = 0.6f; } else if (field_trial::IsEnabled("WebRTC-Aec3UseDot7ReverbDefaultLen")) { adjusted_cfg.ep_strength.default_len = 0.7f; } else if (field_trial::IsEnabled("WebRTC-Aec3UseDot8ReverbDefaultLen")) { adjusted_cfg.ep_strength.default_len = 0.8f; } if (field_trial::IsEnabled("WebRTC-Aec3ShortHeadroomKillSwitch")) { // Two blocks headroom. adjusted_cfg.delay.delay_headroom_samples = kBlockSize * 2; } if (field_trial::IsEnabled("WebRTC-Aec3ClampInstQualityToZeroKillSwitch")) { adjusted_cfg.erle.clamp_quality_estimate_to_zero = false; } if (field_trial::IsEnabled("WebRTC-Aec3ClampInstQualityToOneKillSwitch")) { adjusted_cfg.erle.clamp_quality_estimate_to_one = false; } if (field_trial::IsEnabled("WebRTC-Aec3OnsetDetectionKillSwitch")) { adjusted_cfg.erle.onset_detection = false; } if (field_trial::IsEnabled( "WebRTC-Aec3EnforceRenderDelayEstimationDownmixing")) { adjusted_cfg.delay.render_alignment_mixing.downmix = true; adjusted_cfg.delay.render_alignment_mixing.adaptive_selection = false; } if (field_trial::IsEnabled( "WebRTC-Aec3EnforceCaptureDelayEstimationDownmixing")) { adjusted_cfg.delay.capture_alignment_mixing.downmix = true; adjusted_cfg.delay.capture_alignment_mixing.adaptive_selection = false; } if (field_trial::IsEnabled( "WebRTC-Aec3EnforceCaptureDelayEstimationLeftRightPrioritization")) { adjusted_cfg.delay.capture_alignment_mixing.prefer_first_two_channels = true; } if (field_trial::IsEnabled( "WebRTC-" "Aec3RenderDelayEstimationLeftRightPrioritizationKillSwitch")) { adjusted_cfg.delay.capture_alignment_mixing.prefer_first_two_channels = false; } if (field_trial::IsEnabled("WebRTC-Aec3SensitiveDominantNearendActivation")) { adjusted_cfg.suppressor.dominant_nearend_detection.enr_threshold = 0.5f; } else if (field_trial::IsEnabled( "WebRTC-Aec3VerySensitiveDominantNearendActivation")) { adjusted_cfg.suppressor.dominant_nearend_detection.enr_threshold = 0.75f; } if (field_trial::IsEnabled("WebRTC-Aec3TransparentAntiHowlingGain")) { adjusted_cfg.suppressor.high_bands_suppression.anti_howling_gain = 1.f; } if (field_trial::IsEnabled( "WebRTC-Aec3EnforceMoreTransparentNormalSuppressorTuning")) { adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_transparent = 0.4f; adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_suppress = 0.5f; } if (field_trial::IsEnabled( "WebRTC-Aec3EnforceMoreTransparentNearendSuppressorTuning")) { adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_transparent = 1.29f; adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_suppress = 1.3f; } if (field_trial::IsEnabled( "WebRTC-Aec3EnforceMoreTransparentNormalSuppressorHfTuning")) { adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_transparent = 0.3f; adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_suppress = 0.4f; } if (field_trial::IsEnabled( "WebRTC-Aec3EnforceMoreTransparentNearendSuppressorHfTuning")) { adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_transparent = 1.09f; adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_suppress = 1.1f; } if (field_trial::IsEnabled( "WebRTC-Aec3EnforceRapidlyAdjustingNormalSuppressorTunings")) { adjusted_cfg.suppressor.normal_tuning.max_inc_factor = 2.5f; } if (field_trial::IsEnabled( "WebRTC-Aec3EnforceRapidlyAdjustingNearendSuppressorTunings")) { adjusted_cfg.suppressor.nearend_tuning.max_inc_factor = 2.5f; } if (field_trial::IsEnabled( "WebRTC-Aec3EnforceSlowlyAdjustingNormalSuppressorTunings")) { adjusted_cfg.suppressor.normal_tuning.max_dec_factor_lf = .2f; } if (field_trial::IsEnabled( "WebRTC-Aec3EnforceSlowlyAdjustingNearendSuppressorTunings")) { adjusted_cfg.suppressor.nearend_tuning.max_dec_factor_lf = .2f; } if (field_trial::IsEnabled("WebRTC-Aec3EnforceStationarityProperties")) { adjusted_cfg.echo_audibility.use_stationarity_properties = true; } if (field_trial::IsEnabled( "WebRTC-Aec3EnforceStationarityPropertiesAtInit")) { adjusted_cfg.echo_audibility.use_stationarity_properties_at_init = true; } if (field_trial::IsEnabled("WebRTC-Aec3EnforceLowActiveRenderLimit")) { adjusted_cfg.render_levels.active_render_limit = 50.f; } else if (field_trial::IsEnabled( "WebRTC-Aec3EnforceVeryLowActiveRenderLimit")) { adjusted_cfg.render_levels.active_render_limit = 30.f; } if (field_trial::IsEnabled("WebRTC-Aec3NonlinearModeReverbKillSwitch")) { adjusted_cfg.echo_model.model_reverb_in_nonlinear_mode = false; } // Field-trial based override for the whole suppressor tuning. const std::string suppressor_tuning_override_trial_name = field_trial::FindFullName("WebRTC-Aec3SuppressorTuningOverride"); FieldTrialParameter nearend_tuning_mask_lf_enr_transparent( "nearend_tuning_mask_lf_enr_transparent", adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_transparent); FieldTrialParameter nearend_tuning_mask_lf_enr_suppress( "nearend_tuning_mask_lf_enr_suppress", adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_suppress); FieldTrialParameter nearend_tuning_mask_hf_enr_transparent( "nearend_tuning_mask_hf_enr_transparent", adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_transparent); FieldTrialParameter nearend_tuning_mask_hf_enr_suppress( "nearend_tuning_mask_hf_enr_suppress", adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_suppress); FieldTrialParameter nearend_tuning_max_inc_factor( "nearend_tuning_max_inc_factor", adjusted_cfg.suppressor.nearend_tuning.max_inc_factor); FieldTrialParameter nearend_tuning_max_dec_factor_lf( "nearend_tuning_max_dec_factor_lf", adjusted_cfg.suppressor.nearend_tuning.max_dec_factor_lf); FieldTrialParameter normal_tuning_mask_lf_enr_transparent( "normal_tuning_mask_lf_enr_transparent", adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_transparent); FieldTrialParameter normal_tuning_mask_lf_enr_suppress( "normal_tuning_mask_lf_enr_suppress", adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_suppress); FieldTrialParameter normal_tuning_mask_hf_enr_transparent( "normal_tuning_mask_hf_enr_transparent", adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_transparent); FieldTrialParameter normal_tuning_mask_hf_enr_suppress( "normal_tuning_mask_hf_enr_suppress", adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_suppress); FieldTrialParameter normal_tuning_max_inc_factor( "normal_tuning_max_inc_factor", adjusted_cfg.suppressor.normal_tuning.max_inc_factor); FieldTrialParameter normal_tuning_max_dec_factor_lf( "normal_tuning_max_dec_factor_lf", adjusted_cfg.suppressor.normal_tuning.max_dec_factor_lf); FieldTrialParameter dominant_nearend_detection_enr_threshold( "dominant_nearend_detection_enr_threshold", adjusted_cfg.suppressor.dominant_nearend_detection.enr_threshold); FieldTrialParameter dominant_nearend_detection_enr_exit_threshold( "dominant_nearend_detection_enr_exit_threshold", adjusted_cfg.suppressor.dominant_nearend_detection.enr_exit_threshold); FieldTrialParameter dominant_nearend_detection_snr_threshold( "dominant_nearend_detection_snr_threshold", adjusted_cfg.suppressor.dominant_nearend_detection.snr_threshold); FieldTrialParameter dominant_nearend_detection_hold_duration( "dominant_nearend_detection_hold_duration", adjusted_cfg.suppressor.dominant_nearend_detection.hold_duration); FieldTrialParameter dominant_nearend_detection_trigger_threshold( "dominant_nearend_detection_trigger_threshold", adjusted_cfg.suppressor.dominant_nearend_detection.trigger_threshold); FieldTrialParameter ep_strength_default_len( "ep_strength_default_len", adjusted_cfg.ep_strength.default_len); ParseFieldTrial( {&nearend_tuning_mask_lf_enr_transparent, &nearend_tuning_mask_lf_enr_suppress, &nearend_tuning_mask_hf_enr_transparent, &nearend_tuning_mask_hf_enr_suppress, &nearend_tuning_max_inc_factor, &nearend_tuning_max_dec_factor_lf, &normal_tuning_mask_lf_enr_transparent, &normal_tuning_mask_lf_enr_suppress, &normal_tuning_mask_hf_enr_transparent, &normal_tuning_mask_hf_enr_suppress, &normal_tuning_max_inc_factor, &normal_tuning_max_dec_factor_lf, &dominant_nearend_detection_enr_threshold, &dominant_nearend_detection_enr_exit_threshold, &dominant_nearend_detection_snr_threshold, &dominant_nearend_detection_hold_duration, &dominant_nearend_detection_trigger_threshold, &ep_strength_default_len}, suppressor_tuning_override_trial_name); adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_transparent = static_cast(nearend_tuning_mask_lf_enr_transparent.Get()); adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_suppress = static_cast(nearend_tuning_mask_lf_enr_suppress.Get()); adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_transparent = static_cast(nearend_tuning_mask_hf_enr_transparent.Get()); adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_suppress = static_cast(nearend_tuning_mask_hf_enr_suppress.Get()); adjusted_cfg.suppressor.nearend_tuning.max_inc_factor = static_cast(nearend_tuning_max_inc_factor.Get()); adjusted_cfg.suppressor.nearend_tuning.max_dec_factor_lf = static_cast(nearend_tuning_max_dec_factor_lf.Get()); adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_transparent = static_cast(normal_tuning_mask_lf_enr_transparent.Get()); adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_suppress = static_cast(normal_tuning_mask_lf_enr_suppress.Get()); adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_transparent = static_cast(normal_tuning_mask_hf_enr_transparent.Get()); adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_suppress = static_cast(normal_tuning_mask_hf_enr_suppress.Get()); adjusted_cfg.suppressor.normal_tuning.max_inc_factor = static_cast(normal_tuning_max_inc_factor.Get()); adjusted_cfg.suppressor.normal_tuning.max_dec_factor_lf = static_cast(normal_tuning_max_dec_factor_lf.Get()); adjusted_cfg.suppressor.dominant_nearend_detection.enr_threshold = static_cast(dominant_nearend_detection_enr_threshold.Get()); adjusted_cfg.suppressor.dominant_nearend_detection.enr_exit_threshold = static_cast(dominant_nearend_detection_enr_exit_threshold.Get()); adjusted_cfg.suppressor.dominant_nearend_detection.snr_threshold = static_cast(dominant_nearend_detection_snr_threshold.Get()); adjusted_cfg.suppressor.dominant_nearend_detection.hold_duration = dominant_nearend_detection_hold_duration.Get(); adjusted_cfg.suppressor.dominant_nearend_detection.trigger_threshold = dominant_nearend_detection_trigger_threshold.Get(); adjusted_cfg.ep_strength.default_len = static_cast(ep_strength_default_len.Get()); // Field trial-based overrides of individual suppressor parameters. RetrieveFieldTrialValue( "WebRTC-Aec3SuppressorNearendLfMaskTransparentOverride", 0.f, 10.f, &adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_transparent); RetrieveFieldTrialValue( "WebRTC-Aec3SuppressorNearendLfMaskSuppressOverride", 0.f, 10.f, &adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_suppress); RetrieveFieldTrialValue( "WebRTC-Aec3SuppressorNearendHfMaskTransparentOverride", 0.f, 10.f, &adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_transparent); RetrieveFieldTrialValue( "WebRTC-Aec3SuppressorNearendHfMaskSuppressOverride", 0.f, 10.f, &adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_suppress); RetrieveFieldTrialValue( "WebRTC-Aec3SuppressorNearendMaxIncFactorOverride", 0.f, 10.f, &adjusted_cfg.suppressor.nearend_tuning.max_inc_factor); RetrieveFieldTrialValue( "WebRTC-Aec3SuppressorNearendMaxDecFactorLfOverride", 0.f, 10.f, &adjusted_cfg.suppressor.nearend_tuning.max_dec_factor_lf); RetrieveFieldTrialValue( "WebRTC-Aec3SuppressorNormalLfMaskTransparentOverride", 0.f, 10.f, &adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_transparent); RetrieveFieldTrialValue( "WebRTC-Aec3SuppressorNormalLfMaskSuppressOverride", 0.f, 10.f, &adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_suppress); RetrieveFieldTrialValue( "WebRTC-Aec3SuppressorNormalHfMaskTransparentOverride", 0.f, 10.f, &adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_transparent); RetrieveFieldTrialValue( "WebRTC-Aec3SuppressorNormalHfMaskSuppressOverride", 0.f, 10.f, &adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_suppress); RetrieveFieldTrialValue( "WebRTC-Aec3SuppressorNormalMaxIncFactorOverride", 0.f, 10.f, &adjusted_cfg.suppressor.normal_tuning.max_inc_factor); RetrieveFieldTrialValue( "WebRTC-Aec3SuppressorNormalMaxDecFactorLfOverride", 0.f, 10.f, &adjusted_cfg.suppressor.normal_tuning.max_dec_factor_lf); RetrieveFieldTrialValue( "WebRTC-Aec3SuppressorDominantNearendEnrThresholdOverride", 0.f, 100.f, &adjusted_cfg.suppressor.dominant_nearend_detection.enr_threshold); RetrieveFieldTrialValue( "WebRTC-Aec3SuppressorDominantNearendEnrExitThresholdOverride", 0.f, 100.f, &adjusted_cfg.suppressor.dominant_nearend_detection.enr_exit_threshold); RetrieveFieldTrialValue( "WebRTC-Aec3SuppressorDominantNearendSnrThresholdOverride", 0.f, 100.f, &adjusted_cfg.suppressor.dominant_nearend_detection.snr_threshold); RetrieveFieldTrialValue( "WebRTC-Aec3SuppressorDominantNearendHoldDurationOverride", 0, 1000, &adjusted_cfg.suppressor.dominant_nearend_detection.hold_duration); RetrieveFieldTrialValue( "WebRTC-Aec3SuppressorDominantNearendTriggerThresholdOverride", 0, 1000, &adjusted_cfg.suppressor.dominant_nearend_detection.trigger_threshold); RetrieveFieldTrialValue( "WebRTC-Aec3SuppressorAntiHowlingGainOverride", 0.f, 10.f, &adjusted_cfg.suppressor.high_bands_suppression.anti_howling_gain); RetrieveFieldTrialValue("WebRTC-Aec3SuppressorEpStrengthDefaultLenOverride", -1.f, 1.f, &adjusted_cfg.ep_strength.default_len); return adjusted_cfg; } class EchoCanceller3::RenderWriter { public: RenderWriter(ApmDataDumper* data_dumper, SwapQueue>>, Aec3RenderQueueItemVerifier>* render_transfer_queue, size_t num_bands, size_t num_channels); RenderWriter() = delete; RenderWriter(const RenderWriter&) = delete; RenderWriter& operator=(const RenderWriter&) = delete; ~RenderWriter(); void Insert(const AudioBuffer& input); private: ApmDataDumper* data_dumper_; const size_t num_bands_; const size_t num_channels_; HighPassFilter high_pass_filter_; std::vector>> render_queue_input_frame_; SwapQueue>>, Aec3RenderQueueItemVerifier>* render_transfer_queue_; }; EchoCanceller3::RenderWriter::RenderWriter( ApmDataDumper* data_dumper, SwapQueue>>, Aec3RenderQueueItemVerifier>* render_transfer_queue, size_t num_bands, size_t num_channels) : data_dumper_(data_dumper), num_bands_(num_bands), num_channels_(num_channels), high_pass_filter_(16000, num_channels), render_queue_input_frame_( num_bands_, std::vector>( num_channels_, std::vector(AudioBuffer::kSplitBandSize, 0.f))), render_transfer_queue_(render_transfer_queue) { RTC_DCHECK(data_dumper); } EchoCanceller3::RenderWriter::~RenderWriter() = default; void EchoCanceller3::RenderWriter::Insert(const AudioBuffer& input) { RTC_DCHECK_EQ(AudioBuffer::kSplitBandSize, input.num_frames_per_band()); RTC_DCHECK_EQ(num_bands_, input.num_bands()); RTC_DCHECK_EQ(num_channels_, input.num_channels()); // TODO(bugs.webrtc.org/8759) Temporary work-around. if (num_bands_ != input.num_bands()) return; data_dumper_->DumpWav("aec3_render_input", AudioBuffer::kSplitBandSize, &input.split_bands_const(0)[0][0], 16000, 1); CopyBufferIntoFrame(input, num_bands_, num_channels_, &render_queue_input_frame_); high_pass_filter_.Process(&render_queue_input_frame_[0]); static_cast(render_transfer_queue_->Insert(&render_queue_input_frame_)); } int EchoCanceller3::instance_count_ = 0; EchoCanceller3::EchoCanceller3(const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels, size_t num_capture_channels) : EchoCanceller3(AdjustConfig(config), sample_rate_hz, num_render_channels, num_capture_channels, std::unique_ptr( BlockProcessor::Create(AdjustConfig(config), sample_rate_hz, num_render_channels, num_capture_channels))) {} EchoCanceller3::EchoCanceller3(const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels, size_t num_capture_channels, std::unique_ptr block_processor) : data_dumper_( new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), config_(config), sample_rate_hz_(sample_rate_hz), num_bands_(NumBandsForRate(sample_rate_hz_)), num_render_channels_(num_render_channels), num_capture_channels_(num_capture_channels), output_framer_(num_bands_, num_capture_channels_), capture_blocker_(num_bands_, num_capture_channels_), render_blocker_(num_bands_, num_render_channels_), render_transfer_queue_( kRenderTransferQueueSizeFrames, std::vector>>( num_bands_, std::vector>( num_render_channels_, std::vector(AudioBuffer::kSplitBandSize, 0.f))), Aec3RenderQueueItemVerifier(num_bands_, num_render_channels_, AudioBuffer::kSplitBandSize)), block_processor_(std::move(block_processor)), render_queue_output_frame_( num_bands_, std::vector>( num_render_channels_, std::vector(AudioBuffer::kSplitBandSize, 0.f))), render_block_( num_bands_, std::vector>(num_render_channels_, std::vector(kBlockSize, 0.f))), capture_block_( num_bands_, std::vector>(num_capture_channels_, std::vector(kBlockSize, 0.f))), render_sub_frame_view_( num_bands_, std::vector>(num_render_channels_)), capture_sub_frame_view_( num_bands_, std::vector>(num_capture_channels_)) { RTC_DCHECK(ValidFullBandRate(sample_rate_hz_)); if (config_.delay.fixed_capture_delay_samples > 0) { block_delay_buffer_.reset(new BlockDelayBuffer( num_capture_channels_, num_bands_, AudioBuffer::kSplitBandSize, config_.delay.fixed_capture_delay_samples)); } render_writer_.reset(new RenderWriter(data_dumper_.get(), &render_transfer_queue_, num_bands_, num_render_channels_)); RTC_DCHECK_EQ(num_bands_, std::max(sample_rate_hz_, 16000) / 16000); RTC_DCHECK_GE(kMaxNumBands, num_bands_); if (config_.filter.export_linear_aec_output) { linear_output_framer_.reset(new BlockFramer(1, num_capture_channels_)); linear_output_block_ = std::make_unique>>>( 1, std::vector>( num_capture_channels_, std::vector(kBlockSize, 0.f))); linear_output_sub_frame_view_ = std::vector>>( 1, std::vector>(num_capture_channels_)); } } EchoCanceller3::~EchoCanceller3() = default; void EchoCanceller3::AnalyzeRender(const AudioBuffer& render) { RTC_DCHECK_RUNS_SERIALIZED(&render_race_checker_); RTC_DCHECK_EQ(render.num_channels(), num_render_channels_); data_dumper_->DumpRaw("aec3_call_order", static_cast(EchoCanceller3ApiCall::kRender)); return render_writer_->Insert(render); } void EchoCanceller3::AnalyzeCapture(const AudioBuffer& capture) { RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_); data_dumper_->DumpWav("aec3_capture_analyze_input", capture.num_frames(), capture.channels_const()[0], sample_rate_hz_, 1); saturated_microphone_signal_ = false; for (size_t channel = 0; channel < capture.num_channels(); ++channel) { saturated_microphone_signal_ |= DetectSaturation(rtc::ArrayView( capture.channels_const()[channel], capture.num_frames())); if (saturated_microphone_signal_) { break; } } } void EchoCanceller3::ProcessCapture(AudioBuffer* capture, bool level_change) { ProcessCapture(capture, nullptr, level_change); } void EchoCanceller3::ProcessCapture(AudioBuffer* capture, AudioBuffer* linear_output, bool level_change) { RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_); RTC_DCHECK(capture); RTC_DCHECK_EQ(num_bands_, capture->num_bands()); RTC_DCHECK_EQ(AudioBuffer::kSplitBandSize, capture->num_frames_per_band()); RTC_DCHECK_EQ(capture->num_channels(), num_capture_channels_); data_dumper_->DumpRaw("aec3_call_order", static_cast(EchoCanceller3ApiCall::kCapture)); if (linear_output && !linear_output_framer_) { RTC_LOG(LS_ERROR) << "Trying to retrieve the linear AEC output without " "properly configuring AEC3."; RTC_NOTREACHED(); } // Report capture call in the metrics and periodically update API call // metrics. api_call_metrics_.ReportCaptureCall(); // Optionally delay the capture signal. if (config_.delay.fixed_capture_delay_samples > 0) { RTC_DCHECK(block_delay_buffer_); block_delay_buffer_->DelaySignal(capture); } rtc::ArrayView capture_lower_band = rtc::ArrayView( &capture->split_bands(0)[0][0], AudioBuffer::kSplitBandSize); data_dumper_->DumpWav("aec3_capture_input", capture_lower_band, 16000, 1); EmptyRenderQueue(); ProcessCaptureFrameContent(linear_output, capture, level_change, saturated_microphone_signal_, 0, &capture_blocker_, linear_output_framer_.get(), &output_framer_, block_processor_.get(), linear_output_block_.get(), &linear_output_sub_frame_view_, &capture_block_, &capture_sub_frame_view_); ProcessCaptureFrameContent(linear_output, capture, level_change, saturated_microphone_signal_, 1, &capture_blocker_, linear_output_framer_.get(), &output_framer_, block_processor_.get(), linear_output_block_.get(), &linear_output_sub_frame_view_, &capture_block_, &capture_sub_frame_view_); ProcessRemainingCaptureFrameContent( level_change, saturated_microphone_signal_, &capture_blocker_, linear_output_framer_.get(), &output_framer_, block_processor_.get(), linear_output_block_.get(), &capture_block_); data_dumper_->DumpWav("aec3_capture_output", AudioBuffer::kSplitBandSize, &capture->split_bands(0)[0][0], 16000, 1); } EchoControl::Metrics EchoCanceller3::GetMetrics() const { RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_); Metrics metrics; block_processor_->GetMetrics(&metrics); return metrics; } void EchoCanceller3::SetAudioBufferDelay(int delay_ms) { RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_); block_processor_->SetAudioBufferDelay(delay_ms); } bool EchoCanceller3::ActiveProcessing() const { return true; } EchoCanceller3Config EchoCanceller3::CreateDefaultConfig( size_t num_render_channels, size_t num_capture_channels) { EchoCanceller3Config cfg; if (num_render_channels > 1) { // Use shorter and more rapidly adapting coarse filter to compensate for // thge increased number of total filter parameters to adapt. cfg.filter.coarse.length_blocks = 11; cfg.filter.coarse.rate = 0.95f; cfg.filter.coarse_initial.length_blocks = 11; cfg.filter.coarse_initial.rate = 0.95f; // Use more concervative suppressor behavior for non-nearend speech. cfg.suppressor.normal_tuning.max_dec_factor_lf = 0.35f; cfg.suppressor.normal_tuning.max_inc_factor = 1.5f; } return cfg; } void EchoCanceller3::EmptyRenderQueue() { RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_); bool frame_to_buffer = render_transfer_queue_.Remove(&render_queue_output_frame_); while (frame_to_buffer) { // Report render call in the metrics. api_call_metrics_.ReportRenderCall(); BufferRenderFrameContent(&render_queue_output_frame_, 0, &render_blocker_, block_processor_.get(), &render_block_, &render_sub_frame_view_); BufferRenderFrameContent(&render_queue_output_frame_, 1, &render_blocker_, block_processor_.get(), &render_block_, &render_sub_frame_view_); BufferRemainingRenderFrameContent(&render_blocker_, block_processor_.get(), &render_block_); frame_to_buffer = render_transfer_queue_.Remove(&render_queue_output_frame_); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/echo_canceller3.h0000664000175000017500000001722014475643423027160 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_ECHO_CANCELLER3_H_ #define MODULES_AUDIO_PROCESSING_AEC3_ECHO_CANCELLER3_H_ #include #include #include #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "api/audio/echo_control.h" #include "modules/audio_processing/aec3/api_call_jitter_metrics.h" #include "modules/audio_processing/aec3/block_delay_buffer.h" #include "modules/audio_processing/aec3/block_framer.h" #include "modules/audio_processing/aec3/block_processor.h" #include "modules/audio_processing/aec3/frame_blocker.h" #include "modules/audio_processing/audio_buffer.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" #include "rtc_base/race_checker.h" #include "rtc_base/swap_queue.h" #include "rtc_base/thread_annotations.h" namespace webrtc { // Method for adjusting config parameter dependencies. // Only to be used externally to AEC3 for testing purposes. // TODO(webrtc:5298): Move this to a separate file. EchoCanceller3Config AdjustConfig(const EchoCanceller3Config& config); // Functor for verifying the invariance of the frames being put into the render // queue. class Aec3RenderQueueItemVerifier { public: Aec3RenderQueueItemVerifier(size_t num_bands, size_t num_channels, size_t frame_length) : num_bands_(num_bands), num_channels_(num_channels), frame_length_(frame_length) {} bool operator()(const std::vector>>& v) const { if (v.size() != num_bands_) { return false; } for (const auto& band : v) { if (band.size() != num_channels_) { return false; } for (const auto& channel : band) { if (channel.size() != frame_length_) { return false; } } } return true; } private: const size_t num_bands_; const size_t num_channels_; const size_t frame_length_; }; // Main class for the echo canceller3. // It does 4 things: // -Receives 10 ms frames of band-split audio. // -Provides the lower level echo canceller functionality with // blocks of 64 samples of audio data. // -Partially handles the jitter in the render and capture API // call sequence. // // The class is supposed to be used in a non-concurrent manner apart from the // AnalyzeRender call which can be called concurrently with the other methods. class EchoCanceller3 : public EchoControl { public: // Normal c-tor to use. EchoCanceller3(const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels, size_t num_capture_channels); // Testing c-tor that is used only for testing purposes. EchoCanceller3(const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels, size_t num_capture_channels, std::unique_ptr block_processor); ~EchoCanceller3() override; EchoCanceller3(const EchoCanceller3&) = delete; EchoCanceller3& operator=(const EchoCanceller3&) = delete; // Analyzes and stores an internal copy of the split-band domain render // signal. void AnalyzeRender(AudioBuffer* render) override { AnalyzeRender(*render); } // Analyzes the full-band domain capture signal to detect signal saturation. void AnalyzeCapture(AudioBuffer* capture) override { AnalyzeCapture(*capture); } // Processes the split-band domain capture signal in order to remove any echo // present in the signal. void ProcessCapture(AudioBuffer* capture, bool level_change) override; // As above, but also returns the linear filter output. void ProcessCapture(AudioBuffer* capture, AudioBuffer* linear_output, bool level_change) override; // Collect current metrics from the echo canceller. Metrics GetMetrics() const override; // Provides an optional external estimate of the audio buffer delay. void SetAudioBufferDelay(int delay_ms) override; bool ActiveProcessing() const override; // Signals whether an external detector has detected echo leakage from the // echo canceller. // Note that in the case echo leakage has been flagged, it should be unflagged // once it is no longer occurring. void UpdateEchoLeakageStatus(bool leakage_detected) { RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_); block_processor_->UpdateEchoLeakageStatus(leakage_detected); } // Produces a default configuration that is suitable for a certain combination // of render and capture channels. static EchoCanceller3Config CreateDefaultConfig(size_t num_render_channels, size_t num_capture_channels); private: class RenderWriter; // Empties the render SwapQueue. void EmptyRenderQueue(); // Analyzes and stores an internal copy of the split-band domain render // signal. void AnalyzeRender(const AudioBuffer& render); // Analyzes the full-band domain capture signal to detect signal saturation. void AnalyzeCapture(const AudioBuffer& capture); rtc::RaceChecker capture_race_checker_; rtc::RaceChecker render_race_checker_; // State that is accessed by the AnalyzeRender call. std::unique_ptr render_writer_ RTC_GUARDED_BY(render_race_checker_); // State that may be accessed by the capture thread. static int instance_count_; std::unique_ptr data_dumper_; const EchoCanceller3Config config_; const int sample_rate_hz_; const int num_bands_; const size_t num_render_channels_; const size_t num_capture_channels_; std::unique_ptr linear_output_framer_ RTC_GUARDED_BY(capture_race_checker_); BlockFramer output_framer_ RTC_GUARDED_BY(capture_race_checker_); FrameBlocker capture_blocker_ RTC_GUARDED_BY(capture_race_checker_); FrameBlocker render_blocker_ RTC_GUARDED_BY(capture_race_checker_); SwapQueue>>, Aec3RenderQueueItemVerifier> render_transfer_queue_; std::unique_ptr block_processor_ RTC_GUARDED_BY(capture_race_checker_); std::vector>> render_queue_output_frame_ RTC_GUARDED_BY(capture_race_checker_); bool saturated_microphone_signal_ RTC_GUARDED_BY(capture_race_checker_) = false; std::vector>> render_block_ RTC_GUARDED_BY(capture_race_checker_); std::unique_ptr>>> linear_output_block_ RTC_GUARDED_BY(capture_race_checker_); std::vector>> capture_block_ RTC_GUARDED_BY(capture_race_checker_); std::vector>> render_sub_frame_view_ RTC_GUARDED_BY(capture_race_checker_); std::vector>> linear_output_sub_frame_view_ RTC_GUARDED_BY(capture_race_checker_); std::vector>> capture_sub_frame_view_ RTC_GUARDED_BY(capture_race_checker_); std::unique_ptr block_delay_buffer_ RTC_GUARDED_BY(capture_race_checker_); ApiCallJitterMetrics api_call_metrics_ RTC_GUARDED_BY(capture_race_checker_); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_ECHO_CANCELLER3_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/echo_path_delay_estimator.cc0000664000175000017500000001165314475643423031510 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/echo_path_delay_estimator.h" #include #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/downsampled_render_buffer.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" namespace webrtc { EchoPathDelayEstimator::EchoPathDelayEstimator( ApmDataDumper* data_dumper, const EchoCanceller3Config& config, size_t num_capture_channels) : data_dumper_(data_dumper), down_sampling_factor_(config.delay.down_sampling_factor), sub_block_size_(down_sampling_factor_ != 0 ? kBlockSize / down_sampling_factor_ : kBlockSize), capture_mixer_(num_capture_channels, config.delay.capture_alignment_mixing), capture_decimator_(down_sampling_factor_), matched_filter_( data_dumper_, DetectOptimization(), sub_block_size_, kMatchedFilterWindowSizeSubBlocks, config.delay.num_filters, kMatchedFilterAlignmentShiftSizeSubBlocks, config.delay.down_sampling_factor == 8 ? config.render_levels.poor_excitation_render_limit_ds8 : config.render_levels.poor_excitation_render_limit, config.delay.delay_estimate_smoothing, config.delay.delay_candidate_detection_threshold), matched_filter_lag_aggregator_(data_dumper_, matched_filter_.GetMaxFilterLag(), config.delay.delay_selection_thresholds) { RTC_DCHECK(data_dumper); RTC_DCHECK(down_sampling_factor_ > 0); } EchoPathDelayEstimator::~EchoPathDelayEstimator() = default; void EchoPathDelayEstimator::Reset(bool reset_delay_confidence) { Reset(true, reset_delay_confidence); } absl::optional EchoPathDelayEstimator::EstimateDelay( const DownsampledRenderBuffer& render_buffer, const std::vector>& capture) { RTC_DCHECK_EQ(kBlockSize, capture[0].size()); std::array downsampled_capture_data; rtc::ArrayView downsampled_capture(downsampled_capture_data.data(), sub_block_size_); std::array downmixed_capture; capture_mixer_.ProduceOutput(capture, downmixed_capture); capture_decimator_.Decimate(downmixed_capture, downsampled_capture); data_dumper_->DumpWav("aec3_capture_decimator_output", downsampled_capture.size(), downsampled_capture.data(), 16000 / down_sampling_factor_, 1); matched_filter_.Update(render_buffer, downsampled_capture); absl::optional aggregated_matched_filter_lag = matched_filter_lag_aggregator_.Aggregate( matched_filter_.GetLagEstimates()); // Run clockdrift detection. if (aggregated_matched_filter_lag && (*aggregated_matched_filter_lag).quality == DelayEstimate::Quality::kRefined) clockdrift_detector_.Update((*aggregated_matched_filter_lag).delay); // TODO(peah): Move this logging outside of this class once EchoCanceller3 // development is done. data_dumper_->DumpRaw( "aec3_echo_path_delay_estimator_delay", aggregated_matched_filter_lag ? static_cast(aggregated_matched_filter_lag->delay * down_sampling_factor_) : -1); // Return the detected delay in samples as the aggregated matched filter lag // compensated by the down sampling factor for the signal being correlated. if (aggregated_matched_filter_lag) { aggregated_matched_filter_lag->delay *= down_sampling_factor_; } if (old_aggregated_lag_ && aggregated_matched_filter_lag && old_aggregated_lag_->delay == aggregated_matched_filter_lag->delay) { ++consistent_estimate_counter_; } else { consistent_estimate_counter_ = 0; } old_aggregated_lag_ = aggregated_matched_filter_lag; constexpr size_t kNumBlocksPerSecondBy2 = kNumBlocksPerSecond / 2; if (consistent_estimate_counter_ > kNumBlocksPerSecondBy2) { Reset(false, false); } return aggregated_matched_filter_lag; } void EchoPathDelayEstimator::Reset(bool reset_lag_aggregator, bool reset_delay_confidence) { if (reset_lag_aggregator) { matched_filter_lag_aggregator_.Reset(reset_delay_confidence); } matched_filter_.Reset(); old_aggregated_lag_ = absl::nullopt; consistent_estimate_counter_ = 0; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/echo_path_delay_estimator.h0000664000175000017500000000547514475643423031357 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_ECHO_PATH_DELAY_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_AEC3_ECHO_PATH_DELAY_ESTIMATOR_H_ #include #include "absl/types/optional.h" #include "api/array_view.h" #include "modules/audio_processing/aec3/alignment_mixer.h" #include "modules/audio_processing/aec3/clockdrift_detector.h" #include "modules/audio_processing/aec3/decimator.h" #include "modules/audio_processing/aec3/delay_estimate.h" #include "modules/audio_processing/aec3/matched_filter.h" #include "modules/audio_processing/aec3/matched_filter_lag_aggregator.h" #include "rtc_base/constructor_magic.h" namespace webrtc { class ApmDataDumper; struct DownsampledRenderBuffer; struct EchoCanceller3Config; // Estimates the delay of the echo path. class EchoPathDelayEstimator { public: EchoPathDelayEstimator(ApmDataDumper* data_dumper, const EchoCanceller3Config& config, size_t num_capture_channels); ~EchoPathDelayEstimator(); // Resets the estimation. If the delay confidence is reset, the reset behavior // is as if the call is restarted. void Reset(bool reset_delay_confidence); // Produce a delay estimate if such is avaliable. absl::optional EstimateDelay( const DownsampledRenderBuffer& render_buffer, const std::vector>& capture); // Log delay estimator properties. void LogDelayEstimationProperties(int sample_rate_hz, size_t shift) const { matched_filter_.LogFilterProperties(sample_rate_hz, shift, down_sampling_factor_); } // Returns the level of detected clockdrift. ClockdriftDetector::Level Clockdrift() const { return clockdrift_detector_.ClockdriftLevel(); } private: ApmDataDumper* const data_dumper_; const size_t down_sampling_factor_; const size_t sub_block_size_; AlignmentMixer capture_mixer_; Decimator capture_decimator_; MatchedFilter matched_filter_; MatchedFilterLagAggregator matched_filter_lag_aggregator_; absl::optional old_aggregated_lag_; size_t consistent_estimate_counter_ = 0; ClockdriftDetector clockdrift_detector_; // Internal reset method with more granularity. void Reset(bool reset_lag_aggregator, bool reset_delay_confidence); RTC_DISALLOW_COPY_AND_ASSIGN(EchoPathDelayEstimator); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_ECHO_PATH_DELAY_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/echo_path_variability.cc0000664000175000017500000000145514475643423030641 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/echo_path_variability.h" namespace webrtc { EchoPathVariability::EchoPathVariability(bool gain_change, DelayAdjustment delay_change, bool clock_drift) : gain_change(gain_change), delay_change(delay_change), clock_drift(clock_drift) {} } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/echo_path_variability.h0000664000175000017500000000207214475643423030477 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_ECHO_PATH_VARIABILITY_H_ #define MODULES_AUDIO_PROCESSING_AEC3_ECHO_PATH_VARIABILITY_H_ namespace webrtc { struct EchoPathVariability { enum class DelayAdjustment { kNone, kBufferFlush, kNewDetectedDelay }; EchoPathVariability(bool gain_change, DelayAdjustment delay_change, bool clock_drift); bool AudioPathChanged() const { return gain_change || delay_change != DelayAdjustment::kNone; } bool gain_change; DelayAdjustment delay_change; bool clock_drift; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_ECHO_PATH_VARIABILITY_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/echo_remover.cc0000664000175000017500000005232414475643423026766 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/echo_remover.h" #include #include #include #include #include #include #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/aec3_fft.h" #include "modules/audio_processing/aec3/aec_state.h" #include "modules/audio_processing/aec3/comfort_noise_generator.h" #include "modules/audio_processing/aec3/echo_path_variability.h" #include "modules/audio_processing/aec3/echo_remover_metrics.h" #include "modules/audio_processing/aec3/fft_data.h" #include "modules/audio_processing/aec3/render_buffer.h" #include "modules/audio_processing/aec3/render_signal_analyzer.h" #include "modules/audio_processing/aec3/residual_echo_estimator.h" #include "modules/audio_processing/aec3/subtractor.h" #include "modules/audio_processing/aec3/subtractor_output.h" #include "modules/audio_processing/aec3/suppression_filter.h" #include "modules/audio_processing/aec3/suppression_gain.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/atomic_ops.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" namespace webrtc { namespace { // Maximum number of channels for which the capture channel data is stored on // the stack. If the number of channels are larger than this, they are stored // using scratch memory that is pre-allocated on the heap. The reason for this // partitioning is not to waste heap space for handling the more common numbers // of channels, while at the same time not limiting the support for higher // numbers of channels by enforcing the capture channel data to be stored on the // stack using a fixed maximum value. constexpr size_t kMaxNumChannelsOnStack = 2; // Chooses the number of channels to store on the heap when that is required due // to the number of capture channels being larger than the pre-defined number // of channels to store on the stack. size_t NumChannelsOnHeap(size_t num_capture_channels) { return num_capture_channels > kMaxNumChannelsOnStack ? num_capture_channels : 0; } void LinearEchoPower(const FftData& E, const FftData& Y, std::array* S2) { for (size_t k = 0; k < E.re.size(); ++k) { (*S2)[k] = (Y.re[k] - E.re[k]) * (Y.re[k] - E.re[k]) + (Y.im[k] - E.im[k]) * (Y.im[k] - E.im[k]); } } // Fades between two input signals using a fix-sized transition. void SignalTransition(rtc::ArrayView from, rtc::ArrayView to, rtc::ArrayView out) { if (from == to) { RTC_DCHECK_EQ(to.size(), out.size()); std::copy(to.begin(), to.end(), out.begin()); } else { constexpr size_t kTransitionSize = 30; constexpr float kOneByTransitionSizePlusOne = 1.f / (kTransitionSize + 1); RTC_DCHECK_EQ(from.size(), to.size()); RTC_DCHECK_EQ(from.size(), out.size()); RTC_DCHECK_LE(kTransitionSize, out.size()); for (size_t k = 0; k < kTransitionSize; ++k) { float a = (k + 1) * kOneByTransitionSizePlusOne; out[k] = a * to[k] + (1.f - a) * from[k]; } std::copy(to.begin() + kTransitionSize, to.end(), out.begin() + kTransitionSize); } } // Computes a windowed (square root Hanning) padded FFT and updates the related // memory. void WindowedPaddedFft(const Aec3Fft& fft, rtc::ArrayView v, rtc::ArrayView v_old, FftData* V) { fft.PaddedFft(v, v_old, Aec3Fft::Window::kSqrtHanning, V); std::copy(v.begin(), v.end(), v_old.begin()); } // Class for removing the echo from the capture signal. class EchoRemoverImpl final : public EchoRemover { public: EchoRemoverImpl(const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels, size_t num_capture_channels); ~EchoRemoverImpl() override; EchoRemoverImpl(const EchoRemoverImpl&) = delete; EchoRemoverImpl& operator=(const EchoRemoverImpl&) = delete; void GetMetrics(EchoControl::Metrics* metrics) const override; // Removes the echo from a block of samples from the capture signal. The // supplied render signal is assumed to be pre-aligned with the capture // signal. void ProcessCapture( EchoPathVariability echo_path_variability, bool capture_signal_saturation, const absl::optional& external_delay, RenderBuffer* render_buffer, std::vector>>* linear_output, std::vector>>* capture) override; // Updates the status on whether echo leakage is detected in the output of the // echo remover. void UpdateEchoLeakageStatus(bool leakage_detected) override { echo_leakage_detected_ = leakage_detected; } private: // Selects which of the coarse and refined linear filter outputs that is most // appropriate to pass to the suppressor and forms the linear filter output by // smoothly transition between those. void FormLinearFilterOutput(const SubtractorOutput& subtractor_output, rtc::ArrayView output); static int instance_count_; const EchoCanceller3Config config_; const Aec3Fft fft_; std::unique_ptr data_dumper_; const Aec3Optimization optimization_; const int sample_rate_hz_; const size_t num_render_channels_; const size_t num_capture_channels_; const bool use_coarse_filter_output_; Subtractor subtractor_; SuppressionGain suppression_gain_; ComfortNoiseGenerator cng_; SuppressionFilter suppression_filter_; RenderSignalAnalyzer render_signal_analyzer_; ResidualEchoEstimator residual_echo_estimator_; bool echo_leakage_detected_ = false; AecState aec_state_; EchoRemoverMetrics metrics_; std::vector> e_old_; std::vector> y_old_; size_t block_counter_ = 0; int gain_change_hangover_ = 0; bool refined_filter_output_last_selected_ = true; std::vector> e_heap_; std::vector> Y2_heap_; std::vector> E2_heap_; std::vector> R2_heap_; std::vector> S2_linear_heap_; std::vector Y_heap_; std::vector E_heap_; std::vector comfort_noise_heap_; std::vector high_band_comfort_noise_heap_; std::vector subtractor_output_heap_; }; int EchoRemoverImpl::instance_count_ = 0; EchoRemoverImpl::EchoRemoverImpl(const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels, size_t num_capture_channels) : config_(config), fft_(), data_dumper_( new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), optimization_(DetectOptimization()), sample_rate_hz_(sample_rate_hz), num_render_channels_(num_render_channels), num_capture_channels_(num_capture_channels), use_coarse_filter_output_( config_.filter.enable_coarse_filter_output_usage), subtractor_(config, num_render_channels_, num_capture_channels_, data_dumper_.get(), optimization_), suppression_gain_(config_, optimization_, sample_rate_hz, num_capture_channels), cng_(config_, optimization_, num_capture_channels_), suppression_filter_(optimization_, sample_rate_hz_, num_capture_channels_), render_signal_analyzer_(config_), residual_echo_estimator_(config_, num_render_channels), aec_state_(config_, num_capture_channels_), e_old_(num_capture_channels_, {0.f}), y_old_(num_capture_channels_, {0.f}), e_heap_(NumChannelsOnHeap(num_capture_channels_), {0.f}), Y2_heap_(NumChannelsOnHeap(num_capture_channels_)), E2_heap_(NumChannelsOnHeap(num_capture_channels_)), R2_heap_(NumChannelsOnHeap(num_capture_channels_)), S2_linear_heap_(NumChannelsOnHeap(num_capture_channels_)), Y_heap_(NumChannelsOnHeap(num_capture_channels_)), E_heap_(NumChannelsOnHeap(num_capture_channels_)), comfort_noise_heap_(NumChannelsOnHeap(num_capture_channels_)), high_band_comfort_noise_heap_(NumChannelsOnHeap(num_capture_channels_)), subtractor_output_heap_(NumChannelsOnHeap(num_capture_channels_)) { RTC_DCHECK(ValidFullBandRate(sample_rate_hz)); } EchoRemoverImpl::~EchoRemoverImpl() = default; void EchoRemoverImpl::GetMetrics(EchoControl::Metrics* metrics) const { // Echo return loss (ERL) is inverted to go from gain to attenuation. metrics->echo_return_loss = -10.0 * std::log10(aec_state_.ErlTimeDomain()); metrics->echo_return_loss_enhancement = Log2TodB(aec_state_.FullBandErleLog2()); } void EchoRemoverImpl::ProcessCapture( EchoPathVariability echo_path_variability, bool capture_signal_saturation, const absl::optional& external_delay, RenderBuffer* render_buffer, std::vector>>* linear_output, std::vector>>* capture) { ++block_counter_; const std::vector>>& x = render_buffer->Block(0); std::vector>>* y = capture; RTC_DCHECK(render_buffer); RTC_DCHECK(y); RTC_DCHECK_EQ(x.size(), NumBandsForRate(sample_rate_hz_)); RTC_DCHECK_EQ(y->size(), NumBandsForRate(sample_rate_hz_)); RTC_DCHECK_EQ(x[0].size(), num_render_channels_); RTC_DCHECK_EQ((*y)[0].size(), num_capture_channels_); RTC_DCHECK_EQ(x[0][0].size(), kBlockSize); RTC_DCHECK_EQ((*y)[0][0].size(), kBlockSize); // Stack allocated data to use when the number of channels is low. std::array, kMaxNumChannelsOnStack> e_stack; std::array, kMaxNumChannelsOnStack> Y2_stack; std::array, kMaxNumChannelsOnStack> E2_stack; std::array, kMaxNumChannelsOnStack> R2_stack; std::array, kMaxNumChannelsOnStack> S2_linear_stack; std::array Y_stack; std::array E_stack; std::array comfort_noise_stack; std::array high_band_comfort_noise_stack; std::array subtractor_output_stack; rtc::ArrayView> e(e_stack.data(), num_capture_channels_); rtc::ArrayView> Y2( Y2_stack.data(), num_capture_channels_); rtc::ArrayView> E2( E2_stack.data(), num_capture_channels_); rtc::ArrayView> R2( R2_stack.data(), num_capture_channels_); rtc::ArrayView> S2_linear( S2_linear_stack.data(), num_capture_channels_); rtc::ArrayView Y(Y_stack.data(), num_capture_channels_); rtc::ArrayView E(E_stack.data(), num_capture_channels_); rtc::ArrayView comfort_noise(comfort_noise_stack.data(), num_capture_channels_); rtc::ArrayView high_band_comfort_noise( high_band_comfort_noise_stack.data(), num_capture_channels_); rtc::ArrayView subtractor_output( subtractor_output_stack.data(), num_capture_channels_); if (NumChannelsOnHeap(num_capture_channels_) > 0) { // If the stack-allocated space is too small, use the heap for storing the // microphone data. e = rtc::ArrayView>(e_heap_.data(), num_capture_channels_); Y2 = rtc::ArrayView>( Y2_heap_.data(), num_capture_channels_); E2 = rtc::ArrayView>( E2_heap_.data(), num_capture_channels_); R2 = rtc::ArrayView>( R2_heap_.data(), num_capture_channels_); S2_linear = rtc::ArrayView>( S2_linear_heap_.data(), num_capture_channels_); Y = rtc::ArrayView(Y_heap_.data(), num_capture_channels_); E = rtc::ArrayView(E_heap_.data(), num_capture_channels_); comfort_noise = rtc::ArrayView(comfort_noise_heap_.data(), num_capture_channels_); high_band_comfort_noise = rtc::ArrayView( high_band_comfort_noise_heap_.data(), num_capture_channels_); subtractor_output = rtc::ArrayView( subtractor_output_heap_.data(), num_capture_channels_); } data_dumper_->DumpWav("aec3_echo_remover_capture_input", kBlockSize, &(*y)[0][0][0], 16000, 1); data_dumper_->DumpWav("aec3_echo_remover_render_input", kBlockSize, &x[0][0][0], 16000, 1); data_dumper_->DumpRaw("aec3_echo_remover_capture_input", (*y)[0][0]); data_dumper_->DumpRaw("aec3_echo_remover_render_input", x[0][0]); aec_state_.UpdateCaptureSaturation(capture_signal_saturation); if (echo_path_variability.AudioPathChanged()) { // Ensure that the gain change is only acted on once per frame. if (echo_path_variability.gain_change) { if (gain_change_hangover_ == 0) { constexpr int kMaxBlocksPerFrame = 3; gain_change_hangover_ = kMaxBlocksPerFrame; rtc::LoggingSeverity log_level = config_.delay.log_warning_on_delay_changes ? rtc::LS_WARNING : rtc::LS_VERBOSE; RTC_LOG_V(log_level) << "Gain change detected at block " << block_counter_; } else { echo_path_variability.gain_change = false; } } subtractor_.HandleEchoPathChange(echo_path_variability); aec_state_.HandleEchoPathChange(echo_path_variability); if (echo_path_variability.delay_change != EchoPathVariability::DelayAdjustment::kNone) { suppression_gain_.SetInitialState(true); } } if (gain_change_hangover_ > 0) { --gain_change_hangover_; } // Analyze the render signal. render_signal_analyzer_.Update(*render_buffer, aec_state_.MinDirectPathFilterDelay()); // State transition. if (aec_state_.TransitionTriggered()) { subtractor_.ExitInitialState(); suppression_gain_.SetInitialState(false); } // Perform linear echo cancellation. subtractor_.Process(*render_buffer, (*y)[0], render_signal_analyzer_, aec_state_, subtractor_output); // Compute spectra. for (size_t ch = 0; ch < num_capture_channels_; ++ch) { FormLinearFilterOutput(subtractor_output[ch], e[ch]); WindowedPaddedFft(fft_, (*y)[0][ch], y_old_[ch], &Y[ch]); WindowedPaddedFft(fft_, e[ch], e_old_[ch], &E[ch]); LinearEchoPower(E[ch], Y[ch], &S2_linear[ch]); Y[ch].Spectrum(optimization_, Y2[ch]); E[ch].Spectrum(optimization_, E2[ch]); } // Optionally return the linear filter output. if (linear_output) { RTC_DCHECK_GE(1, linear_output->size()); RTC_DCHECK_EQ(num_capture_channels_, linear_output[0].size()); for (size_t ch = 0; ch < num_capture_channels_; ++ch) { RTC_DCHECK_EQ(kBlockSize, (*linear_output)[0][ch].size()); std::copy(e[ch].begin(), e[ch].end(), (*linear_output)[0][ch].begin()); } } // Update the AEC state information. aec_state_.Update(external_delay, subtractor_.FilterFrequencyResponses(), subtractor_.FilterImpulseResponses(), *render_buffer, E2, Y2, subtractor_output); // Choose the linear output. const auto& Y_fft = aec_state_.UseLinearFilterOutput() ? E : Y; data_dumper_->DumpWav("aec3_output_linear", kBlockSize, &(*y)[0][0][0], 16000, 1); data_dumper_->DumpWav("aec3_output_linear2", kBlockSize, &e[0][0], 16000, 1); // Estimate the residual echo power. residual_echo_estimator_.Estimate(aec_state_, *render_buffer, S2_linear, Y2, R2); // Estimate the comfort noise. cng_.Compute(aec_state_.SaturatedCapture(), Y2, comfort_noise, high_band_comfort_noise); // Suppressor nearend estimate. if (aec_state_.UsableLinearEstimate()) { // E2 is bound by Y2. for (size_t ch = 0; ch < num_capture_channels_; ++ch) { std::transform(E2[ch].begin(), E2[ch].end(), Y2[ch].begin(), E2[ch].begin(), [](float a, float b) { return std::min(a, b); }); } } const auto& nearend_spectrum = aec_state_.UsableLinearEstimate() ? E2 : Y2; // Suppressor echo estimate. const auto& echo_spectrum = aec_state_.UsableLinearEstimate() ? S2_linear : R2; // Compute preferred gains. float high_bands_gain; std::array G; suppression_gain_.GetGain(nearend_spectrum, echo_spectrum, R2, cng_.NoiseSpectrum(), render_signal_analyzer_, aec_state_, x, &high_bands_gain, &G); suppression_filter_.ApplyGain(comfort_noise, high_band_comfort_noise, G, high_bands_gain, Y_fft, y); // Update the metrics. metrics_.Update(aec_state_, cng_.NoiseSpectrum()[0], G); // Debug outputs for the purpose of development and analysis. data_dumper_->DumpWav("aec3_echo_estimate", kBlockSize, &subtractor_output[0].s_refined[0], 16000, 1); data_dumper_->DumpRaw("aec3_output", (*y)[0][0]); data_dumper_->DumpRaw("aec3_narrow_render", render_signal_analyzer_.NarrowPeakBand() ? 1 : 0); data_dumper_->DumpRaw("aec3_N2", cng_.NoiseSpectrum()[0]); data_dumper_->DumpRaw("aec3_suppressor_gain", G); data_dumper_->DumpWav("aec3_output", rtc::ArrayView(&(*y)[0][0][0], kBlockSize), 16000, 1); data_dumper_->DumpRaw("aec3_using_subtractor_output[0]", aec_state_.UseLinearFilterOutput() ? 1 : 0); data_dumper_->DumpRaw("aec3_E2", E2[0]); data_dumper_->DumpRaw("aec3_S2_linear", S2_linear[0]); data_dumper_->DumpRaw("aec3_Y2", Y2[0]); data_dumper_->DumpRaw( "aec3_X2", render_buffer->Spectrum( aec_state_.MinDirectPathFilterDelay())[/*channel=*/0]); data_dumper_->DumpRaw("aec3_R2", R2[0]); data_dumper_->DumpRaw("aec3_filter_delay", aec_state_.MinDirectPathFilterDelay()); data_dumper_->DumpRaw("aec3_capture_saturation", aec_state_.SaturatedCapture() ? 1 : 0); } void EchoRemoverImpl::FormLinearFilterOutput( const SubtractorOutput& subtractor_output, rtc::ArrayView output) { RTC_DCHECK_EQ(subtractor_output.e_refined.size(), output.size()); RTC_DCHECK_EQ(subtractor_output.e_coarse.size(), output.size()); bool use_refined_output = true; if (use_coarse_filter_output_) { // As the output of the refined adaptive filter generally should be better // than the coarse filter output, add a margin and threshold for when // choosing the coarse filter output. if (subtractor_output.e2_coarse < 0.9f * subtractor_output.e2_refined && subtractor_output.y2 > 30.f * 30.f * kBlockSize && (subtractor_output.s2_refined > 60.f * 60.f * kBlockSize || subtractor_output.s2_coarse > 60.f * 60.f * kBlockSize)) { use_refined_output = false; } else { // If the refined filter is diverged, choose the filter output that has // the lowest power. if (subtractor_output.e2_coarse < subtractor_output.e2_refined && subtractor_output.y2 < subtractor_output.e2_refined) { use_refined_output = false; } } } SignalTransition(refined_filter_output_last_selected_ ? subtractor_output.e_refined : subtractor_output.e_coarse, use_refined_output ? subtractor_output.e_refined : subtractor_output.e_coarse, output); refined_filter_output_last_selected_ = use_refined_output; } } // namespace EchoRemover* EchoRemover::Create(const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels, size_t num_capture_channels) { return new EchoRemoverImpl(config, sample_rate_hz, num_render_channels, num_capture_channels); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/echo_remover.h0000664000175000017500000000402114475643423026617 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_ECHO_REMOVER_H_ #define MODULES_AUDIO_PROCESSING_AEC3_ECHO_REMOVER_H_ #include #include "absl/types/optional.h" #include "api/audio/echo_canceller3_config.h" #include "api/audio/echo_control.h" #include "modules/audio_processing/aec3/delay_estimate.h" #include "modules/audio_processing/aec3/echo_path_variability.h" #include "modules/audio_processing/aec3/render_buffer.h" namespace webrtc { // Class for removing the echo from the capture signal. class EchoRemover { public: static EchoRemover* Create(const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels, size_t num_capture_channels); virtual ~EchoRemover() = default; // Get current metrics. virtual void GetMetrics(EchoControl::Metrics* metrics) const = 0; // Removes the echo from a block of samples from the capture signal. The // supplied render signal is assumed to be pre-aligned with the capture // signal. virtual void ProcessCapture( EchoPathVariability echo_path_variability, bool capture_signal_saturation, const absl::optional& external_delay, RenderBuffer* render_buffer, std::vector>>* linear_output, std::vector>>* capture) = 0; // Updates the status on whether echo leakage is detected in the output of the // echo remover. virtual void UpdateEchoLeakageStatus(bool leakage_detected) = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_ECHO_REMOVER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/echo_remover_metrics.cc0000664000175000017500000002431414475643423030512 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/echo_remover_metrics.h" #include #include #include #include #include #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_minmax.h" #include "system_wrappers/include/metrics.h" namespace webrtc { namespace { constexpr float kOneByMetricsCollectionBlocks = 1.f / kMetricsCollectionBlocks; } // namespace EchoRemoverMetrics::DbMetric::DbMetric() : DbMetric(0.f, 0.f, 0.f) {} EchoRemoverMetrics::DbMetric::DbMetric(float sum_value, float floor_value, float ceil_value) : sum_value(sum_value), floor_value(floor_value), ceil_value(ceil_value) {} void EchoRemoverMetrics::DbMetric::Update(float value) { sum_value += value; floor_value = std::min(floor_value, value); ceil_value = std::max(ceil_value, value); } void EchoRemoverMetrics::DbMetric::UpdateInstant(float value) { sum_value = value; floor_value = std::min(floor_value, value); ceil_value = std::max(ceil_value, value); } EchoRemoverMetrics::EchoRemoverMetrics() { ResetMetrics(); } void EchoRemoverMetrics::ResetMetrics() { erl_.fill(DbMetric(0.f, 10000.f, 0.000f)); erl_time_domain_ = DbMetric(0.f, 10000.f, 0.000f); erle_.fill(DbMetric(0.f, 0.f, 1000.f)); erle_time_domain_ = DbMetric(0.f, 0.f, 1000.f); active_render_count_ = 0; saturated_capture_ = false; } void EchoRemoverMetrics::Update( const AecState& aec_state, const std::array& comfort_noise_spectrum, const std::array& suppressor_gain) { metrics_reported_ = false; if (++block_counter_ <= kMetricsCollectionBlocks) { aec3::UpdateDbMetric(aec_state.Erl(), &erl_); erl_time_domain_.UpdateInstant(aec_state.ErlTimeDomain()); aec3::UpdateDbMetric(aec_state.Erle()[0], &erle_); erle_time_domain_.UpdateInstant(aec_state.FullBandErleLog2()); active_render_count_ += (aec_state.ActiveRender() ? 1 : 0); saturated_capture_ = saturated_capture_ || aec_state.SaturatedCapture(); } else { // Report the metrics over several frames in order to lower the impact of // the logarithms involved on the computational complexity. constexpr int kMetricsCollectionBlocksBy2 = kMetricsCollectionBlocks / 2; switch (block_counter_) { case kMetricsCollectionBlocks + 1: RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.ErleBand0.Average", aec3::TransformDbMetricForReporting(true, 0.f, 19.f, 0.f, kOneByMetricsCollectionBlocks, erle_[0].sum_value), 0, 19, 20); RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.ErleBand0.Max", aec3::TransformDbMetricForReporting(true, 0.f, 19.f, 0.f, 1.f, erle_[0].ceil_value), 0, 19, 20); RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.ErleBand0.Min", aec3::TransformDbMetricForReporting(true, 0.f, 19.f, 0.f, 1.f, erle_[0].floor_value), 0, 19, 20); break; case kMetricsCollectionBlocks + 2: RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.ErleBand1.Average", aec3::TransformDbMetricForReporting(true, 0.f, 19.f, 0.f, kOneByMetricsCollectionBlocks, erle_[1].sum_value), 0, 19, 20); RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.ErleBand1.Max", aec3::TransformDbMetricForReporting(true, 0.f, 19.f, 0.f, 1.f, erle_[1].ceil_value), 0, 19, 20); RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.ErleBand1.Min", aec3::TransformDbMetricForReporting(true, 0.f, 19.f, 0.f, 1.f, erle_[1].floor_value), 0, 19, 20); break; case kMetricsCollectionBlocks + 3: RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.ErlBand0.Average", aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, kOneByMetricsCollectionBlocks, erl_[0].sum_value), 0, 59, 30); RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.ErlBand0.Max", aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f, erl_[0].ceil_value), 0, 59, 30); RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.ErlBand0.Min", aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f, erl_[0].floor_value), 0, 59, 30); break; case kMetricsCollectionBlocks + 4: RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.ErlBand1.Average", aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, kOneByMetricsCollectionBlocks, erl_[1].sum_value), 0, 59, 30); RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.ErlBand1.Max", aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f, erl_[1].ceil_value), 0, 59, 30); RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.ErlBand1.Min", aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f, erl_[1].floor_value), 0, 59, 30); break; case kMetricsCollectionBlocks + 5: RTC_HISTOGRAM_BOOLEAN( "WebRTC.Audio.EchoCanceller.UsableLinearEstimate", static_cast(aec_state.UsableLinearEstimate() ? 1 : 0)); RTC_HISTOGRAM_BOOLEAN( "WebRTC.Audio.EchoCanceller.ActiveRender", static_cast( active_render_count_ > kMetricsCollectionBlocksBy2 ? 1 : 0)); RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.FilterDelay", aec_state.MinDirectPathFilterDelay(), 0, 30, 31); RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.EchoCanceller.CaptureSaturation", static_cast(saturated_capture_ ? 1 : 0)); break; case kMetricsCollectionBlocks + 6: RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.Erl.Value", aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f, erl_time_domain_.sum_value), 0, 59, 30); RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.Erl.Max", aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f, erl_time_domain_.ceil_value), 0, 59, 30); RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.Erl.Min", aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f, erl_time_domain_.floor_value), 0, 59, 30); break; case kMetricsCollectionBlocks + 7: RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.Erle.Value", aec3::TransformDbMetricForReporting(false, 0.f, 19.f, 0.f, 1.f, erle_time_domain_.sum_value), 0, 19, 20); RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.Erle.Max", aec3::TransformDbMetricForReporting(false, 0.f, 19.f, 0.f, 1.f, erle_time_domain_.ceil_value), 0, 19, 20); RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.EchoCanceller.Erle.Min", aec3::TransformDbMetricForReporting(false, 0.f, 19.f, 0.f, 1.f, erle_time_domain_.floor_value), 0, 19, 20); metrics_reported_ = true; RTC_DCHECK_EQ(kMetricsReportingIntervalBlocks, block_counter_); block_counter_ = 0; ResetMetrics(); break; default: RTC_NOTREACHED(); break; } } } namespace aec3 { void UpdateDbMetric(const std::array& value, std::array* statistic) { RTC_DCHECK(statistic); // Truncation is intended in the band width computation. constexpr int kNumBands = 2; constexpr int kBandWidth = 65 / kNumBands; constexpr float kOneByBandWidth = 1.f / kBandWidth; RTC_DCHECK_EQ(kNumBands, statistic->size()); RTC_DCHECK_EQ(65, value.size()); for (size_t k = 0; k < statistic->size(); ++k) { float average_band = std::accumulate(value.begin() + kBandWidth * k, value.begin() + kBandWidth * (k + 1), 0.f) * kOneByBandWidth; (*statistic)[k].Update(average_band); } } int TransformDbMetricForReporting(bool negate, float min_value, float max_value, float offset, float scaling, float value) { float new_value = 10.f * std::log10(value * scaling + 1e-10f) + offset; if (negate) { new_value = -new_value; } return static_cast(rtc::SafeClamp(new_value, min_value, max_value)); } } // namespace aec3 } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/echo_remover_metrics.h0000664000175000017500000000477314475643423030363 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_ECHO_REMOVER_METRICS_H_ #define MODULES_AUDIO_PROCESSING_AEC3_ECHO_REMOVER_METRICS_H_ #include #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/aec_state.h" #include "rtc_base/constructor_magic.h" namespace webrtc { // Handles the reporting of metrics for the echo remover. class EchoRemoverMetrics { public: struct DbMetric { DbMetric(); DbMetric(float sum_value, float floor_value, float ceil_value); void Update(float value); void UpdateInstant(float value); float sum_value; float floor_value; float ceil_value; }; EchoRemoverMetrics(); // Updates the metric with new data. void Update( const AecState& aec_state, const std::array& comfort_noise_spectrum, const std::array& suppressor_gain); // Returns true if the metrics have just been reported, otherwise false. bool MetricsReported() { return metrics_reported_; } private: // Resets the metrics. void ResetMetrics(); int block_counter_ = 0; std::array erl_; DbMetric erl_time_domain_; std::array erle_; DbMetric erle_time_domain_; int active_render_count_ = 0; bool saturated_capture_ = false; bool metrics_reported_ = false; RTC_DISALLOW_COPY_AND_ASSIGN(EchoRemoverMetrics); }; namespace aec3 { // Updates a banded metric of type DbMetric with the values in the supplied // array. void UpdateDbMetric(const std::array& value, std::array* statistic); // Transforms a DbMetric from the linear domain into the logarithmic domain. int TransformDbMetricForReporting(bool negate, float min_value, float max_value, float offset, float scaling, float value); } // namespace aec3 } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_ECHO_REMOVER_METRICS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/erl_estimator.cc0000664000175000017500000001157714475643423027167 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/erl_estimator.h" #include #include #include "rtc_base/checks.h" namespace webrtc { namespace { constexpr float kMinErl = 0.01f; constexpr float kMaxErl = 1000.f; } // namespace ErlEstimator::ErlEstimator(size_t startup_phase_length_blocks_) : startup_phase_length_blocks__(startup_phase_length_blocks_) { erl_.fill(kMaxErl); hold_counters_.fill(0); erl_time_domain_ = kMaxErl; hold_counter_time_domain_ = 0; } ErlEstimator::~ErlEstimator() = default; void ErlEstimator::Reset() { blocks_since_reset_ = 0; } void ErlEstimator::Update( const std::vector& converged_filters, rtc::ArrayView> render_spectra, rtc::ArrayView> capture_spectra) { const size_t num_capture_channels = converged_filters.size(); RTC_DCHECK_EQ(capture_spectra.size(), num_capture_channels); // Corresponds to WGN of power -46 dBFS. constexpr float kX2Min = 44015068.0f; const auto first_converged_iter = std::find(converged_filters.begin(), converged_filters.end(), true); const bool any_filter_converged = first_converged_iter != converged_filters.end(); if (++blocks_since_reset_ < startup_phase_length_blocks__ || !any_filter_converged) { return; } // Use the maximum spectrum across capture and the maximum across render. std::array max_capture_spectrum_data; std::array max_capture_spectrum = capture_spectra[/*channel=*/0]; if (num_capture_channels > 1) { // Initialize using the first channel with a converged filter. const size_t first_converged = std::distance(converged_filters.begin(), first_converged_iter); RTC_DCHECK_GE(first_converged, 0); RTC_DCHECK_LT(first_converged, num_capture_channels); max_capture_spectrum_data = capture_spectra[first_converged]; for (size_t ch = first_converged + 1; ch < num_capture_channels; ++ch) { if (!converged_filters[ch]) { continue; } for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { max_capture_spectrum_data[k] = std::max(max_capture_spectrum_data[k], capture_spectra[ch][k]); } } max_capture_spectrum = max_capture_spectrum_data; } const size_t num_render_channels = render_spectra.size(); std::array max_render_spectrum_data; rtc::ArrayView max_render_spectrum = render_spectra[/*channel=*/0]; if (num_render_channels > 1) { std::copy(render_spectra[0].begin(), render_spectra[0].end(), max_render_spectrum_data.begin()); for (size_t ch = 1; ch < num_render_channels; ++ch) { for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { max_render_spectrum_data[k] = std::max(max_render_spectrum_data[k], render_spectra[ch][k]); } } max_render_spectrum = max_render_spectrum_data; } const auto& X2 = max_render_spectrum; const auto& Y2 = max_capture_spectrum; // Update the estimates in a maximum statistics manner. for (size_t k = 1; k < kFftLengthBy2; ++k) { if (X2[k] > kX2Min) { const float new_erl = Y2[k] / X2[k]; if (new_erl < erl_[k]) { hold_counters_[k - 1] = 1000; erl_[k] += 0.1f * (new_erl - erl_[k]); erl_[k] = std::max(erl_[k], kMinErl); } } } std::for_each(hold_counters_.begin(), hold_counters_.end(), [](int& a) { --a; }); std::transform(hold_counters_.begin(), hold_counters_.end(), erl_.begin() + 1, erl_.begin() + 1, [](int a, float b) { return a > 0 ? b : std::min(kMaxErl, 2.f * b); }); erl_[0] = erl_[1]; erl_[kFftLengthBy2] = erl_[kFftLengthBy2 - 1]; // Compute ERL over all frequency bins. const float X2_sum = std::accumulate(X2.begin(), X2.end(), 0.0f); if (X2_sum > kX2Min * X2.size()) { const float Y2_sum = std::accumulate(Y2.begin(), Y2.end(), 0.0f); const float new_erl = Y2_sum / X2_sum; if (new_erl < erl_time_domain_) { hold_counter_time_domain_ = 1000; erl_time_domain_ += 0.1f * (new_erl - erl_time_domain_); erl_time_domain_ = std::max(erl_time_domain_, kMinErl); } } --hold_counter_time_domain_; erl_time_domain_ = (hold_counter_time_domain_ > 0) ? erl_time_domain_ : std::min(kMaxErl, 2.f * erl_time_domain_); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/erl_estimator.h0000664000175000017500000000343314475643423027021 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_ERL_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_AEC3_ERL_ESTIMATOR_H_ #include #include #include #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "rtc_base/constructor_magic.h" namespace webrtc { // Estimates the echo return loss based on the signal spectra. class ErlEstimator { public: explicit ErlEstimator(size_t startup_phase_length_blocks_); ~ErlEstimator(); // Resets the ERL estimation. void Reset(); // Updates the ERL estimate. void Update(const std::vector& converged_filters, rtc::ArrayView> render_spectra, rtc::ArrayView> capture_spectra); // Returns the most recent ERL estimate. const std::array& Erl() const { return erl_; } float ErlTimeDomain() const { return erl_time_domain_; } private: const size_t startup_phase_length_blocks__; std::array erl_; std::array hold_counters_; float erl_time_domain_; int hold_counter_time_domain_; size_t blocks_since_reset_ = 0; RTC_DISALLOW_COPY_AND_ASSIGN(ErlEstimator); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_ERL_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/erle_estimator.cc0000664000175000017500000000601314475643423027321 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/erle_estimator.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "rtc_base/checks.h" namespace webrtc { ErleEstimator::ErleEstimator(size_t startup_phase_length_blocks, const EchoCanceller3Config& config, size_t num_capture_channels) : startup_phase_length_blocks_(startup_phase_length_blocks), fullband_erle_estimator_(config.erle, num_capture_channels), subband_erle_estimator_(config, num_capture_channels) { if (config.erle.num_sections > 1) { signal_dependent_erle_estimator_ = std::make_unique(config, num_capture_channels); } Reset(true); } ErleEstimator::~ErleEstimator() = default; void ErleEstimator::Reset(bool delay_change) { fullband_erle_estimator_.Reset(); subband_erle_estimator_.Reset(); if (signal_dependent_erle_estimator_) { signal_dependent_erle_estimator_->Reset(); } if (delay_change) { blocks_since_reset_ = 0; } } void ErleEstimator::Update( const RenderBuffer& render_buffer, rtc::ArrayView>> filter_frequency_responses, rtc::ArrayView avg_render_spectrum_with_reverb, rtc::ArrayView> capture_spectra, rtc::ArrayView> subtractor_spectra, const std::vector& converged_filters) { RTC_DCHECK_EQ(subband_erle_estimator_.Erle().size(), capture_spectra.size()); RTC_DCHECK_EQ(subband_erle_estimator_.Erle().size(), subtractor_spectra.size()); const auto& X2_reverb = avg_render_spectrum_with_reverb; const auto& Y2 = capture_spectra; const auto& E2 = subtractor_spectra; if (++blocks_since_reset_ < startup_phase_length_blocks_) { return; } subband_erle_estimator_.Update(X2_reverb, Y2, E2, converged_filters); if (signal_dependent_erle_estimator_) { signal_dependent_erle_estimator_->Update( render_buffer, filter_frequency_responses, X2_reverb, Y2, E2, subband_erle_estimator_.Erle(), converged_filters); } fullband_erle_estimator_.Update(X2_reverb, Y2, E2, converged_filters); } void ErleEstimator::Dump( const std::unique_ptr& data_dumper) const { fullband_erle_estimator_.Dump(data_dumper); subband_erle_estimator_.Dump(data_dumper); if (signal_dependent_erle_estimator_) { signal_dependent_erle_estimator_->Dump(data_dumper); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/erle_estimator.h0000664000175000017500000000717714475643423027177 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_ERLE_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_AEC3_ERLE_ESTIMATOR_H_ #include #include #include #include #include "absl/types/optional.h" #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/fullband_erle_estimator.h" #include "modules/audio_processing/aec3/render_buffer.h" #include "modules/audio_processing/aec3/signal_dependent_erle_estimator.h" #include "modules/audio_processing/aec3/subband_erle_estimator.h" #include "modules/audio_processing/logging/apm_data_dumper.h" namespace webrtc { // Estimates the echo return loss enhancement. One estimate is done per subband // and another one is done using the aggreation of energy over all the subbands. class ErleEstimator { public: ErleEstimator(size_t startup_phase_length_blocks, const EchoCanceller3Config& config, size_t num_capture_channels); ~ErleEstimator(); // Resets the fullband ERLE estimator and the subbands ERLE estimators. void Reset(bool delay_change); // Updates the ERLE estimates. void Update( const RenderBuffer& render_buffer, rtc::ArrayView>> filter_frequency_responses, rtc::ArrayView avg_render_spectrum_with_reverb, rtc::ArrayView> capture_spectra, rtc::ArrayView> subtractor_spectra, const std::vector& converged_filters); // Returns the most recent subband ERLE estimates. rtc::ArrayView> Erle() const { return signal_dependent_erle_estimator_ ? signal_dependent_erle_estimator_->Erle() : subband_erle_estimator_.Erle(); } // Returns the subband ERLE that are estimated during onsets (only used for // testing). rtc::ArrayView> ErleOnsets() const { return subband_erle_estimator_.ErleOnsets(); } // Returns the fullband ERLE estimate. float FullbandErleLog2() const { return fullband_erle_estimator_.FullbandErleLog2(); } // Returns an estimation of the current linear filter quality based on the // current and past fullband ERLE estimates. The returned value is a float // vector with content between 0 and 1 where 1 indicates that, at this current // time instant, the linear filter is reaching its maximum subtraction // performance. rtc::ArrayView> GetInstLinearQualityEstimates() const { return fullband_erle_estimator_.GetInstLinearQualityEstimates(); } void Dump(const std::unique_ptr& data_dumper) const; private: const size_t startup_phase_length_blocks_; FullBandErleEstimator fullband_erle_estimator_; SubbandErleEstimator subband_erle_estimator_; std::unique_ptr signal_dependent_erle_estimator_; size_t blocks_since_reset_ = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_ERLE_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/fft_buffer.cc0000664000175000017500000000145714475643423026422 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/fft_buffer.h" namespace webrtc { FftBuffer::FftBuffer(size_t size, size_t num_channels) : size(static_cast(size)), buffer(size, std::vector(num_channels)) { for (auto& block : buffer) { for (auto& channel_fft_data : block) { channel_fft_data.Clear(); } } } FftBuffer::~FftBuffer() = default; } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/fft_buffer.h0000664000175000017500000000351514475643423026261 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_FFT_BUFFER_H_ #define MODULES_AUDIO_PROCESSING_AEC3_FFT_BUFFER_H_ #include #include #include "modules/audio_processing/aec3/fft_data.h" #include "rtc_base/checks.h" namespace webrtc { // Struct for bundling a circular buffer of FftData objects together with the // read and write indices. struct FftBuffer { FftBuffer(size_t size, size_t num_channels); ~FftBuffer(); int IncIndex(int index) const { RTC_DCHECK_EQ(buffer.size(), static_cast(size)); return index < size - 1 ? index + 1 : 0; } int DecIndex(int index) const { RTC_DCHECK_EQ(buffer.size(), static_cast(size)); return index > 0 ? index - 1 : size - 1; } int OffsetIndex(int index, int offset) const { RTC_DCHECK_GE(buffer.size(), offset); RTC_DCHECK_EQ(buffer.size(), static_cast(size)); return (size + index + offset) % size; } void UpdateWriteIndex(int offset) { write = OffsetIndex(write, offset); } void IncWriteIndex() { write = IncIndex(write); } void DecWriteIndex() { write = DecIndex(write); } void UpdateReadIndex(int offset) { read = OffsetIndex(read, offset); } void IncReadIndex() { read = IncIndex(read); } void DecReadIndex() { read = DecIndex(read); } const int size; std::vector> buffer; int write = 0; int read = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_FFT_BUFFER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/fft_data.h0000664000175000017500000000640714475643423025724 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_FFT_DATA_H_ #define MODULES_AUDIO_PROCESSING_AEC3_FFT_DATA_H_ // Defines WEBRTC_ARCH_X86_FAMILY, used below. #include "rtc_base/system/arch.h" #if defined(WEBRTC_ARCH_X86_FAMILY) #include #endif #include #include #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" namespace webrtc { // Struct that holds imaginary data produced from 128 point real-valued FFTs. struct FftData { // Copies the data in src. void Assign(const FftData& src) { std::copy(src.re.begin(), src.re.end(), re.begin()); std::copy(src.im.begin(), src.im.end(), im.begin()); im[0] = im[kFftLengthBy2] = 0; } // Clears all the imaginary. void Clear() { re.fill(0.f); im.fill(0.f); } // Computes the power spectrum of the data. void SpectrumAVX2(rtc::ArrayView power_spectrum) const; // Computes the power spectrum of the data. void Spectrum(Aec3Optimization optimization, rtc::ArrayView power_spectrum) const { RTC_DCHECK_EQ(kFftLengthBy2Plus1, power_spectrum.size()); switch (optimization) { #if defined(WEBRTC_ARCH_X86_FAMILY) case Aec3Optimization::kSse2: { constexpr int kNumFourBinBands = kFftLengthBy2 / 4; constexpr int kLimit = kNumFourBinBands * 4; for (size_t k = 0; k < kLimit; k += 4) { const __m128 r = _mm_loadu_ps(&re[k]); const __m128 i = _mm_loadu_ps(&im[k]); const __m128 ii = _mm_mul_ps(i, i); const __m128 rr = _mm_mul_ps(r, r); const __m128 rrii = _mm_add_ps(rr, ii); _mm_storeu_ps(&power_spectrum[k], rrii); } power_spectrum[kFftLengthBy2] = re[kFftLengthBy2] * re[kFftLengthBy2] + im[kFftLengthBy2] * im[kFftLengthBy2]; } break; case Aec3Optimization::kAvx2: SpectrumAVX2(power_spectrum); break; #endif default: std::transform(re.begin(), re.end(), im.begin(), power_spectrum.begin(), [](float a, float b) { return a * a + b * b; }); } } // Copy the data from an interleaved array. void CopyFromPackedArray(const std::array& v) { re[0] = v[0]; re[kFftLengthBy2] = v[1]; im[0] = im[kFftLengthBy2] = 0; for (size_t k = 1, j = 2; k < kFftLengthBy2; ++k) { re[k] = v[j++]; im[k] = v[j++]; } } // Copies the data into an interleaved array. void CopyToPackedArray(std::array* v) const { RTC_DCHECK(v); (*v)[0] = re[0]; (*v)[1] = re[kFftLengthBy2]; for (size_t k = 1, j = 2; k < kFftLengthBy2; ++k) { (*v)[j++] = re[k]; (*v)[j++] = im[k]; } } std::array re; std::array im; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_FFT_DATA_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/fft_data_avx2.cc0000664000175000017500000000216714475643423027021 0ustar00arunarun/* * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/fft_data.h" #include #include "api/array_view.h" namespace webrtc { // Computes the power spectrum of the data. void FftData::SpectrumAVX2(rtc::ArrayView power_spectrum) const { RTC_DCHECK_EQ(kFftLengthBy2Plus1, power_spectrum.size()); for (size_t k = 0; k < kFftLengthBy2; k += 8) { __m256 r = _mm256_loadu_ps(&re[k]); __m256 i = _mm256_loadu_ps(&im[k]); __m256 ii = _mm256_mul_ps(i, i); ii = _mm256_fmadd_ps(r, r, ii); _mm256_storeu_ps(&power_spectrum[k], ii); } power_spectrum[kFftLengthBy2] = re[kFftLengthBy2] * re[kFftLengthBy2] + im[kFftLengthBy2] * im[kFftLengthBy2]; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/filter_analyzer.cc0000664000175000017500000002344214475643423027502 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/filter_analyzer.h" #include #include #include #include #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/render_buffer.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/atomic_ops.h" #include "rtc_base/checks.h" namespace webrtc { namespace { size_t FindPeakIndex(rtc::ArrayView filter_time_domain, size_t peak_index_in, size_t start_sample, size_t end_sample) { size_t peak_index_out = peak_index_in; float max_h2 = filter_time_domain[peak_index_out] * filter_time_domain[peak_index_out]; for (size_t k = start_sample; k <= end_sample; ++k) { float tmp = filter_time_domain[k] * filter_time_domain[k]; if (tmp > max_h2) { peak_index_out = k; max_h2 = tmp; } } return peak_index_out; } } // namespace int FilterAnalyzer::instance_count_ = 0; FilterAnalyzer::FilterAnalyzer(const EchoCanceller3Config& config, size_t num_capture_channels) : data_dumper_( new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), bounded_erl_(config.ep_strength.bounded_erl), default_gain_(config.ep_strength.default_gain), h_highpass_(num_capture_channels, std::vector( GetTimeDomainLength(config.filter.refined.length_blocks), 0.f)), filter_analysis_states_(num_capture_channels, FilterAnalysisState(config)), filter_delays_blocks_(num_capture_channels, 0) { Reset(); } FilterAnalyzer::~FilterAnalyzer() = default; void FilterAnalyzer::Reset() { blocks_since_reset_ = 0; ResetRegion(); for (auto& state : filter_analysis_states_) { state.Reset(default_gain_); } std::fill(filter_delays_blocks_.begin(), filter_delays_blocks_.end(), 0); } void FilterAnalyzer::Update( rtc::ArrayView> filters_time_domain, const RenderBuffer& render_buffer, bool* any_filter_consistent, float* max_echo_path_gain) { RTC_DCHECK(any_filter_consistent); RTC_DCHECK(max_echo_path_gain); RTC_DCHECK_EQ(filters_time_domain.size(), filter_analysis_states_.size()); RTC_DCHECK_EQ(filters_time_domain.size(), h_highpass_.size()); ++blocks_since_reset_; SetRegionToAnalyze(filters_time_domain[0].size()); AnalyzeRegion(filters_time_domain, render_buffer); // Aggregate the results for all capture channels. auto& st_ch0 = filter_analysis_states_[0]; *any_filter_consistent = st_ch0.consistent_estimate; *max_echo_path_gain = st_ch0.gain; min_filter_delay_blocks_ = filter_delays_blocks_[0]; for (size_t ch = 1; ch < filters_time_domain.size(); ++ch) { auto& st_ch = filter_analysis_states_[ch]; *any_filter_consistent = *any_filter_consistent || st_ch.consistent_estimate; *max_echo_path_gain = std::max(*max_echo_path_gain, st_ch.gain); min_filter_delay_blocks_ = std::min(min_filter_delay_blocks_, filter_delays_blocks_[ch]); } } void FilterAnalyzer::AnalyzeRegion( rtc::ArrayView> filters_time_domain, const RenderBuffer& render_buffer) { // Preprocess the filter to avoid issues with low-frequency components in the // filter. PreProcessFilters(filters_time_domain); data_dumper_->DumpRaw("aec3_linear_filter_processed_td", h_highpass_[0]); constexpr float kOneByBlockSize = 1.f / kBlockSize; for (size_t ch = 0; ch < filters_time_domain.size(); ++ch) { RTC_DCHECK_LT(region_.start_sample_, filters_time_domain[ch].size()); RTC_DCHECK_LT(region_.end_sample_, filters_time_domain[ch].size()); auto& st_ch = filter_analysis_states_[ch]; RTC_DCHECK_EQ(h_highpass_[ch].size(), filters_time_domain[ch].size()); RTC_DCHECK_GT(h_highpass_[ch].size(), 0); st_ch.peak_index = std::min(st_ch.peak_index, h_highpass_[ch].size() - 1); st_ch.peak_index = FindPeakIndex(h_highpass_[ch], st_ch.peak_index, region_.start_sample_, region_.end_sample_); filter_delays_blocks_[ch] = st_ch.peak_index >> kBlockSizeLog2; UpdateFilterGain(h_highpass_[ch], &st_ch); st_ch.filter_length_blocks = filters_time_domain[ch].size() * kOneByBlockSize; st_ch.consistent_estimate = st_ch.consistent_filter_detector.Detect( h_highpass_[ch], region_, render_buffer.Block(-filter_delays_blocks_[ch])[0], st_ch.peak_index, filter_delays_blocks_[ch]); } } void FilterAnalyzer::UpdateFilterGain( rtc::ArrayView filter_time_domain, FilterAnalysisState* st) { bool sufficient_time_to_converge = blocks_since_reset_ > 5 * kNumBlocksPerSecond; if (sufficient_time_to_converge && st->consistent_estimate) { st->gain = fabsf(filter_time_domain[st->peak_index]); } else { // TODO(peah): Verify whether this check against a float is ok. if (st->gain) { st->gain = std::max(st->gain, fabsf(filter_time_domain[st->peak_index])); } } if (bounded_erl_ && st->gain) { st->gain = std::max(st->gain, 0.01f); } } void FilterAnalyzer::PreProcessFilters( rtc::ArrayView> filters_time_domain) { for (size_t ch = 0; ch < filters_time_domain.size(); ++ch) { RTC_DCHECK_LT(region_.start_sample_, filters_time_domain[ch].size()); RTC_DCHECK_LT(region_.end_sample_, filters_time_domain[ch].size()); RTC_DCHECK_GE(h_highpass_[ch].capacity(), filters_time_domain[ch].size()); h_highpass_[ch].resize(filters_time_domain[ch].size()); // Minimum phase high-pass filter with cutoff frequency at about 600 Hz. constexpr std::array h = { {0.7929742f, -0.36072128f, -0.47047766f}}; std::fill(h_highpass_[ch].begin() + region_.start_sample_, h_highpass_[ch].begin() + region_.end_sample_ + 1, 0.f); for (size_t k = std::max(h.size() - 1, region_.start_sample_); k <= region_.end_sample_; ++k) { for (size_t j = 0; j < h.size(); ++j) { h_highpass_[ch][k] += filters_time_domain[ch][k - j] * h[j]; } } } } void FilterAnalyzer::ResetRegion() { region_.start_sample_ = 0; region_.end_sample_ = 0; } void FilterAnalyzer::SetRegionToAnalyze(size_t filter_size) { constexpr size_t kNumberBlocksToUpdate = 1; auto& r = region_; r.start_sample_ = r.end_sample_ >= filter_size - 1 ? 0 : r.end_sample_ + 1; r.end_sample_ = std::min(r.start_sample_ + kNumberBlocksToUpdate * kBlockSize - 1, filter_size - 1); // Check range. RTC_DCHECK_LT(r.start_sample_, filter_size); RTC_DCHECK_LT(r.end_sample_, filter_size); RTC_DCHECK_LE(r.start_sample_, r.end_sample_); } FilterAnalyzer::ConsistentFilterDetector::ConsistentFilterDetector( const EchoCanceller3Config& config) : active_render_threshold_(config.render_levels.active_render_limit * config.render_levels.active_render_limit * kFftLengthBy2) { Reset(); } void FilterAnalyzer::ConsistentFilterDetector::Reset() { significant_peak_ = false; filter_floor_accum_ = 0.f; filter_secondary_peak_ = 0.f; filter_floor_low_limit_ = 0; filter_floor_high_limit_ = 0; consistent_estimate_counter_ = 0; consistent_delay_reference_ = -10; } bool FilterAnalyzer::ConsistentFilterDetector::Detect( rtc::ArrayView filter_to_analyze, const FilterRegion& region, rtc::ArrayView> x_block, size_t peak_index, int delay_blocks) { if (region.start_sample_ == 0) { filter_floor_accum_ = 0.f; filter_secondary_peak_ = 0.f; filter_floor_low_limit_ = peak_index < 64 ? 0 : peak_index - 64; filter_floor_high_limit_ = peak_index > filter_to_analyze.size() - 129 ? 0 : peak_index + 128; } for (size_t k = region.start_sample_; k < std::min(region.end_sample_ + 1, filter_floor_low_limit_); ++k) { float abs_h = fabsf(filter_to_analyze[k]); filter_floor_accum_ += abs_h; filter_secondary_peak_ = std::max(filter_secondary_peak_, abs_h); } for (size_t k = std::max(filter_floor_high_limit_, region.start_sample_); k <= region.end_sample_; ++k) { float abs_h = fabsf(filter_to_analyze[k]); filter_floor_accum_ += abs_h; filter_secondary_peak_ = std::max(filter_secondary_peak_, abs_h); } if (region.end_sample_ == filter_to_analyze.size() - 1) { float filter_floor = filter_floor_accum_ / (filter_floor_low_limit_ + filter_to_analyze.size() - filter_floor_high_limit_); float abs_peak = fabsf(filter_to_analyze[peak_index]); significant_peak_ = abs_peak > 10.f * filter_floor && abs_peak > 2.f * filter_secondary_peak_; } if (significant_peak_) { bool active_render_block = false; for (auto& x_channel : x_block) { const float x_energy = std::inner_product( x_channel.begin(), x_channel.end(), x_channel.begin(), 0.f); if (x_energy > active_render_threshold_) { active_render_block = true; break; } } if (consistent_delay_reference_ == delay_blocks) { if (active_render_block) { ++consistent_estimate_counter_; } } else { consistent_estimate_counter_ = 0; consistent_delay_reference_ = delay_blocks; } } return consistent_estimate_counter_ > 1.5f * kNumBlocksPerSecond; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/filter_analyzer.h0000664000175000017500000001060214475643423027336 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_FILTER_ANALYZER_H_ #define MODULES_AUDIO_PROCESSING_AEC3_FILTER_ANALYZER_H_ #include #include #include #include #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "rtc_base/constructor_magic.h" namespace webrtc { class ApmDataDumper; class RenderBuffer; // Class for analyzing the properties of an adaptive filter. class FilterAnalyzer { public: FilterAnalyzer(const EchoCanceller3Config& config, size_t num_capture_channels); ~FilterAnalyzer(); FilterAnalyzer(const FilterAnalyzer&) = delete; FilterAnalyzer& operator=(const FilterAnalyzer&) = delete; // Resets the analysis. void Reset(); // Updates the estimates with new input data. void Update(rtc::ArrayView> filters_time_domain, const RenderBuffer& render_buffer, bool* any_filter_consistent, float* max_echo_path_gain); // Returns the delay in blocks for each filter. rtc::ArrayView FilterDelaysBlocks() const { return filter_delays_blocks_; } // Returns the minimum delay of all filters in terms of blocks. int MinFilterDelayBlocks() const { return min_filter_delay_blocks_; } // Returns the number of blocks for the current used filter. int FilterLengthBlocks() const { return filter_analysis_states_[0].filter_length_blocks; } // Returns the preprocessed filter. rtc::ArrayView> GetAdjustedFilters() const { return h_highpass_; } // Public for testing purposes only. void SetRegionToAnalyze(size_t filter_size); private: struct FilterAnalysisState; void AnalyzeRegion( rtc::ArrayView> filters_time_domain, const RenderBuffer& render_buffer); void UpdateFilterGain(rtc::ArrayView filters_time_domain, FilterAnalysisState* st); void PreProcessFilters( rtc::ArrayView> filters_time_domain); void ResetRegion(); struct FilterRegion { size_t start_sample_; size_t end_sample_; }; // This class checks whether the shape of the impulse response has been // consistent over time. class ConsistentFilterDetector { public: explicit ConsistentFilterDetector(const EchoCanceller3Config& config); void Reset(); bool Detect(rtc::ArrayView filter_to_analyze, const FilterRegion& region, rtc::ArrayView> x_block, size_t peak_index, int delay_blocks); private: bool significant_peak_; float filter_floor_accum_; float filter_secondary_peak_; size_t filter_floor_low_limit_; size_t filter_floor_high_limit_; const float active_render_threshold_; size_t consistent_estimate_counter_ = 0; int consistent_delay_reference_ = -10; }; struct FilterAnalysisState { explicit FilterAnalysisState(const EchoCanceller3Config& config) : filter_length_blocks(config.filter.refined_initial.length_blocks), consistent_filter_detector(config) { Reset(config.ep_strength.default_gain); } void Reset(float default_gain) { peak_index = 0; gain = default_gain; consistent_filter_detector.Reset(); } float gain; size_t peak_index; int filter_length_blocks; bool consistent_estimate = false; ConsistentFilterDetector consistent_filter_detector; }; static int instance_count_; std::unique_ptr data_dumper_; const bool bounded_erl_; const float default_gain_; std::vector> h_highpass_; size_t blocks_since_reset_ = 0; FilterRegion region_; std::vector filter_analysis_states_; std::vector filter_delays_blocks_; int min_filter_delay_blocks_ = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_FILTER_ANALYZER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/frame_blocker.cc0000664000175000017500000000660414475643423027104 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/frame_blocker.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "rtc_base/checks.h" namespace webrtc { FrameBlocker::FrameBlocker(size_t num_bands, size_t num_channels) : num_bands_(num_bands), num_channels_(num_channels), buffer_(num_bands_, std::vector>(num_channels)) { RTC_DCHECK_LT(0, num_bands); RTC_DCHECK_LT(0, num_channels); for (auto& band : buffer_) { for (auto& channel : band) { channel.reserve(kBlockSize); RTC_DCHECK(channel.empty()); } } } FrameBlocker::~FrameBlocker() = default; void FrameBlocker::InsertSubFrameAndExtractBlock( const std::vector>>& sub_frame, std::vector>>* block) { RTC_DCHECK(block); RTC_DCHECK_EQ(num_bands_, block->size()); RTC_DCHECK_EQ(num_bands_, sub_frame.size()); for (size_t band = 0; band < num_bands_; ++band) { RTC_DCHECK_EQ(num_channels_, (*block)[band].size()); RTC_DCHECK_EQ(num_channels_, sub_frame[band].size()); for (size_t channel = 0; channel < num_channels_; ++channel) { RTC_DCHECK_GE(kBlockSize - 16, buffer_[band][channel].size()); RTC_DCHECK_EQ(kBlockSize, (*block)[band][channel].size()); RTC_DCHECK_EQ(kSubFrameLength, sub_frame[band][channel].size()); const int samples_to_block = kBlockSize - buffer_[band][channel].size(); (*block)[band][channel].clear(); (*block)[band][channel].insert((*block)[band][channel].begin(), buffer_[band][channel].begin(), buffer_[band][channel].end()); (*block)[band][channel].insert( (*block)[band][channel].begin() + buffer_[band][channel].size(), sub_frame[band][channel].begin(), sub_frame[band][channel].begin() + samples_to_block); buffer_[band][channel].clear(); buffer_[band][channel].insert( buffer_[band][channel].begin(), sub_frame[band][channel].begin() + samples_to_block, sub_frame[band][channel].end()); } } } bool FrameBlocker::IsBlockAvailable() const { return kBlockSize == buffer_[0][0].size(); } void FrameBlocker::ExtractBlock( std::vector>>* block) { RTC_DCHECK(block); RTC_DCHECK_EQ(num_bands_, block->size()); RTC_DCHECK(IsBlockAvailable()); for (size_t band = 0; band < num_bands_; ++band) { RTC_DCHECK_EQ(num_channels_, (*block)[band].size()); for (size_t channel = 0; channel < num_channels_; ++channel) { RTC_DCHECK_EQ(kBlockSize, buffer_[band][channel].size()); RTC_DCHECK_EQ(kBlockSize, (*block)[band][channel].size()); (*block)[band][channel].clear(); (*block)[band][channel].insert((*block)[band][channel].begin(), buffer_[band][channel].begin(), buffer_[band][channel].end()); buffer_[band][channel].clear(); } } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/frame_blocker.h0000664000175000017500000000327314475643423026745 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_FRAME_BLOCKER_H_ #define MODULES_AUDIO_PROCESSING_AEC3_FRAME_BLOCKER_H_ #include #include #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" namespace webrtc { // Class for producing 64 sample multiband blocks from frames consisting of 2 // subframes of 80 samples. class FrameBlocker { public: FrameBlocker(size_t num_bands, size_t num_channels); ~FrameBlocker(); FrameBlocker(const FrameBlocker&) = delete; FrameBlocker& operator=(const FrameBlocker&) = delete; // Inserts one 80 sample multiband subframe from the multiband frame and // extracts one 64 sample multiband block. void InsertSubFrameAndExtractBlock( const std::vector>>& sub_frame, std::vector>>* block); // Reports whether a multiband block of 64 samples is available for // extraction. bool IsBlockAvailable() const; // Extracts a multiband block of 64 samples. void ExtractBlock(std::vector>>* block); private: const size_t num_bands_; const size_t num_channels_; std::vector>> buffer_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_FRAME_BLOCKER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/fullband_erle_estimator.cc0000664000175000017500000001520514475643423031173 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/fullband_erle_estimator.h" #include #include #include #include "absl/types/optional.h" #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_minmax.h" namespace webrtc { namespace { constexpr float kEpsilon = 1e-3f; constexpr float kX2BandEnergyThreshold = 44015068.0f; constexpr int kBlocksToHoldErle = 100; constexpr int kPointsToAccumulate = 6; } // namespace FullBandErleEstimator::FullBandErleEstimator( const EchoCanceller3Config::Erle& config, size_t num_capture_channels) : min_erle_log2_(FastApproxLog2f(config.min + kEpsilon)), max_erle_lf_log2(FastApproxLog2f(config.max_l + kEpsilon)), hold_counters_time_domain_(num_capture_channels, 0), erle_time_domain_log2_(num_capture_channels, min_erle_log2_), instantaneous_erle_(num_capture_channels, ErleInstantaneous(config)), linear_filters_qualities_(num_capture_channels) { Reset(); } FullBandErleEstimator::~FullBandErleEstimator() = default; void FullBandErleEstimator::Reset() { for (auto& instantaneous_erle_ch : instantaneous_erle_) { instantaneous_erle_ch.Reset(); } UpdateQualityEstimates(); std::fill(erle_time_domain_log2_.begin(), erle_time_domain_log2_.end(), min_erle_log2_); std::fill(hold_counters_time_domain_.begin(), hold_counters_time_domain_.end(), 0); } void FullBandErleEstimator::Update( rtc::ArrayView X2, rtc::ArrayView> Y2, rtc::ArrayView> E2, const std::vector& converged_filters) { for (size_t ch = 0; ch < Y2.size(); ++ch) { if (converged_filters[ch]) { // Computes the fullband ERLE. const float X2_sum = std::accumulate(X2.begin(), X2.end(), 0.0f); if (X2_sum > kX2BandEnergyThreshold * X2.size()) { const float Y2_sum = std::accumulate(Y2[ch].begin(), Y2[ch].end(), 0.0f); const float E2_sum = std::accumulate(E2[ch].begin(), E2[ch].end(), 0.0f); if (instantaneous_erle_[ch].Update(Y2_sum, E2_sum)) { hold_counters_time_domain_[ch] = kBlocksToHoldErle; erle_time_domain_log2_[ch] += 0.1f * ((instantaneous_erle_[ch].GetInstErleLog2().value()) - erle_time_domain_log2_[ch]); erle_time_domain_log2_[ch] = rtc::SafeClamp( erle_time_domain_log2_[ch], min_erle_log2_, max_erle_lf_log2); } } } --hold_counters_time_domain_[ch]; if (hold_counters_time_domain_[ch] <= 0) { erle_time_domain_log2_[ch] = std::max(min_erle_log2_, erle_time_domain_log2_[ch] - 0.044f); } if (hold_counters_time_domain_[ch] == 0) { instantaneous_erle_[ch].ResetAccumulators(); } } UpdateQualityEstimates(); } void FullBandErleEstimator::Dump( const std::unique_ptr& data_dumper) const { data_dumper->DumpRaw("aec3_fullband_erle_log2", FullbandErleLog2()); instantaneous_erle_[0].Dump(data_dumper); } void FullBandErleEstimator::UpdateQualityEstimates() { for (size_t ch = 0; ch < instantaneous_erle_.size(); ++ch) { linear_filters_qualities_[ch] = instantaneous_erle_[ch].GetQualityEstimate(); } } FullBandErleEstimator::ErleInstantaneous::ErleInstantaneous( const EchoCanceller3Config::Erle& config) : clamp_inst_quality_to_zero_(config.clamp_quality_estimate_to_zero), clamp_inst_quality_to_one_(config.clamp_quality_estimate_to_one) { Reset(); } FullBandErleEstimator::ErleInstantaneous::~ErleInstantaneous() = default; bool FullBandErleEstimator::ErleInstantaneous::Update(const float Y2_sum, const float E2_sum) { bool update_estimates = false; E2_acum_ += E2_sum; Y2_acum_ += Y2_sum; num_points_++; if (num_points_ == kPointsToAccumulate) { if (E2_acum_ > 0.f) { update_estimates = true; erle_log2_ = FastApproxLog2f(Y2_acum_ / E2_acum_ + kEpsilon); } num_points_ = 0; E2_acum_ = 0.f; Y2_acum_ = 0.f; } if (update_estimates) { UpdateMaxMin(); UpdateQualityEstimate(); } return update_estimates; } void FullBandErleEstimator::ErleInstantaneous::Reset() { ResetAccumulators(); max_erle_log2_ = -10.f; // -30 dB. min_erle_log2_ = 33.f; // 100 dB. inst_quality_estimate_ = 0.f; } void FullBandErleEstimator::ErleInstantaneous::ResetAccumulators() { erle_log2_ = absl::nullopt; inst_quality_estimate_ = 0.f; num_points_ = 0; E2_acum_ = 0.f; Y2_acum_ = 0.f; } void FullBandErleEstimator::ErleInstantaneous::Dump( const std::unique_ptr& data_dumper) const { data_dumper->DumpRaw("aec3_fullband_erle_inst_log2", erle_log2_ ? *erle_log2_ : -10.f); data_dumper->DumpRaw( "aec3_erle_instantaneous_quality", GetQualityEstimate() ? GetQualityEstimate().value() : 0.f); data_dumper->DumpRaw("aec3_fullband_erle_max_log2", max_erle_log2_); data_dumper->DumpRaw("aec3_fullband_erle_min_log2", min_erle_log2_); } void FullBandErleEstimator::ErleInstantaneous::UpdateMaxMin() { RTC_DCHECK(erle_log2_); if (erle_log2_.value() > max_erle_log2_) { max_erle_log2_ = erle_log2_.value(); } else { max_erle_log2_ -= 0.0004; // Forget factor, approx 1dB every 3 sec. } if (erle_log2_.value() < min_erle_log2_) { min_erle_log2_ = erle_log2_.value(); } else { min_erle_log2_ += 0.0004; // Forget factor, approx 1dB every 3 sec. } } void FullBandErleEstimator::ErleInstantaneous::UpdateQualityEstimate() { const float alpha = 0.07f; float quality_estimate = 0.f; RTC_DCHECK(erle_log2_); // TODO(peah): Currently, the estimate can become be less than 0; this should // be corrected. if (max_erle_log2_ > min_erle_log2_) { quality_estimate = (erle_log2_.value() - min_erle_log2_) / (max_erle_log2_ - min_erle_log2_); } if (quality_estimate > inst_quality_estimate_) { inst_quality_estimate_ = quality_estimate; } else { inst_quality_estimate_ += alpha * (quality_estimate - inst_quality_estimate_); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/fullband_erle_estimator.h0000664000175000017500000001005714475643423031035 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_FULLBAND_ERLE_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_AEC3_FULLBAND_ERLE_ESTIMATOR_H_ #include #include #include "absl/types/optional.h" #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/logging/apm_data_dumper.h" namespace webrtc { // Estimates the echo return loss enhancement using the energy of all the // freuquency bands. class FullBandErleEstimator { public: FullBandErleEstimator(const EchoCanceller3Config::Erle& config, size_t num_capture_channels); ~FullBandErleEstimator(); // Resets the ERLE estimator. void Reset(); // Updates the ERLE estimator. void Update(rtc::ArrayView X2, rtc::ArrayView> Y2, rtc::ArrayView> E2, const std::vector& converged_filters); // Returns the fullband ERLE estimates in log2 units. float FullbandErleLog2() const { float min_erle = erle_time_domain_log2_[0]; for (size_t ch = 1; ch < erle_time_domain_log2_.size(); ++ch) { min_erle = std::min(min_erle, erle_time_domain_log2_[ch]); } return min_erle; } // Returns an estimation of the current linear filter quality. It returns a // float number between 0 and 1 mapping 1 to the highest possible quality. rtc::ArrayView> GetInstLinearQualityEstimates() const { return linear_filters_qualities_; } void Dump(const std::unique_ptr& data_dumper) const; private: void UpdateQualityEstimates(); class ErleInstantaneous { public: explicit ErleInstantaneous(const EchoCanceller3Config::Erle& config); ~ErleInstantaneous(); // Updates the estimator with a new point, returns true // if the instantaneous ERLE was updated due to having enough // points for performing the estimate. bool Update(const float Y2_sum, const float E2_sum); // Resets the instantaneous ERLE estimator to its initial state. void Reset(); // Resets the members related with an instantaneous estimate. void ResetAccumulators(); // Returns the instantaneous ERLE in log2 units. absl::optional GetInstErleLog2() const { return erle_log2_; } // Gets an indication between 0 and 1 of the performance of the linear // filter for the current time instant. absl::optional GetQualityEstimate() const { if (erle_log2_) { float value = inst_quality_estimate_; if (clamp_inst_quality_to_zero_) { value = std::max(0.f, value); } if (clamp_inst_quality_to_one_) { value = std::min(1.f, value); } return absl::optional(value); } return absl::nullopt; } void Dump(const std::unique_ptr& data_dumper) const; private: void UpdateMaxMin(); void UpdateQualityEstimate(); const bool clamp_inst_quality_to_zero_; const bool clamp_inst_quality_to_one_; absl::optional erle_log2_; float inst_quality_estimate_; float max_erle_log2_; float min_erle_log2_; float Y2_acum_; float E2_acum_; int num_points_; }; const float min_erle_log2_; const float max_erle_lf_log2; std::vector hold_counters_time_domain_; std::vector erle_time_domain_log2_; std::vector instantaneous_erle_; std::vector> linear_filters_qualities_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_FULLBAND_ERLE_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/matched_filter.cc0000664000175000017500000003751014475643423027263 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/matched_filter.h" // Defines WEBRTC_ARCH_X86_FAMILY, used below. #include "rtc_base/system/arch.h" #if defined(WEBRTC_HAS_NEON) #include #endif #if defined(WEBRTC_ARCH_X86_FAMILY) #include #endif #include #include #include #include #include #include "modules/audio_processing/aec3/downsampled_render_buffer.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" namespace webrtc { namespace aec3 { #if defined(WEBRTC_HAS_NEON) void MatchedFilterCore_NEON(size_t x_start_index, float x2_sum_threshold, float smoothing, rtc::ArrayView x, rtc::ArrayView y, rtc::ArrayView h, bool* filters_updated, float* error_sum) { const int h_size = static_cast(h.size()); const int x_size = static_cast(x.size()); RTC_DCHECK_EQ(0, h_size % 4); // Process for all samples in the sub-block. for (size_t i = 0; i < y.size(); ++i) { // Apply the matched filter as filter * x, and compute x * x. RTC_DCHECK_GT(x_size, x_start_index); const float* x_p = &x[x_start_index]; const float* h_p = &h[0]; // Initialize values for the accumulation. float32x4_t s_128 = vdupq_n_f32(0); float32x4_t x2_sum_128 = vdupq_n_f32(0); float x2_sum = 0.f; float s = 0; // Compute loop chunk sizes until, and after, the wraparound of the circular // buffer for x. const int chunk1 = std::min(h_size, static_cast(x_size - x_start_index)); // Perform the loop in two chunks. const int chunk2 = h_size - chunk1; for (int limit : {chunk1, chunk2}) { // Perform 128 bit vector operations. const int limit_by_4 = limit >> 2; for (int k = limit_by_4; k > 0; --k, h_p += 4, x_p += 4) { // Load the data into 128 bit vectors. const float32x4_t x_k = vld1q_f32(x_p); const float32x4_t h_k = vld1q_f32(h_p); // Compute and accumulate x * x and h * x. x2_sum_128 = vmlaq_f32(x2_sum_128, x_k, x_k); s_128 = vmlaq_f32(s_128, h_k, x_k); } // Perform non-vector operations for any remaining items. for (int k = limit - limit_by_4 * 4; k > 0; --k, ++h_p, ++x_p) { const float x_k = *x_p; x2_sum += x_k * x_k; s += *h_p * x_k; } x_p = &x[0]; } // Combine the accumulated vector and scalar values. float* v = reinterpret_cast(&x2_sum_128); x2_sum += v[0] + v[1] + v[2] + v[3]; v = reinterpret_cast(&s_128); s += v[0] + v[1] + v[2] + v[3]; // Compute the matched filter error. float e = y[i] - s; const bool saturation = y[i] >= 32000.f || y[i] <= -32000.f; (*error_sum) += e * e; // Update the matched filter estimate in an NLMS manner. if (x2_sum > x2_sum_threshold && !saturation) { RTC_DCHECK_LT(0.f, x2_sum); const float alpha = smoothing * e / x2_sum; const float32x4_t alpha_128 = vmovq_n_f32(alpha); // filter = filter + smoothing * (y - filter * x) * x / x * x. float* h_p = &h[0]; x_p = &x[x_start_index]; // Perform the loop in two chunks. for (int limit : {chunk1, chunk2}) { // Perform 128 bit vector operations. const int limit_by_4 = limit >> 2; for (int k = limit_by_4; k > 0; --k, h_p += 4, x_p += 4) { // Load the data into 128 bit vectors. float32x4_t h_k = vld1q_f32(h_p); const float32x4_t x_k = vld1q_f32(x_p); // Compute h = h + alpha * x. h_k = vmlaq_f32(h_k, alpha_128, x_k); // Store the result. vst1q_f32(h_p, h_k); } // Perform non-vector operations for any remaining items. for (int k = limit - limit_by_4 * 4; k > 0; --k, ++h_p, ++x_p) { *h_p += alpha * *x_p; } x_p = &x[0]; } *filters_updated = true; } x_start_index = x_start_index > 0 ? x_start_index - 1 : x_size - 1; } } #endif #if defined(WEBRTC_ARCH_X86_FAMILY) void MatchedFilterCore_SSE2(size_t x_start_index, float x2_sum_threshold, float smoothing, rtc::ArrayView x, rtc::ArrayView y, rtc::ArrayView h, bool* filters_updated, float* error_sum) { const int h_size = static_cast(h.size()); const int x_size = static_cast(x.size()); RTC_DCHECK_EQ(0, h_size % 4); // Process for all samples in the sub-block. for (size_t i = 0; i < y.size(); ++i) { // Apply the matched filter as filter * x, and compute x * x. RTC_DCHECK_GT(x_size, x_start_index); const float* x_p = &x[x_start_index]; const float* h_p = &h[0]; // Initialize values for the accumulation. __m128 s_128 = _mm_set1_ps(0); __m128 x2_sum_128 = _mm_set1_ps(0); float x2_sum = 0.f; float s = 0; // Compute loop chunk sizes until, and after, the wraparound of the circular // buffer for x. const int chunk1 = std::min(h_size, static_cast(x_size - x_start_index)); // Perform the loop in two chunks. const int chunk2 = h_size - chunk1; for (int limit : {chunk1, chunk2}) { // Perform 128 bit vector operations. const int limit_by_4 = limit >> 2; for (int k = limit_by_4; k > 0; --k, h_p += 4, x_p += 4) { // Load the data into 128 bit vectors. const __m128 x_k = _mm_loadu_ps(x_p); const __m128 h_k = _mm_loadu_ps(h_p); const __m128 xx = _mm_mul_ps(x_k, x_k); // Compute and accumulate x * x and h * x. x2_sum_128 = _mm_add_ps(x2_sum_128, xx); const __m128 hx = _mm_mul_ps(h_k, x_k); s_128 = _mm_add_ps(s_128, hx); } // Perform non-vector operations for any remaining items. for (int k = limit - limit_by_4 * 4; k > 0; --k, ++h_p, ++x_p) { const float x_k = *x_p; x2_sum += x_k * x_k; s += *h_p * x_k; } x_p = &x[0]; } // Combine the accumulated vector and scalar values. float* v = reinterpret_cast(&x2_sum_128); x2_sum += v[0] + v[1] + v[2] + v[3]; v = reinterpret_cast(&s_128); s += v[0] + v[1] + v[2] + v[3]; // Compute the matched filter error. float e = y[i] - s; const bool saturation = y[i] >= 32000.f || y[i] <= -32000.f; (*error_sum) += e * e; // Update the matched filter estimate in an NLMS manner. if (x2_sum > x2_sum_threshold && !saturation) { RTC_DCHECK_LT(0.f, x2_sum); const float alpha = smoothing * e / x2_sum; const __m128 alpha_128 = _mm_set1_ps(alpha); // filter = filter + smoothing * (y - filter * x) * x / x * x. float* h_p = &h[0]; x_p = &x[x_start_index]; // Perform the loop in two chunks. for (int limit : {chunk1, chunk2}) { // Perform 128 bit vector operations. const int limit_by_4 = limit >> 2; for (int k = limit_by_4; k > 0; --k, h_p += 4, x_p += 4) { // Load the data into 128 bit vectors. __m128 h_k = _mm_loadu_ps(h_p); const __m128 x_k = _mm_loadu_ps(x_p); // Compute h = h + alpha * x. const __m128 alpha_x = _mm_mul_ps(alpha_128, x_k); h_k = _mm_add_ps(h_k, alpha_x); // Store the result. _mm_storeu_ps(h_p, h_k); } // Perform non-vector operations for any remaining items. for (int k = limit - limit_by_4 * 4; k > 0; --k, ++h_p, ++x_p) { *h_p += alpha * *x_p; } x_p = &x[0]; } *filters_updated = true; } x_start_index = x_start_index > 0 ? x_start_index - 1 : x_size - 1; } } #endif void MatchedFilterCore(size_t x_start_index, float x2_sum_threshold, float smoothing, rtc::ArrayView x, rtc::ArrayView y, rtc::ArrayView h, bool* filters_updated, float* error_sum) { // Process for all samples in the sub-block. for (size_t i = 0; i < y.size(); ++i) { // Apply the matched filter as filter * x, and compute x * x. float x2_sum = 0.f; float s = 0; size_t x_index = x_start_index; for (size_t k = 0; k < h.size(); ++k) { x2_sum += x[x_index] * x[x_index]; s += h[k] * x[x_index]; x_index = x_index < (x.size() - 1) ? x_index + 1 : 0; } // Compute the matched filter error. float e = y[i] - s; const bool saturation = y[i] >= 32000.f || y[i] <= -32000.f; (*error_sum) += e * e; // Update the matched filter estimate in an NLMS manner. if (x2_sum > x2_sum_threshold && !saturation) { RTC_DCHECK_LT(0.f, x2_sum); const float alpha = smoothing * e / x2_sum; // filter = filter + smoothing * (y - filter * x) * x / x * x. size_t x_index = x_start_index; for (size_t k = 0; k < h.size(); ++k) { h[k] += alpha * x[x_index]; x_index = x_index < (x.size() - 1) ? x_index + 1 : 0; } *filters_updated = true; } x_start_index = x_start_index > 0 ? x_start_index - 1 : x.size() - 1; } } } // namespace aec3 MatchedFilter::MatchedFilter(ApmDataDumper* data_dumper, Aec3Optimization optimization, size_t sub_block_size, size_t window_size_sub_blocks, int num_matched_filters, size_t alignment_shift_sub_blocks, float excitation_limit, float smoothing, float matching_filter_threshold) : data_dumper_(data_dumper), optimization_(optimization), sub_block_size_(sub_block_size), filter_intra_lag_shift_(alignment_shift_sub_blocks * sub_block_size_), filters_( num_matched_filters, std::vector(window_size_sub_blocks * sub_block_size_, 0.f)), lag_estimates_(num_matched_filters), filters_offsets_(num_matched_filters, 0), excitation_limit_(excitation_limit), smoothing_(smoothing), matching_filter_threshold_(matching_filter_threshold) { RTC_DCHECK(data_dumper); RTC_DCHECK_LT(0, window_size_sub_blocks); RTC_DCHECK((kBlockSize % sub_block_size) == 0); RTC_DCHECK((sub_block_size % 4) == 0); } MatchedFilter::~MatchedFilter() = default; void MatchedFilter::Reset() { for (auto& f : filters_) { std::fill(f.begin(), f.end(), 0.f); } for (auto& l : lag_estimates_) { l = MatchedFilter::LagEstimate(); } } void MatchedFilter::Update(const DownsampledRenderBuffer& render_buffer, rtc::ArrayView capture) { RTC_DCHECK_EQ(sub_block_size_, capture.size()); auto& y = capture; const float x2_sum_threshold = filters_[0].size() * excitation_limit_ * excitation_limit_; // Apply all matched filters. size_t alignment_shift = 0; for (size_t n = 0; n < filters_.size(); ++n) { float error_sum = 0.f; bool filters_updated = false; size_t x_start_index = (render_buffer.read + alignment_shift + sub_block_size_ - 1) % render_buffer.buffer.size(); switch (optimization_) { #if defined(WEBRTC_ARCH_X86_FAMILY) case Aec3Optimization::kSse2: aec3::MatchedFilterCore_SSE2(x_start_index, x2_sum_threshold, smoothing_, render_buffer.buffer, y, filters_[n], &filters_updated, &error_sum); break; case Aec3Optimization::kAvx2: aec3::MatchedFilterCore_AVX2(x_start_index, x2_sum_threshold, smoothing_, render_buffer.buffer, y, filters_[n], &filters_updated, &error_sum); break; #endif #if defined(WEBRTC_HAS_NEON) case Aec3Optimization::kNeon: aec3::MatchedFilterCore_NEON(x_start_index, x2_sum_threshold, smoothing_, render_buffer.buffer, y, filters_[n], &filters_updated, &error_sum); break; #endif default: aec3::MatchedFilterCore(x_start_index, x2_sum_threshold, smoothing_, render_buffer.buffer, y, filters_[n], &filters_updated, &error_sum); } // Compute anchor for the matched filter error. const float error_sum_anchor = std::inner_product(y.begin(), y.end(), y.begin(), 0.f); // Estimate the lag in the matched filter as the distance to the portion in // the filter that contributes the most to the matched filter output. This // is detected as the peak of the matched filter. const size_t lag_estimate = std::distance( filters_[n].begin(), std::max_element( filters_[n].begin(), filters_[n].end(), [](float a, float b) -> bool { return a * a < b * b; })); // Update the lag estimates for the matched filter. lag_estimates_[n] = LagEstimate( error_sum_anchor - error_sum, (lag_estimate > 2 && lag_estimate < (filters_[n].size() - 10) && error_sum < matching_filter_threshold_ * error_sum_anchor), lag_estimate + alignment_shift, filters_updated); RTC_DCHECK_GE(10, filters_.size()); switch (n) { case 0: data_dumper_->DumpRaw("aec3_correlator_0_h", filters_[0]); break; case 1: data_dumper_->DumpRaw("aec3_correlator_1_h", filters_[1]); break; case 2: data_dumper_->DumpRaw("aec3_correlator_2_h", filters_[2]); break; case 3: data_dumper_->DumpRaw("aec3_correlator_3_h", filters_[3]); break; case 4: data_dumper_->DumpRaw("aec3_correlator_4_h", filters_[4]); break; case 5: data_dumper_->DumpRaw("aec3_correlator_5_h", filters_[5]); break; case 6: data_dumper_->DumpRaw("aec3_correlator_6_h", filters_[6]); break; case 7: data_dumper_->DumpRaw("aec3_correlator_7_h", filters_[7]); break; case 8: data_dumper_->DumpRaw("aec3_correlator_8_h", filters_[8]); break; case 9: data_dumper_->DumpRaw("aec3_correlator_9_h", filters_[9]); break; default: RTC_NOTREACHED(); } alignment_shift += filter_intra_lag_shift_; } } void MatchedFilter::LogFilterProperties(int sample_rate_hz, size_t shift, size_t downsampling_factor) const { size_t alignment_shift = 0; constexpr int kFsBy1000 = 16; for (size_t k = 0; k < filters_.size(); ++k) { int start = static_cast(alignment_shift * downsampling_factor); int end = static_cast((alignment_shift + filters_[k].size()) * downsampling_factor); RTC_LOG(LS_VERBOSE) << "Filter " << k << ": start: " << (start - static_cast(shift)) / kFsBy1000 << " ms, end: " << (end - static_cast(shift)) / kFsBy1000 << " ms."; alignment_shift += filter_intra_lag_shift_; } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/matched_filter.h0000664000175000017500000001167714475643423027133 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_MATCHED_FILTER_H_ #define MODULES_AUDIO_PROCESSING_AEC3_MATCHED_FILTER_H_ #include #include #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "rtc_base/system/arch.h" namespace webrtc { class ApmDataDumper; struct DownsampledRenderBuffer; namespace aec3 { #if defined(WEBRTC_HAS_NEON) // Filter core for the matched filter that is optimized for NEON. void MatchedFilterCore_NEON(size_t x_start_index, float x2_sum_threshold, float smoothing, rtc::ArrayView x, rtc::ArrayView y, rtc::ArrayView h, bool* filters_updated, float* error_sum); #endif #if defined(WEBRTC_ARCH_X86_FAMILY) // Filter core for the matched filter that is optimized for SSE2. void MatchedFilterCore_SSE2(size_t x_start_index, float x2_sum_threshold, float smoothing, rtc::ArrayView x, rtc::ArrayView y, rtc::ArrayView h, bool* filters_updated, float* error_sum); // Filter core for the matched filter that is optimized for AVX2. void MatchedFilterCore_AVX2(size_t x_start_index, float x2_sum_threshold, float smoothing, rtc::ArrayView x, rtc::ArrayView y, rtc::ArrayView h, bool* filters_updated, float* error_sum); #endif // Filter core for the matched filter. void MatchedFilterCore(size_t x_start_index, float x2_sum_threshold, float smoothing, rtc::ArrayView x, rtc::ArrayView y, rtc::ArrayView h, bool* filters_updated, float* error_sum); } // namespace aec3 // Produces recursively updated cross-correlation estimates for several signal // shifts where the intra-shift spacing is uniform. class MatchedFilter { public: // Stores properties for the lag estimate corresponding to a particular signal // shift. struct LagEstimate { LagEstimate() = default; LagEstimate(float accuracy, bool reliable, size_t lag, bool updated) : accuracy(accuracy), reliable(reliable), lag(lag), updated(updated) {} float accuracy = 0.f; bool reliable = false; size_t lag = 0; bool updated = false; }; MatchedFilter(ApmDataDumper* data_dumper, Aec3Optimization optimization, size_t sub_block_size, size_t window_size_sub_blocks, int num_matched_filters, size_t alignment_shift_sub_blocks, float excitation_limit, float smoothing, float matching_filter_threshold); MatchedFilter() = delete; MatchedFilter(const MatchedFilter&) = delete; MatchedFilter& operator=(const MatchedFilter&) = delete; ~MatchedFilter(); // Updates the correlation with the values in the capture buffer. void Update(const DownsampledRenderBuffer& render_buffer, rtc::ArrayView capture); // Resets the matched filter. void Reset(); // Returns the current lag estimates. rtc::ArrayView GetLagEstimates() const { return lag_estimates_; } // Returns the maximum filter lag. size_t GetMaxFilterLag() const { return filters_.size() * filter_intra_lag_shift_ + filters_[0].size(); } // Log matched filter properties. void LogFilterProperties(int sample_rate_hz, size_t shift, size_t downsampling_factor) const; private: ApmDataDumper* const data_dumper_; const Aec3Optimization optimization_; const size_t sub_block_size_; const size_t filter_intra_lag_shift_; std::vector> filters_; std::vector lag_estimates_; std::vector filters_offsets_; const float excitation_limit_; const float smoothing_; const float matching_filter_threshold_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_MATCHED_FILTER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/matched_filter_avx2.cc0000664000175000017500000001074114475643423030220 0ustar00arunarun/* * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/matched_filter.h" #include #include "rtc_base/checks.h" namespace webrtc { namespace aec3 { void MatchedFilterCore_AVX2(size_t x_start_index, float x2_sum_threshold, float smoothing, rtc::ArrayView x, rtc::ArrayView y, rtc::ArrayView h, bool* filters_updated, float* error_sum) { const int h_size = static_cast(h.size()); const int x_size = static_cast(x.size()); RTC_DCHECK_EQ(0, h_size % 8); // Process for all samples in the sub-block. for (size_t i = 0; i < y.size(); ++i) { // Apply the matched filter as filter * x, and compute x * x. RTC_DCHECK_GT(x_size, x_start_index); const float* x_p = &x[x_start_index]; const float* h_p = &h[0]; // Initialize values for the accumulation. __m256 s_256 = _mm256_set1_ps(0); __m256 x2_sum_256 = _mm256_set1_ps(0); float x2_sum = 0.f; float s = 0; // Compute loop chunk sizes until, and after, the wraparound of the circular // buffer for x. const int chunk1 = std::min(h_size, static_cast(x_size - x_start_index)); // Perform the loop in two chunks. const int chunk2 = h_size - chunk1; for (int limit : {chunk1, chunk2}) { // Perform 256 bit vector operations. const int limit_by_8 = limit >> 3; for (int k = limit_by_8; k > 0; --k, h_p += 8, x_p += 8) { // Load the data into 256 bit vectors. __m256 x_k = _mm256_loadu_ps(x_p); __m256 h_k = _mm256_loadu_ps(h_p); // Compute and accumulate x * x and h * x. x2_sum_256 = _mm256_fmadd_ps(x_k, x_k, x2_sum_256); s_256 = _mm256_fmadd_ps(h_k, x_k, s_256); } // Perform non-vector operations for any remaining items. for (int k = limit - limit_by_8 * 8; k > 0; --k, ++h_p, ++x_p) { const float x_k = *x_p; x2_sum += x_k * x_k; s += *h_p * x_k; } x_p = &x[0]; } // Sum components together. __m128 x2_sum_128 = _mm_add_ps(_mm256_extractf128_ps(x2_sum_256, 0), _mm256_extractf128_ps(x2_sum_256, 1)); __m128 s_128 = _mm_add_ps(_mm256_extractf128_ps(s_256, 0), _mm256_extractf128_ps(s_256, 1)); // Combine the accumulated vector and scalar values. float* v = reinterpret_cast(&x2_sum_128); x2_sum += v[0] + v[1] + v[2] + v[3]; v = reinterpret_cast(&s_128); s += v[0] + v[1] + v[2] + v[3]; // Compute the matched filter error. float e = y[i] - s; const bool saturation = y[i] >= 32000.f || y[i] <= -32000.f; (*error_sum) += e * e; // Update the matched filter estimate in an NLMS manner. if (x2_sum > x2_sum_threshold && !saturation) { RTC_DCHECK_LT(0.f, x2_sum); const float alpha = smoothing * e / x2_sum; const __m256 alpha_256 = _mm256_set1_ps(alpha); // filter = filter + smoothing * (y - filter * x) * x / x * x. float* h_p = &h[0]; x_p = &x[x_start_index]; // Perform the loop in two chunks. for (int limit : {chunk1, chunk2}) { // Perform 256 bit vector operations. const int limit_by_8 = limit >> 3; for (int k = limit_by_8; k > 0; --k, h_p += 8, x_p += 8) { // Load the data into 256 bit vectors. __m256 h_k = _mm256_loadu_ps(h_p); __m256 x_k = _mm256_loadu_ps(x_p); // Compute h = h + alpha * x. h_k = _mm256_fmadd_ps(x_k, alpha_256, h_k); // Store the result. _mm256_storeu_ps(h_p, h_k); } // Perform non-vector operations for any remaining items. for (int k = limit - limit_by_8 * 8; k > 0; --k, ++h_p, ++x_p) { *h_p += alpha * *x_p; } x_p = &x[0]; } *filters_updated = true; } x_start_index = x_start_index > 0 ? x_start_index - 1 : x_size - 1; } } } // namespace aec3 } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc0000664000175000017500000000700014475643423032277 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/matched_filter_lag_aggregator.h" #include #include #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" namespace webrtc { MatchedFilterLagAggregator::MatchedFilterLagAggregator( ApmDataDumper* data_dumper, size_t max_filter_lag, const EchoCanceller3Config::Delay::DelaySelectionThresholds& thresholds) : data_dumper_(data_dumper), histogram_(max_filter_lag + 1, 0), thresholds_(thresholds) { RTC_DCHECK(data_dumper); RTC_DCHECK_LE(thresholds_.initial, thresholds_.converged); histogram_data_.fill(0); } MatchedFilterLagAggregator::~MatchedFilterLagAggregator() = default; void MatchedFilterLagAggregator::Reset(bool hard_reset) { std::fill(histogram_.begin(), histogram_.end(), 0); histogram_data_.fill(0); histogram_data_index_ = 0; if (hard_reset) { significant_candidate_found_ = false; } } absl::optional MatchedFilterLagAggregator::Aggregate( rtc::ArrayView lag_estimates) { // Choose the strongest lag estimate as the best one. float best_accuracy = 0.f; int best_lag_estimate_index = -1; for (size_t k = 0; k < lag_estimates.size(); ++k) { if (lag_estimates[k].updated && lag_estimates[k].reliable) { if (lag_estimates[k].accuracy > best_accuracy) { best_accuracy = lag_estimates[k].accuracy; best_lag_estimate_index = static_cast(k); } } } // TODO(peah): Remove this logging once all development is done. data_dumper_->DumpRaw("aec3_echo_path_delay_estimator_best_index", best_lag_estimate_index); data_dumper_->DumpRaw("aec3_echo_path_delay_estimator_histogram", histogram_); if (best_lag_estimate_index != -1) { RTC_DCHECK_GT(histogram_.size(), histogram_data_[histogram_data_index_]); RTC_DCHECK_LE(0, histogram_data_[histogram_data_index_]); --histogram_[histogram_data_[histogram_data_index_]]; histogram_data_[histogram_data_index_] = lag_estimates[best_lag_estimate_index].lag; RTC_DCHECK_GT(histogram_.size(), histogram_data_[histogram_data_index_]); RTC_DCHECK_LE(0, histogram_data_[histogram_data_index_]); ++histogram_[histogram_data_[histogram_data_index_]]; histogram_data_index_ = (histogram_data_index_ + 1) % histogram_data_.size(); const int candidate = std::distance(histogram_.begin(), std::max_element(histogram_.begin(), histogram_.end())); significant_candidate_found_ = significant_candidate_found_ || histogram_[candidate] > thresholds_.converged; if (histogram_[candidate] > thresholds_.converged || (histogram_[candidate] > thresholds_.initial && !significant_candidate_found_)) { DelayEstimate::Quality quality = significant_candidate_found_ ? DelayEstimate::Quality::kRefined : DelayEstimate::Quality::kCoarse; return DelayEstimate(quality, candidate); } } return absl::nullopt; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/matched_filter_lag_aggregator.h0000664000175000017500000000367114475643423032153 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_MATCHED_FILTER_LAG_AGGREGATOR_H_ #define MODULES_AUDIO_PROCESSING_AEC3_MATCHED_FILTER_LAG_AGGREGATOR_H_ #include #include "absl/types/optional.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/delay_estimate.h" #include "modules/audio_processing/aec3/matched_filter.h" namespace webrtc { class ApmDataDumper; // Aggregates lag estimates produced by the MatchedFilter class into a single // reliable combined lag estimate. class MatchedFilterLagAggregator { public: MatchedFilterLagAggregator( ApmDataDumper* data_dumper, size_t max_filter_lag, const EchoCanceller3Config::Delay::DelaySelectionThresholds& thresholds); MatchedFilterLagAggregator() = delete; MatchedFilterLagAggregator(const MatchedFilterLagAggregator&) = delete; MatchedFilterLagAggregator& operator=(const MatchedFilterLagAggregator&) = delete; ~MatchedFilterLagAggregator(); // Resets the aggregator. void Reset(bool hard_reset); // Aggregates the provided lag estimates. absl::optional Aggregate( rtc::ArrayView lag_estimates); private: ApmDataDumper* const data_dumper_; std::vector histogram_; std::array histogram_data_; int histogram_data_index_ = 0; bool significant_candidate_found_ = false; const EchoCanceller3Config::Delay::DelaySelectionThresholds thresholds_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_MATCHED_FILTER_LAG_AGGREGATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/moving_average.cc0000664000175000017500000000326014475643423027275 0ustar00arunarun /* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/moving_average.h" #include #include #include "rtc_base/checks.h" namespace webrtc { namespace aec3 { MovingAverage::MovingAverage(size_t num_elem, size_t mem_len) : num_elem_(num_elem), mem_len_(mem_len - 1), scaling_(1.0f / static_cast(mem_len)), memory_(num_elem * mem_len_, 0.f), mem_index_(0) { RTC_DCHECK(num_elem_ > 0); RTC_DCHECK(mem_len > 0); } MovingAverage::~MovingAverage() = default; void MovingAverage::Average(rtc::ArrayView input, rtc::ArrayView output) { RTC_DCHECK(input.size() == num_elem_); RTC_DCHECK(output.size() == num_elem_); // Sum all contributions. std::copy(input.begin(), input.end(), output.begin()); for (auto i = memory_.begin(); i < memory_.end(); i += num_elem_) { std::transform(i, i + num_elem_, output.begin(), output.begin(), std::plus()); } // Divide by mem_len_. for (float& o : output) { o *= scaling_; } // Update memory. if (mem_len_ > 0) { std::copy(input.begin(), input.end(), memory_.begin() + mem_index_ * num_elem_); mem_index_ = (mem_index_ + 1) % mem_len_; } } } // namespace aec3 } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/moving_average.h0000664000175000017500000000240414475643423027136 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_MOVING_AVERAGE_H_ #define MODULES_AUDIO_PROCESSING_AEC3_MOVING_AVERAGE_H_ #include #include #include "api/array_view.h" namespace webrtc { namespace aec3 { class MovingAverage { public: // Creates an instance of MovingAverage that accepts inputs of length num_elem // and averages over mem_len inputs. MovingAverage(size_t num_elem, size_t mem_len); ~MovingAverage(); // Computes the average of input and mem_len-1 previous inputs and stores the // result in output. void Average(rtc::ArrayView input, rtc::ArrayView output); private: const size_t num_elem_; const size_t mem_len_; const float scaling_; std::vector memory_; size_t mem_index_; }; } // namespace aec3 } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_MOVING_AVERAGE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/nearend_detector.h0000664000175000017500000000265714475643423027464 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_NEAREND_DETECTOR_H_ #define MODULES_AUDIO_PROCESSING_AEC3_NEAREND_DETECTOR_H_ #include #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" namespace webrtc { // Class for selecting whether the suppressor is in the nearend or echo state. class NearendDetector { public: virtual ~NearendDetector() {} // Returns whether the current state is the nearend state. virtual bool IsNearendState() const = 0; // Updates the state selection based on latest spectral estimates. virtual void Update( rtc::ArrayView> nearend_spectrum, rtc::ArrayView> residual_echo_spectrum, rtc::ArrayView> comfort_noise_spectrum, bool initial_state) = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_NEAREND_DETECTOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/refined_filter_update_gain.cc0000664000175000017500000001377314475643423031637 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/refined_filter_update_gain.h" #include #include #include "modules/audio_processing/aec3/adaptive_fir_filter.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/echo_path_variability.h" #include "modules/audio_processing/aec3/fft_data.h" #include "modules/audio_processing/aec3/render_signal_analyzer.h" #include "modules/audio_processing/aec3/subtractor_output.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/atomic_ops.h" #include "rtc_base/checks.h" namespace webrtc { namespace { constexpr float kHErrorInitial = 10000.f; constexpr int kPoorExcitationCounterInitial = 1000; } // namespace int RefinedFilterUpdateGain::instance_count_ = 0; RefinedFilterUpdateGain::RefinedFilterUpdateGain( const EchoCanceller3Config::Filter::RefinedConfiguration& config, size_t config_change_duration_blocks) : data_dumper_( new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), config_change_duration_blocks_( static_cast(config_change_duration_blocks)), poor_excitation_counter_(kPoorExcitationCounterInitial) { SetConfig(config, true); H_error_.fill(kHErrorInitial); RTC_DCHECK_LT(0, config_change_duration_blocks_); one_by_config_change_duration_blocks_ = 1.f / config_change_duration_blocks_; } RefinedFilterUpdateGain::~RefinedFilterUpdateGain() {} void RefinedFilterUpdateGain::HandleEchoPathChange( const EchoPathVariability& echo_path_variability) { if (echo_path_variability.gain_change) { // TODO(bugs.webrtc.org/9526) Handle gain changes. } if (echo_path_variability.delay_change != EchoPathVariability::DelayAdjustment::kNone) { H_error_.fill(kHErrorInitial); } if (!echo_path_variability.gain_change) { poor_excitation_counter_ = kPoorExcitationCounterInitial; call_counter_ = 0; } } void RefinedFilterUpdateGain::Compute( const std::array& render_power, const RenderSignalAnalyzer& render_signal_analyzer, const SubtractorOutput& subtractor_output, rtc::ArrayView erl, size_t size_partitions, bool saturated_capture_signal, FftData* gain_fft) { RTC_DCHECK(gain_fft); // Introducing shorter notation to improve readability. const FftData& E_refined = subtractor_output.E_refined; const auto& E2_refined = subtractor_output.E2_refined; const auto& E2_coarse = subtractor_output.E2_coarse; FftData* G = gain_fft; const auto& X2 = render_power; ++call_counter_; UpdateCurrentConfig(); if (render_signal_analyzer.PoorSignalExcitation()) { poor_excitation_counter_ = 0; } // Do not update the filter if the render is not sufficiently excited. if (++poor_excitation_counter_ < size_partitions || saturated_capture_signal || call_counter_ <= size_partitions) { G->re.fill(0.f); G->im.fill(0.f); } else { // Corresponds to WGN of power -39 dBFS. std::array mu; // mu = H_error / (0.5* H_error* X2 + n * E2). for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { if (X2[k] >= current_config_.noise_gate) { mu[k] = H_error_[k] / (0.5f * H_error_[k] * X2[k] + size_partitions * E2_refined[k]); } else { mu[k] = 0.f; } } // Avoid updating the filter close to narrow bands in the render signals. render_signal_analyzer.MaskRegionsAroundNarrowBands(&mu); // H_error = H_error - 0.5 * mu * X2 * H_error. for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { H_error_[k] -= 0.5f * mu[k] * X2[k] * H_error_[k]; } // G = mu * E. for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { G->re[k] = mu[k] * E_refined.re[k]; G->im[k] = mu[k] * E_refined.im[k]; } } // H_error = H_error + factor * erl. for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { if (E2_coarse[k] >= E2_refined[k]) { H_error_[k] += current_config_.leakage_converged * erl[k]; } else { H_error_[k] += current_config_.leakage_diverged * erl[k]; } H_error_[k] = std::max(H_error_[k], current_config_.error_floor); H_error_[k] = std::min(H_error_[k], current_config_.error_ceil); } data_dumper_->DumpRaw("aec3_refined_gain_H_error", H_error_); } void RefinedFilterUpdateGain::UpdateCurrentConfig() { RTC_DCHECK_GE(config_change_duration_blocks_, config_change_counter_); if (config_change_counter_ > 0) { if (--config_change_counter_ > 0) { auto average = [](float from, float to, float from_weight) { return from * from_weight + to * (1.f - from_weight); }; float change_factor = config_change_counter_ * one_by_config_change_duration_blocks_; current_config_.leakage_converged = average(old_target_config_.leakage_converged, target_config_.leakage_converged, change_factor); current_config_.leakage_diverged = average(old_target_config_.leakage_diverged, target_config_.leakage_diverged, change_factor); current_config_.error_floor = average(old_target_config_.error_floor, target_config_.error_floor, change_factor); current_config_.error_ceil = average(old_target_config_.error_ceil, target_config_.error_ceil, change_factor); current_config_.noise_gate = average(old_target_config_.noise_gate, target_config_.noise_gate, change_factor); } else { current_config_ = old_target_config_ = target_config_; } } RTC_DCHECK_LE(0, config_change_counter_); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/refined_filter_update_gain.h0000664000175000017500000000575014475643423031475 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_REFINED_FILTER_UPDATE_GAIN_H_ #define MODULES_AUDIO_PROCESSING_AEC3_REFINED_FILTER_UPDATE_GAIN_H_ #include #include #include #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" namespace webrtc { class AdaptiveFirFilter; class ApmDataDumper; struct EchoPathVariability; struct FftData; class RenderSignalAnalyzer; struct SubtractorOutput; // Provides functionality for computing the adaptive gain for the refined // filter. class RefinedFilterUpdateGain { public: RefinedFilterUpdateGain( const EchoCanceller3Config::Filter::RefinedConfiguration& config, size_t config_change_duration_blocks); ~RefinedFilterUpdateGain(); RefinedFilterUpdateGain(const RefinedFilterUpdateGain&) = delete; RefinedFilterUpdateGain& operator=(const RefinedFilterUpdateGain&) = delete; // Takes action in the case of a known echo path change. void HandleEchoPathChange(const EchoPathVariability& echo_path_variability); // Computes the gain. void Compute(const std::array& render_power, const RenderSignalAnalyzer& render_signal_analyzer, const SubtractorOutput& subtractor_output, rtc::ArrayView erl, size_t size_partitions, bool saturated_capture_signal, FftData* gain_fft); // Sets a new config. void SetConfig( const EchoCanceller3Config::Filter::RefinedConfiguration& config, bool immediate_effect) { if (immediate_effect) { old_target_config_ = current_config_ = target_config_ = config; config_change_counter_ = 0; } else { old_target_config_ = current_config_; target_config_ = config; config_change_counter_ = config_change_duration_blocks_; } } private: static int instance_count_; std::unique_ptr data_dumper_; const int config_change_duration_blocks_; float one_by_config_change_duration_blocks_; EchoCanceller3Config::Filter::RefinedConfiguration current_config_; EchoCanceller3Config::Filter::RefinedConfiguration target_config_; EchoCanceller3Config::Filter::RefinedConfiguration old_target_config_; std::array H_error_; size_t poor_excitation_counter_; size_t call_counter_ = 0; int config_change_counter_ = 0; // Updates the current config towards the target config. void UpdateCurrentConfig(); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_REFINED_FILTER_UPDATE_GAIN_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/render_buffer.cc0000664000175000017500000000557314475643423027125 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/render_buffer.h" #include #include #include "modules/audio_processing/aec3/aec3_common.h" #include "rtc_base/checks.h" namespace webrtc { RenderBuffer::RenderBuffer(BlockBuffer* block_buffer, SpectrumBuffer* spectrum_buffer, FftBuffer* fft_buffer) : block_buffer_(block_buffer), spectrum_buffer_(spectrum_buffer), fft_buffer_(fft_buffer) { RTC_DCHECK(block_buffer_); RTC_DCHECK(spectrum_buffer_); RTC_DCHECK(fft_buffer_); RTC_DCHECK_EQ(block_buffer_->buffer.size(), fft_buffer_->buffer.size()); RTC_DCHECK_EQ(spectrum_buffer_->buffer.size(), fft_buffer_->buffer.size()); RTC_DCHECK_EQ(spectrum_buffer_->read, fft_buffer_->read); RTC_DCHECK_EQ(spectrum_buffer_->write, fft_buffer_->write); } RenderBuffer::~RenderBuffer() = default; void RenderBuffer::SpectralSum( size_t num_spectra, std::array* X2) const { X2->fill(0.f); int position = spectrum_buffer_->read; for (size_t j = 0; j < num_spectra; ++j) { for (const auto& channel_spectrum : spectrum_buffer_->buffer[position]) { std::transform(X2->begin(), X2->end(), channel_spectrum.begin(), X2->begin(), std::plus()); } position = spectrum_buffer_->IncIndex(position); } } void RenderBuffer::SpectralSums( size_t num_spectra_shorter, size_t num_spectra_longer, std::array* X2_shorter, std::array* X2_longer) const { RTC_DCHECK_LE(num_spectra_shorter, num_spectra_longer); X2_shorter->fill(0.f); int position = spectrum_buffer_->read; size_t j = 0; for (; j < num_spectra_shorter; ++j) { for (const auto& channel_spectrum : spectrum_buffer_->buffer[position]) { std::transform(X2_shorter->begin(), X2_shorter->end(), channel_spectrum.begin(), X2_shorter->begin(), std::plus()); } position = spectrum_buffer_->IncIndex(position); } std::copy(X2_shorter->begin(), X2_shorter->end(), X2_longer->begin()); for (; j < num_spectra_longer; ++j) { for (const auto& channel_spectrum : spectrum_buffer_->buffer[position]) { std::transform(X2_longer->begin(), X2_longer->end(), channel_spectrum.begin(), X2_longer->begin(), std::plus()); } position = spectrum_buffer_->IncIndex(position); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/render_buffer.h0000664000175000017500000000771614475643423026770 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_RENDER_BUFFER_H_ #define MODULES_AUDIO_PROCESSING_AEC3_RENDER_BUFFER_H_ #include #include #include #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/block_buffer.h" #include "modules/audio_processing/aec3/fft_buffer.h" #include "modules/audio_processing/aec3/fft_data.h" #include "modules/audio_processing/aec3/spectrum_buffer.h" #include "rtc_base/checks.h" namespace webrtc { // Provides a buffer of the render data for the echo remover. class RenderBuffer { public: RenderBuffer(BlockBuffer* block_buffer, SpectrumBuffer* spectrum_buffer, FftBuffer* fft_buffer); RenderBuffer() = delete; RenderBuffer(const RenderBuffer&) = delete; RenderBuffer& operator=(const RenderBuffer&) = delete; ~RenderBuffer(); // Get a block. const std::vector>>& Block( int buffer_offset_blocks) const { int position = block_buffer_->OffsetIndex(block_buffer_->read, buffer_offset_blocks); return block_buffer_->buffer[position]; } // Get the spectrum from one of the FFTs in the buffer. rtc::ArrayView> Spectrum( int buffer_offset_ffts) const { int position = spectrum_buffer_->OffsetIndex(spectrum_buffer_->read, buffer_offset_ffts); return spectrum_buffer_->buffer[position]; } // Returns the circular fft buffer. rtc::ArrayView> GetFftBuffer() const { return fft_buffer_->buffer; } // Returns the current position in the circular buffer. size_t Position() const { RTC_DCHECK_EQ(spectrum_buffer_->read, fft_buffer_->read); RTC_DCHECK_EQ(spectrum_buffer_->write, fft_buffer_->write); return fft_buffer_->read; } // Returns the sum of the spectrums for a certain number of FFTs. void SpectralSum(size_t num_spectra, std::array* X2) const; // Returns the sums of the spectrums for two numbers of FFTs. void SpectralSums(size_t num_spectra_shorter, size_t num_spectra_longer, std::array* X2_shorter, std::array* X2_longer) const; // Gets the recent activity seen in the render signal. bool GetRenderActivity() const { return render_activity_; } // Specifies the recent activity seen in the render signal. void SetRenderActivity(bool activity) { render_activity_ = activity; } // Returns the headroom between the write and the read positions in the // buffer. int Headroom() const { // The write and read indices are decreased over time. int headroom = fft_buffer_->write < fft_buffer_->read ? fft_buffer_->read - fft_buffer_->write : fft_buffer_->size - fft_buffer_->write + fft_buffer_->read; RTC_DCHECK_LE(0, headroom); RTC_DCHECK_GE(fft_buffer_->size, headroom); return headroom; } // Returns a reference to the spectrum buffer. const SpectrumBuffer& GetSpectrumBuffer() const { return *spectrum_buffer_; } // Returns a reference to the block buffer. const BlockBuffer& GetBlockBuffer() const { return *block_buffer_; } private: const BlockBuffer* const block_buffer_; const SpectrumBuffer* const spectrum_buffer_; const FftBuffer* const fft_buffer_; bool render_activity_ = false; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_RENDER_BUFFER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/render_delay_buffer.cc0000664000175000017500000004656414475643423030310 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/render_delay_buffer.h" #include #include #include #include #include #include #include "absl/types/optional.h" #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/aec3_fft.h" #include "modules/audio_processing/aec3/alignment_mixer.h" #include "modules/audio_processing/aec3/block_buffer.h" #include "modules/audio_processing/aec3/decimator.h" #include "modules/audio_processing/aec3/downsampled_render_buffer.h" #include "modules/audio_processing/aec3/fft_buffer.h" #include "modules/audio_processing/aec3/fft_data.h" #include "modules/audio_processing/aec3/render_buffer.h" #include "modules/audio_processing/aec3/spectrum_buffer.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/atomic_ops.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "system_wrappers/include/field_trial.h" namespace webrtc { namespace { bool UpdateCaptureCallCounterOnSkippedBlocks() { return !field_trial::IsEnabled( "WebRTC-Aec3RenderBufferCallCounterUpdateKillSwitch"); } class RenderDelayBufferImpl final : public RenderDelayBuffer { public: RenderDelayBufferImpl(const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels); RenderDelayBufferImpl() = delete; ~RenderDelayBufferImpl() override; void Reset() override; BufferingEvent Insert( const std::vector>>& block) override; BufferingEvent PrepareCaptureProcessing() override; void HandleSkippedCaptureProcessing() override; bool AlignFromDelay(size_t delay) override; void AlignFromExternalDelay() override; size_t Delay() const override { return ComputeDelay(); } size_t MaxDelay() const override { return blocks_.buffer.size() - 1 - buffer_headroom_; } RenderBuffer* GetRenderBuffer() override { return &echo_remover_buffer_; } const DownsampledRenderBuffer& GetDownsampledRenderBuffer() const override { return low_rate_; } int BufferLatency() const; void SetAudioBufferDelay(int delay_ms) override; bool HasReceivedBufferDelay() override; private: static int instance_count_; std::unique_ptr data_dumper_; const Aec3Optimization optimization_; const EchoCanceller3Config config_; const bool update_capture_call_counter_on_skipped_blocks_; const float render_linear_amplitude_gain_; const rtc::LoggingSeverity delay_log_level_; size_t down_sampling_factor_; const int sub_block_size_; BlockBuffer blocks_; SpectrumBuffer spectra_; FftBuffer ffts_; absl::optional delay_; RenderBuffer echo_remover_buffer_; DownsampledRenderBuffer low_rate_; AlignmentMixer render_mixer_; Decimator render_decimator_; const Aec3Fft fft_; std::vector render_ds_; const int buffer_headroom_; bool last_call_was_render_ = false; int num_api_calls_in_a_row_ = 0; int max_observed_jitter_ = 1; int64_t capture_call_counter_ = 0; int64_t render_call_counter_ = 0; bool render_activity_ = false; size_t render_activity_counter_ = 0; absl::optional external_audio_buffer_delay_; bool external_audio_buffer_delay_verified_after_reset_ = false; size_t min_latency_blocks_ = 0; size_t excess_render_detection_counter_ = 0; int MapDelayToTotalDelay(size_t delay) const; int ComputeDelay() const; void ApplyTotalDelay(int delay); void InsertBlock(const std::vector>>& block, int previous_write); bool DetectActiveRender(rtc::ArrayView x) const; bool DetectExcessRenderBlocks(); void IncrementWriteIndices(); void IncrementLowRateReadIndices(); void IncrementReadIndices(); bool RenderOverrun(); bool RenderUnderrun(); }; int RenderDelayBufferImpl::instance_count_ = 0; RenderDelayBufferImpl::RenderDelayBufferImpl(const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels) : data_dumper_( new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), optimization_(DetectOptimization()), config_(config), update_capture_call_counter_on_skipped_blocks_( UpdateCaptureCallCounterOnSkippedBlocks()), render_linear_amplitude_gain_( std::pow(10.0f, config_.render_levels.render_power_gain_db / 20.f)), delay_log_level_(config_.delay.log_warning_on_delay_changes ? rtc::LS_WARNING : rtc::LS_VERBOSE), down_sampling_factor_(config.delay.down_sampling_factor), sub_block_size_(static_cast(down_sampling_factor_ > 0 ? kBlockSize / down_sampling_factor_ : kBlockSize)), blocks_(GetRenderDelayBufferSize(down_sampling_factor_, config.delay.num_filters, config.filter.refined.length_blocks), NumBandsForRate(sample_rate_hz), num_render_channels, kBlockSize), spectra_(blocks_.buffer.size(), num_render_channels), ffts_(blocks_.buffer.size(), num_render_channels), delay_(config_.delay.default_delay), echo_remover_buffer_(&blocks_, &spectra_, &ffts_), low_rate_(GetDownSampledBufferSize(down_sampling_factor_, config.delay.num_filters)), render_mixer_(num_render_channels, config.delay.render_alignment_mixing), render_decimator_(down_sampling_factor_), fft_(), render_ds_(sub_block_size_, 0.f), buffer_headroom_(config.filter.refined.length_blocks) { RTC_DCHECK_EQ(blocks_.buffer.size(), ffts_.buffer.size()); RTC_DCHECK_EQ(spectra_.buffer.size(), ffts_.buffer.size()); for (size_t i = 0; i < blocks_.buffer.size(); ++i) { RTC_DCHECK_EQ(blocks_.buffer[i][0].size(), ffts_.buffer[i].size()); RTC_DCHECK_EQ(spectra_.buffer[i].size(), ffts_.buffer[i].size()); } Reset(); } RenderDelayBufferImpl::~RenderDelayBufferImpl() = default; // Resets the buffer delays and clears the reported delays. void RenderDelayBufferImpl::Reset() { last_call_was_render_ = false; num_api_calls_in_a_row_ = 1; min_latency_blocks_ = 0; excess_render_detection_counter_ = 0; // Initialize the read index to one sub-block before the write index. low_rate_.read = low_rate_.OffsetIndex(low_rate_.write, sub_block_size_); // Check for any external audio buffer delay and whether it is feasible. if (external_audio_buffer_delay_) { const int headroom = 2; size_t audio_buffer_delay_to_set; // Minimum delay is 1 (like the low-rate render buffer). if (*external_audio_buffer_delay_ <= headroom) { audio_buffer_delay_to_set = 1; } else { audio_buffer_delay_to_set = *external_audio_buffer_delay_ - headroom; } audio_buffer_delay_to_set = std::min(audio_buffer_delay_to_set, MaxDelay()); // When an external delay estimate is available, use that delay as the // initial render buffer delay. ApplyTotalDelay(audio_buffer_delay_to_set); delay_ = ComputeDelay(); external_audio_buffer_delay_verified_after_reset_ = false; } else { // If an external delay estimate is not available, use that delay as the // initial delay. Set the render buffer delays to the default delay. ApplyTotalDelay(config_.delay.default_delay); // Unset the delays which are set by AlignFromDelay. delay_ = absl::nullopt; } } // Inserts a new block into the render buffers. RenderDelayBuffer::BufferingEvent RenderDelayBufferImpl::Insert( const std::vector>>& block) { ++render_call_counter_; if (delay_) { if (!last_call_was_render_) { last_call_was_render_ = true; num_api_calls_in_a_row_ = 1; } else { if (++num_api_calls_in_a_row_ > max_observed_jitter_) { max_observed_jitter_ = num_api_calls_in_a_row_; RTC_LOG_V(delay_log_level_) << "New max number api jitter observed at render block " << render_call_counter_ << ": " << num_api_calls_in_a_row_ << " blocks"; } } } // Increase the write indices to where the new blocks should be written. const int previous_write = blocks_.write; IncrementWriteIndices(); // Allow overrun and do a reset when render overrun occurrs due to more render // data being inserted than capture data is received. BufferingEvent event = RenderOverrun() ? BufferingEvent::kRenderOverrun : BufferingEvent::kNone; // Detect and update render activity. if (!render_activity_) { render_activity_counter_ += DetectActiveRender(block[0][0]) ? 1 : 0; render_activity_ = render_activity_counter_ >= 20; } // Insert the new render block into the specified position. InsertBlock(block, previous_write); if (event != BufferingEvent::kNone) { Reset(); } return event; } void RenderDelayBufferImpl::HandleSkippedCaptureProcessing() { if (update_capture_call_counter_on_skipped_blocks_) { ++capture_call_counter_; } } // Prepares the render buffers for processing another capture block. RenderDelayBuffer::BufferingEvent RenderDelayBufferImpl::PrepareCaptureProcessing() { RenderDelayBuffer::BufferingEvent event = BufferingEvent::kNone; ++capture_call_counter_; if (delay_) { if (last_call_was_render_) { last_call_was_render_ = false; num_api_calls_in_a_row_ = 1; } else { if (++num_api_calls_in_a_row_ > max_observed_jitter_) { max_observed_jitter_ = num_api_calls_in_a_row_; RTC_LOG_V(delay_log_level_) << "New max number api jitter observed at capture block " << capture_call_counter_ << ": " << num_api_calls_in_a_row_ << " blocks"; } } } if (DetectExcessRenderBlocks()) { // Too many render blocks compared to capture blocks. Risk of delay ending // up before the filter used by the delay estimator. RTC_LOG_V(delay_log_level_) << "Excess render blocks detected at block " << capture_call_counter_; Reset(); event = BufferingEvent::kRenderOverrun; } else if (RenderUnderrun()) { // Don't increment the read indices of the low rate buffer if there is a // render underrun. RTC_LOG_V(delay_log_level_) << "Render buffer underrun detected at block " << capture_call_counter_; IncrementReadIndices(); // Incrementing the buffer index without increasing the low rate buffer // index means that the delay is reduced by one. if (delay_ && *delay_ > 0) delay_ = *delay_ - 1; event = BufferingEvent::kRenderUnderrun; } else { // Increment the read indices in the render buffers to point to the most // recent block to use in the capture processing. IncrementLowRateReadIndices(); IncrementReadIndices(); } echo_remover_buffer_.SetRenderActivity(render_activity_); if (render_activity_) { render_activity_counter_ = 0; render_activity_ = false; } return event; } // Sets the delay and returns a bool indicating whether the delay was changed. bool RenderDelayBufferImpl::AlignFromDelay(size_t delay) { RTC_DCHECK(!config_.delay.use_external_delay_estimator); if (!external_audio_buffer_delay_verified_after_reset_ && external_audio_buffer_delay_ && delay_) { int difference = static_cast(delay) - static_cast(*delay_); RTC_LOG_V(delay_log_level_) << "Mismatch between first estimated delay after reset " "and externally reported audio buffer delay: " << difference << " blocks"; external_audio_buffer_delay_verified_after_reset_ = true; } if (delay_ && *delay_ == delay) { return false; } delay_ = delay; // Compute the total delay and limit the delay to the allowed range. int total_delay = MapDelayToTotalDelay(*delay_); total_delay = std::min(MaxDelay(), static_cast(std::max(total_delay, 0))); // Apply the delay to the buffers. ApplyTotalDelay(total_delay); return true; } void RenderDelayBufferImpl::SetAudioBufferDelay(int delay_ms) { if (!external_audio_buffer_delay_) { RTC_LOG_V(delay_log_level_) << "Receiving a first externally reported audio buffer delay of " << delay_ms << " ms."; } // Convert delay from milliseconds to blocks (rounded down). external_audio_buffer_delay_ = delay_ms / 4; } bool RenderDelayBufferImpl::HasReceivedBufferDelay() { return external_audio_buffer_delay_.has_value(); } // Maps the externally computed delay to the delay used internally. int RenderDelayBufferImpl::MapDelayToTotalDelay( size_t external_delay_blocks) const { const int latency_blocks = BufferLatency(); return latency_blocks + static_cast(external_delay_blocks); } // Returns the delay (not including call jitter). int RenderDelayBufferImpl::ComputeDelay() const { const int latency_blocks = BufferLatency(); int internal_delay = spectra_.read >= spectra_.write ? spectra_.read - spectra_.write : spectra_.size + spectra_.read - spectra_.write; return internal_delay - latency_blocks; } // Set the read indices according to the delay. void RenderDelayBufferImpl::ApplyTotalDelay(int delay) { RTC_LOG_V(delay_log_level_) << "Applying total delay of " << delay << " blocks."; blocks_.read = blocks_.OffsetIndex(blocks_.write, -delay); spectra_.read = spectra_.OffsetIndex(spectra_.write, delay); ffts_.read = ffts_.OffsetIndex(ffts_.write, delay); } void RenderDelayBufferImpl::AlignFromExternalDelay() { RTC_DCHECK(config_.delay.use_external_delay_estimator); if (external_audio_buffer_delay_) { const int64_t delay = render_call_counter_ - capture_call_counter_ + *external_audio_buffer_delay_; const int64_t delay_with_headroom = delay - config_.delay.delay_headroom_samples / kBlockSize; ApplyTotalDelay(delay_with_headroom); } } // Inserts a block into the render buffers. void RenderDelayBufferImpl::InsertBlock( const std::vector>>& block, int previous_write) { auto& b = blocks_; auto& lr = low_rate_; auto& ds = render_ds_; auto& f = ffts_; auto& s = spectra_; const size_t num_bands = b.buffer[b.write].size(); const size_t num_render_channels = b.buffer[b.write][0].size(); RTC_DCHECK_EQ(block.size(), b.buffer[b.write].size()); for (size_t band = 0; band < num_bands; ++band) { RTC_DCHECK_EQ(block[band].size(), num_render_channels); RTC_DCHECK_EQ(b.buffer[b.write][band].size(), num_render_channels); for (size_t ch = 0; ch < num_render_channels; ++ch) { RTC_DCHECK_EQ(block[band][ch].size(), b.buffer[b.write][band][ch].size()); std::copy(block[band][ch].begin(), block[band][ch].end(), b.buffer[b.write][band][ch].begin()); } } if (render_linear_amplitude_gain_ != 1.f) { for (size_t band = 0; band < num_bands; ++band) { for (size_t ch = 0; ch < num_render_channels; ++ch) { for (size_t k = 0; k < 64; ++k) { b.buffer[b.write][band][ch][k] *= render_linear_amplitude_gain_; } } } } std::array downmixed_render; render_mixer_.ProduceOutput(b.buffer[b.write][0], downmixed_render); render_decimator_.Decimate(downmixed_render, ds); data_dumper_->DumpWav("aec3_render_decimator_output", ds.size(), ds.data(), 16000 / down_sampling_factor_, 1); std::copy(ds.rbegin(), ds.rend(), lr.buffer.begin() + lr.write); for (size_t channel = 0; channel < b.buffer[b.write][0].size(); ++channel) { fft_.PaddedFft(b.buffer[b.write][0][channel], b.buffer[previous_write][0][channel], &f.buffer[f.write][channel]); f.buffer[f.write][channel].Spectrum(optimization_, s.buffer[s.write][channel]); } } bool RenderDelayBufferImpl::DetectActiveRender( rtc::ArrayView x) const { const float x_energy = std::inner_product(x.begin(), x.end(), x.begin(), 0.f); return x_energy > (config_.render_levels.active_render_limit * config_.render_levels.active_render_limit) * kFftLengthBy2; } bool RenderDelayBufferImpl::DetectExcessRenderBlocks() { bool excess_render_detected = false; const size_t latency_blocks = static_cast(BufferLatency()); // The recently seen minimum latency in blocks. Should be close to 0. min_latency_blocks_ = std::min(min_latency_blocks_, latency_blocks); // After processing a configurable number of blocks the minimum latency is // checked. if (++excess_render_detection_counter_ >= config_.buffering.excess_render_detection_interval_blocks) { // If the minimum latency is not lower than the threshold there have been // more render than capture frames. excess_render_detected = min_latency_blocks_ > config_.buffering.max_allowed_excess_render_blocks; // Reset the counter and let the minimum latency be the current latency. min_latency_blocks_ = latency_blocks; excess_render_detection_counter_ = 0; } data_dumper_->DumpRaw("aec3_latency_blocks", latency_blocks); data_dumper_->DumpRaw("aec3_min_latency_blocks", min_latency_blocks_); data_dumper_->DumpRaw("aec3_excess_render_detected", excess_render_detected); return excess_render_detected; } // Computes the latency in the buffer (the number of unread sub-blocks). int RenderDelayBufferImpl::BufferLatency() const { const DownsampledRenderBuffer& l = low_rate_; int latency_samples = (l.buffer.size() + l.read - l.write) % l.buffer.size(); int latency_blocks = latency_samples / sub_block_size_; return latency_blocks; } // Increments the write indices for the render buffers. void RenderDelayBufferImpl::IncrementWriteIndices() { low_rate_.UpdateWriteIndex(-sub_block_size_); blocks_.IncWriteIndex(); spectra_.DecWriteIndex(); ffts_.DecWriteIndex(); } // Increments the read indices of the low rate render buffers. void RenderDelayBufferImpl::IncrementLowRateReadIndices() { low_rate_.UpdateReadIndex(-sub_block_size_); } // Increments the read indices for the render buffers. void RenderDelayBufferImpl::IncrementReadIndices() { if (blocks_.read != blocks_.write) { blocks_.IncReadIndex(); spectra_.DecReadIndex(); ffts_.DecReadIndex(); } } // Checks for a render buffer overrun. bool RenderDelayBufferImpl::RenderOverrun() { return low_rate_.read == low_rate_.write || blocks_.read == blocks_.write; } // Checks for a render buffer underrun. bool RenderDelayBufferImpl::RenderUnderrun() { return low_rate_.read == low_rate_.write; } } // namespace RenderDelayBuffer* RenderDelayBuffer::Create(const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels) { return new RenderDelayBufferImpl(config, sample_rate_hz, num_render_channels); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/render_delay_buffer.h0000664000175000017500000000556114475643423030142 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_RENDER_DELAY_BUFFER_H_ #define MODULES_AUDIO_PROCESSING_AEC3_RENDER_DELAY_BUFFER_H_ #include #include #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/downsampled_render_buffer.h" #include "modules/audio_processing/aec3/render_buffer.h" namespace webrtc { // Class for buffering the incoming render blocks such that these may be // extracted with a specified delay. class RenderDelayBuffer { public: enum class BufferingEvent { kNone, kRenderUnderrun, kRenderOverrun, kApiCallSkew }; static RenderDelayBuffer* Create(const EchoCanceller3Config& config, int sample_rate_hz, size_t num_render_channels); virtual ~RenderDelayBuffer() = default; // Resets the buffer alignment. virtual void Reset() = 0; // Inserts a block into the buffer. virtual BufferingEvent Insert( const std::vector>>& block) = 0; // Updates the buffers one step based on the specified buffer delay. Returns // an enum indicating whether there was a special event that occurred. virtual BufferingEvent PrepareCaptureProcessing() = 0; // Called on capture blocks where PrepareCaptureProcessing is not called. virtual void HandleSkippedCaptureProcessing() = 0; // Sets the buffer delay and returns a bool indicating whether the delay // changed. virtual bool AlignFromDelay(size_t delay) = 0; // Sets the buffer delay from the most recently reported external delay. virtual void AlignFromExternalDelay() = 0; // Gets the buffer delay. virtual size_t Delay() const = 0; // Gets the buffer delay. virtual size_t MaxDelay() const = 0; // Returns the render buffer for the echo remover. virtual RenderBuffer* GetRenderBuffer() = 0; // Returns the downsampled render buffer. virtual const DownsampledRenderBuffer& GetDownsampledRenderBuffer() const = 0; // Returns the maximum non calusal offset that can occur in the delay buffer. static int DelayEstimatorOffset(const EchoCanceller3Config& config); // Provides an optional external estimate of the audio buffer delay. virtual void SetAudioBufferDelay(int delay_ms) = 0; // Returns whether an external delay estimate has been reported via // SetAudioBufferDelay. virtual bool HasReceivedBufferDelay() = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_RENDER_DELAY_BUFFER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/render_delay_controller.cc0000664000175000017500000001566614475643423031221 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/render_delay_controller.h" #include #include #include #include "absl/types/optional.h" #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/delay_estimate.h" #include "modules/audio_processing/aec3/downsampled_render_buffer.h" #include "modules/audio_processing/aec3/echo_path_delay_estimator.h" #include "modules/audio_processing/aec3/render_delay_controller_metrics.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/atomic_ops.h" #include "rtc_base/checks.h" namespace webrtc { namespace { class RenderDelayControllerImpl final : public RenderDelayController { public: RenderDelayControllerImpl(const EchoCanceller3Config& config, int sample_rate_hz, size_t num_capture_channels); RenderDelayControllerImpl() = delete; RenderDelayControllerImpl(const RenderDelayControllerImpl&) = delete; RenderDelayControllerImpl& operator=(const RenderDelayControllerImpl&) = delete; ~RenderDelayControllerImpl() override; void Reset(bool reset_delay_confidence) override; void LogRenderCall() override; absl::optional GetDelay( const DownsampledRenderBuffer& render_buffer, size_t render_delay_buffer_delay, const std::vector>& capture) override; bool HasClockdrift() const override; private: static int instance_count_; std::unique_ptr data_dumper_; const int hysteresis_limit_blocks_; const int delay_headroom_samples_; absl::optional delay_; EchoPathDelayEstimator delay_estimator_; RenderDelayControllerMetrics metrics_; absl::optional delay_samples_; size_t capture_call_counter_ = 0; int delay_change_counter_ = 0; DelayEstimate::Quality last_delay_estimate_quality_; }; DelayEstimate ComputeBufferDelay( const absl::optional& current_delay, int hysteresis_limit_blocks, int delay_headroom_samples, DelayEstimate estimated_delay) { // Subtract delay headroom. const int delay_with_headroom_samples = std::max( static_cast(estimated_delay.delay) - delay_headroom_samples, 0); // Compute the buffer delay increase required to achieve the desired latency. size_t new_delay_blocks = delay_with_headroom_samples >> kBlockSizeLog2; // Add hysteresis. if (current_delay) { size_t current_delay_blocks = current_delay->delay; if (new_delay_blocks > current_delay_blocks && new_delay_blocks <= current_delay_blocks + hysteresis_limit_blocks) { new_delay_blocks = current_delay_blocks; } } DelayEstimate new_delay = estimated_delay; new_delay.delay = new_delay_blocks; return new_delay; } int RenderDelayControllerImpl::instance_count_ = 0; RenderDelayControllerImpl::RenderDelayControllerImpl( const EchoCanceller3Config& config, int sample_rate_hz, size_t num_capture_channels) : data_dumper_( new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), hysteresis_limit_blocks_( static_cast(config.delay.hysteresis_limit_blocks)), delay_headroom_samples_(config.delay.delay_headroom_samples), delay_estimator_(data_dumper_.get(), config, num_capture_channels), last_delay_estimate_quality_(DelayEstimate::Quality::kCoarse) { RTC_DCHECK(ValidFullBandRate(sample_rate_hz)); delay_estimator_.LogDelayEstimationProperties(sample_rate_hz, 0); } RenderDelayControllerImpl::~RenderDelayControllerImpl() = default; void RenderDelayControllerImpl::Reset(bool reset_delay_confidence) { delay_ = absl::nullopt; delay_samples_ = absl::nullopt; delay_estimator_.Reset(reset_delay_confidence); delay_change_counter_ = 0; if (reset_delay_confidence) { last_delay_estimate_quality_ = DelayEstimate::Quality::kCoarse; } } void RenderDelayControllerImpl::LogRenderCall() {} absl::optional RenderDelayControllerImpl::GetDelay( const DownsampledRenderBuffer& render_buffer, size_t render_delay_buffer_delay, const std::vector>& capture) { RTC_DCHECK_EQ(kBlockSize, capture[0].size()); ++capture_call_counter_; auto delay_samples = delay_estimator_.EstimateDelay(render_buffer, capture); if (delay_samples) { if (!delay_samples_ || delay_samples->delay != delay_samples_->delay) { delay_change_counter_ = 0; } if (delay_samples_) { delay_samples_->blocks_since_last_change = delay_samples_->delay == delay_samples->delay ? delay_samples_->blocks_since_last_change + 1 : 0; delay_samples_->blocks_since_last_update = 0; delay_samples_->delay = delay_samples->delay; delay_samples_->quality = delay_samples->quality; } else { delay_samples_ = delay_samples; } } else { if (delay_samples_) { ++delay_samples_->blocks_since_last_change; ++delay_samples_->blocks_since_last_update; } } if (delay_change_counter_ < 2 * kNumBlocksPerSecond) { ++delay_change_counter_; } if (delay_samples_) { // Compute the render delay buffer delay. const bool use_hysteresis = last_delay_estimate_quality_ == DelayEstimate::Quality::kRefined && delay_samples_->quality == DelayEstimate::Quality::kRefined; delay_ = ComputeBufferDelay(delay_, use_hysteresis ? hysteresis_limit_blocks_ : 0, delay_headroom_samples_, *delay_samples_); last_delay_estimate_quality_ = delay_samples_->quality; } metrics_.Update(delay_samples_ ? absl::optional(delay_samples_->delay) : absl::nullopt, delay_ ? delay_->delay : 0, 0, delay_estimator_.Clockdrift()); data_dumper_->DumpRaw("aec3_render_delay_controller_delay", delay_samples ? delay_samples->delay : 0); data_dumper_->DumpRaw("aec3_render_delay_controller_buffer_delay", delay_ ? delay_->delay : 0); return delay_; } bool RenderDelayControllerImpl::HasClockdrift() const { return delay_estimator_.Clockdrift() != ClockdriftDetector::Level::kNone; } } // namespace RenderDelayController* RenderDelayController::Create( const EchoCanceller3Config& config, int sample_rate_hz, size_t num_capture_channels) { return new RenderDelayControllerImpl(config, sample_rate_hz, num_capture_channels); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/render_delay_controller.h0000664000175000017500000000370414475643423031051 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_RENDER_DELAY_CONTROLLER_H_ #define MODULES_AUDIO_PROCESSING_AEC3_RENDER_DELAY_CONTROLLER_H_ #include "absl/types/optional.h" #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/delay_estimate.h" #include "modules/audio_processing/aec3/downsampled_render_buffer.h" #include "modules/audio_processing/aec3/render_delay_buffer.h" #include "modules/audio_processing/logging/apm_data_dumper.h" namespace webrtc { // Class for aligning the render and capture signal using a RenderDelayBuffer. class RenderDelayController { public: static RenderDelayController* Create(const EchoCanceller3Config& config, int sample_rate_hz, size_t num_capture_channels); virtual ~RenderDelayController() = default; // Resets the delay controller. If the delay confidence is reset, the reset // behavior is as if the call is restarted. virtual void Reset(bool reset_delay_confidence) = 0; // Logs a render call. virtual void LogRenderCall() = 0; // Aligns the render buffer content with the capture signal. virtual absl::optional GetDelay( const DownsampledRenderBuffer& render_buffer, size_t render_delay_buffer_delay, const std::vector>& capture) = 0; // Returns true if clockdrift has been detected. virtual bool HasClockdrift() const = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_RENDER_DELAY_CONTROLLER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/render_delay_controller_metrics.cc0000664000175000017500000001106014475643423032727 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/render_delay_controller_metrics.h" #include #include "modules/audio_processing/aec3/aec3_common.h" #include "rtc_base/checks.h" #include "system_wrappers/include/metrics.h" namespace webrtc { namespace { enum class DelayReliabilityCategory { kNone, kPoor, kMedium, kGood, kExcellent, kNumCategories }; enum class DelayChangesCategory { kNone, kFew, kSeveral, kMany, kConstant, kNumCategories }; constexpr int kMaxSkewShiftCount = 20; } // namespace RenderDelayControllerMetrics::RenderDelayControllerMetrics() = default; void RenderDelayControllerMetrics::Update( absl::optional delay_samples, size_t buffer_delay_blocks, absl::optional skew_shift_blocks, ClockdriftDetector::Level clockdrift) { ++call_counter_; if (!initial_update) { size_t delay_blocks; if (delay_samples) { ++reliable_delay_estimate_counter_; delay_blocks = (*delay_samples) / kBlockSize + 2; } else { delay_blocks = 0; } if (delay_blocks != delay_blocks_) { ++delay_change_counter_; delay_blocks_ = delay_blocks; } if (skew_shift_blocks) { skew_shift_count_ = std::min(kMaxSkewShiftCount, skew_shift_count_); } } else if (++initial_call_counter_ == 5 * kNumBlocksPerSecond) { initial_update = false; } if (call_counter_ == kMetricsReportingIntervalBlocks) { int value_to_report = static_cast(delay_blocks_); value_to_report = std::min(124, value_to_report >> 1); RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.EchoPathDelay", value_to_report, 0, 124, 125); value_to_report = static_cast(buffer_delay_blocks + 2); value_to_report = std::min(124, value_to_report >> 1); RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.BufferDelay", value_to_report, 0, 124, 125); DelayReliabilityCategory delay_reliability; if (reliable_delay_estimate_counter_ == 0) { delay_reliability = DelayReliabilityCategory::kNone; } else if (reliable_delay_estimate_counter_ > (call_counter_ >> 1)) { delay_reliability = DelayReliabilityCategory::kExcellent; } else if (reliable_delay_estimate_counter_ > 100) { delay_reliability = DelayReliabilityCategory::kGood; } else if (reliable_delay_estimate_counter_ > 10) { delay_reliability = DelayReliabilityCategory::kMedium; } else { delay_reliability = DelayReliabilityCategory::kPoor; } RTC_HISTOGRAM_ENUMERATION( "WebRTC.Audio.EchoCanceller.ReliableDelayEstimates", static_cast(delay_reliability), static_cast(DelayReliabilityCategory::kNumCategories)); DelayChangesCategory delay_changes; if (delay_change_counter_ == 0) { delay_changes = DelayChangesCategory::kNone; } else if (delay_change_counter_ > 10) { delay_changes = DelayChangesCategory::kConstant; } else if (delay_change_counter_ > 5) { delay_changes = DelayChangesCategory::kMany; } else if (delay_change_counter_ > 2) { delay_changes = DelayChangesCategory::kSeveral; } else { delay_changes = DelayChangesCategory::kFew; } RTC_HISTOGRAM_ENUMERATION( "WebRTC.Audio.EchoCanceller.DelayChanges", static_cast(delay_changes), static_cast(DelayChangesCategory::kNumCategories)); RTC_HISTOGRAM_ENUMERATION( "WebRTC.Audio.EchoCanceller.Clockdrift", static_cast(clockdrift), static_cast(ClockdriftDetector::Level::kNumCategories)); metrics_reported_ = true; call_counter_ = 0; ResetMetrics(); } else { metrics_reported_ = false; } if (!initial_update && ++skew_report_timer_ == 60 * kNumBlocksPerSecond) { RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.MaxSkewShiftCount", skew_shift_count_, 0, kMaxSkewShiftCount, kMaxSkewShiftCount + 1); skew_shift_count_ = 0; skew_report_timer_ = 0; } } void RenderDelayControllerMetrics::ResetMetrics() { delay_change_counter_ = 0; reliable_delay_estimate_counter_ = 0; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/render_delay_controller_metrics.h0000664000175000017500000000335414475643423032600 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_RENDER_DELAY_CONTROLLER_METRICS_H_ #define MODULES_AUDIO_PROCESSING_AEC3_RENDER_DELAY_CONTROLLER_METRICS_H_ #include #include "absl/types/optional.h" #include "modules/audio_processing/aec3/clockdrift_detector.h" #include "rtc_base/constructor_magic.h" namespace webrtc { // Handles the reporting of metrics for the render delay controller. class RenderDelayControllerMetrics { public: RenderDelayControllerMetrics(); // Updates the metric with new data. void Update(absl::optional delay_samples, size_t buffer_delay_blocks, absl::optional skew_shift_blocks, ClockdriftDetector::Level clockdrift); // Returns true if the metrics have just been reported, otherwise false. bool MetricsReported() { return metrics_reported_; } private: // Resets the metrics. void ResetMetrics(); size_t delay_blocks_ = 0; int reliable_delay_estimate_counter_ = 0; int delay_change_counter_ = 0; int call_counter_ = 0; int skew_report_timer_ = 0; int initial_call_counter_ = 0; bool metrics_reported_ = false; bool initial_update = true; int skew_shift_count_ = 0; RTC_DISALLOW_COPY_AND_ASSIGN(RenderDelayControllerMetrics); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_RENDER_DELAY_CONTROLLER_METRICS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/render_signal_analyzer.cc0000664000175000017500000001266714475643423031040 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/render_signal_analyzer.h" #include #include #include #include #include "api/array_view.h" #include "rtc_base/checks.h" namespace webrtc { namespace { constexpr size_t kCounterThreshold = 5; // Identifies local bands with narrow characteristics. void IdentifySmallNarrowBandRegions( const RenderBuffer& render_buffer, const absl::optional& delay_partitions, std::array* narrow_band_counters) { RTC_DCHECK(narrow_band_counters); if (!delay_partitions) { narrow_band_counters->fill(0); return; } std::array channel_counters; channel_counters.fill(0); rtc::ArrayView> X2 = render_buffer.Spectrum(*delay_partitions); for (size_t ch = 0; ch < X2.size(); ++ch) { for (size_t k = 1; k < kFftLengthBy2; ++k) { if (X2[ch][k] > 3 * std::max(X2[ch][k - 1], X2[ch][k + 1])) { ++channel_counters[k - 1]; } } } for (size_t k = 1; k < kFftLengthBy2; ++k) { (*narrow_band_counters)[k - 1] = channel_counters[k - 1] > 0 ? (*narrow_band_counters)[k - 1] + 1 : 0; } } // Identifies whether the signal has a single strong narrow-band component. void IdentifyStrongNarrowBandComponent(const RenderBuffer& render_buffer, int strong_peak_freeze_duration, absl::optional* narrow_peak_band, size_t* narrow_peak_counter) { RTC_DCHECK(narrow_peak_band); RTC_DCHECK(narrow_peak_counter); if (*narrow_peak_band && ++(*narrow_peak_counter) > static_cast(strong_peak_freeze_duration)) { *narrow_peak_band = absl::nullopt; } const std::vector>>& x_latest = render_buffer.Block(0); float max_peak_level = 0.f; for (size_t channel = 0; channel < x_latest[0].size(); ++channel) { rtc::ArrayView X2_latest = render_buffer.Spectrum(0)[channel]; // Identify the spectral peak. const int peak_bin = static_cast(std::max_element(X2_latest.begin(), X2_latest.end()) - X2_latest.begin()); // Compute the level around the peak. float non_peak_power = 0.f; for (int k = std::max(0, peak_bin - 14); k < peak_bin - 4; ++k) { non_peak_power = std::max(X2_latest[k], non_peak_power); } for (int k = peak_bin + 5; k < std::min(peak_bin + 15, static_cast(kFftLengthBy2Plus1)); ++k) { non_peak_power = std::max(X2_latest[k], non_peak_power); } // Assess the render signal strength. auto result0 = std::minmax_element(x_latest[0][channel].begin(), x_latest[0][channel].end()); float max_abs = std::max(fabs(*result0.first), fabs(*result0.second)); if (x_latest.size() > 1) { const auto result1 = std::minmax_element(x_latest[1][channel].begin(), x_latest[1][channel].end()); max_abs = std::max(max_abs, static_cast(std::max( fabs(*result1.first), fabs(*result1.second)))); } // Detect whether the spectral peak has as strong narrowband nature. const float peak_level = X2_latest[peak_bin]; if (peak_bin > 0 && max_abs > 100 && peak_level > 100 * non_peak_power) { // Store the strongest peak across channels. if (peak_level > max_peak_level) { max_peak_level = peak_level; *narrow_peak_band = peak_bin; *narrow_peak_counter = 0; } } } } } // namespace RenderSignalAnalyzer::RenderSignalAnalyzer(const EchoCanceller3Config& config) : strong_peak_freeze_duration_(config.filter.refined.length_blocks) { narrow_band_counters_.fill(0); } RenderSignalAnalyzer::~RenderSignalAnalyzer() = default; void RenderSignalAnalyzer::Update( const RenderBuffer& render_buffer, const absl::optional& delay_partitions) { // Identify bands of narrow nature. IdentifySmallNarrowBandRegions(render_buffer, delay_partitions, &narrow_band_counters_); // Identify the presence of a strong narrow band. IdentifyStrongNarrowBandComponent(render_buffer, strong_peak_freeze_duration_, &narrow_peak_band_, &narrow_peak_counter_); } void RenderSignalAnalyzer::MaskRegionsAroundNarrowBands( std::array* v) const { RTC_DCHECK(v); // Set v to zero around narrow band signal regions. if (narrow_band_counters_[0] > kCounterThreshold) { (*v)[1] = (*v)[0] = 0.f; } for (size_t k = 2; k < kFftLengthBy2 - 1; ++k) { if (narrow_band_counters_[k - 1] > kCounterThreshold) { (*v)[k - 2] = (*v)[k - 1] = (*v)[k] = (*v)[k + 1] = (*v)[k + 2] = 0.f; } } if (narrow_band_counters_[kFftLengthBy2 - 2] > kCounterThreshold) { (*v)[kFftLengthBy2] = (*v)[kFftLengthBy2 - 1] = 0.f; } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/render_signal_analyzer.h0000664000175000017500000000421014475643423030663 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_RENDER_SIGNAL_ANALYZER_H_ #define MODULES_AUDIO_PROCESSING_AEC3_RENDER_SIGNAL_ANALYZER_H_ #include #include #include #include "absl/types/optional.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/render_buffer.h" #include "rtc_base/checks.h" #include "rtc_base/constructor_magic.h" namespace webrtc { // Provides functionality for analyzing the properties of the render signal. class RenderSignalAnalyzer { public: explicit RenderSignalAnalyzer(const EchoCanceller3Config& config); ~RenderSignalAnalyzer(); // Updates the render signal analysis with the most recent render signal. void Update(const RenderBuffer& render_buffer, const absl::optional& delay_partitions); // Returns true if the render signal is poorly exciting. bool PoorSignalExcitation() const { RTC_DCHECK_LT(2, narrow_band_counters_.size()); return std::any_of(narrow_band_counters_.begin(), narrow_band_counters_.end(), [](size_t a) { return a > 10; }); } // Zeros the array around regions with narrow bands signal characteristics. void MaskRegionsAroundNarrowBands( std::array* v) const; absl::optional NarrowPeakBand() const { return narrow_peak_band_; } private: const int strong_peak_freeze_duration_; std::array narrow_band_counters_; absl::optional narrow_peak_band_; size_t narrow_peak_counter_; RTC_DISALLOW_COPY_AND_ASSIGN(RenderSignalAnalyzer); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_RENDER_SIGNAL_ANALYZER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/residual_echo_estimator.cc0000664000175000017500000003301014475643423031175 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/residual_echo_estimator.h" #include #include #include #include "api/array_view.h" #include "modules/audio_processing/aec3/reverb_model.h" #include "rtc_base/checks.h" #include "system_wrappers/include/field_trial.h" namespace webrtc { namespace { constexpr float kDefaultTransparentModeGain = 0.f; float GetTransparentModeGain() { if (field_trial::IsEnabled( "WebRTC-Aec3NoSuppressionInTransparentModeKillSwitch")) { return 0.01f; } else { return kDefaultTransparentModeGain; } } float GetEarlyReflectionsDefaultModeGain( const EchoCanceller3Config::EpStrength& config) { if (field_trial::IsEnabled("WebRTC-Aec3UseLowEarlyReflectionsDefaultGain")) { return 0.1f; } return config.default_gain; } float GetLateReflectionsDefaultModeGain( const EchoCanceller3Config::EpStrength& config) { if (field_trial::IsEnabled("WebRTC-Aec3UseLowLateReflectionsDefaultGain")) { return 0.1f; } return config.default_gain; } // Computes the indexes that will be used for computing spectral power over // the blocks surrounding the delay. void GetRenderIndexesToAnalyze( const SpectrumBuffer& spectrum_buffer, const EchoCanceller3Config::EchoModel& echo_model, int filter_delay_blocks, int* idx_start, int* idx_stop) { RTC_DCHECK(idx_start); RTC_DCHECK(idx_stop); size_t window_start; size_t window_end; window_start = std::max(0, filter_delay_blocks - static_cast(echo_model.render_pre_window_size)); window_end = filter_delay_blocks + static_cast(echo_model.render_post_window_size); *idx_start = spectrum_buffer.OffsetIndex(spectrum_buffer.read, window_start); *idx_stop = spectrum_buffer.OffsetIndex(spectrum_buffer.read, window_end + 1); } // Estimates the residual echo power based on the echo return loss enhancement // (ERLE) and the linear power estimate. void LinearEstimate( rtc::ArrayView> S2_linear, rtc::ArrayView> erle, rtc::ArrayView> R2) { RTC_DCHECK_EQ(S2_linear.size(), erle.size()); RTC_DCHECK_EQ(S2_linear.size(), R2.size()); const size_t num_capture_channels = R2.size(); for (size_t ch = 0; ch < num_capture_channels; ++ch) { for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { RTC_DCHECK_LT(0.f, erle[ch][k]); R2[ch][k] = S2_linear[ch][k] / erle[ch][k]; } } } // Estimates the residual echo power based on an uncertainty estimate of the // echo return loss enhancement (ERLE) and the linear power estimate. void LinearEstimate( rtc::ArrayView> S2_linear, float erle_uncertainty, rtc::ArrayView> R2) { RTC_DCHECK_EQ(S2_linear.size(), R2.size()); const size_t num_capture_channels = R2.size(); for (size_t ch = 0; ch < num_capture_channels; ++ch) { for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { R2[ch][k] = S2_linear[ch][k] * erle_uncertainty; } } } // Estimates the residual echo power based on the estimate of the echo path // gain. void NonLinearEstimate( float echo_path_gain, const std::array& X2, rtc::ArrayView> R2) { const size_t num_capture_channels = R2.size(); for (size_t ch = 0; ch < num_capture_channels; ++ch) { for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { R2[ch][k] = X2[k] * echo_path_gain; } } } // Applies a soft noise gate to the echo generating power. void ApplyNoiseGate(const EchoCanceller3Config::EchoModel& config, rtc::ArrayView X2) { for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { if (config.noise_gate_power > X2[k]) { X2[k] = std::max(0.f, X2[k] - config.noise_gate_slope * (config.noise_gate_power - X2[k])); } } } // Estimates the echo generating signal power as gated maximal power over a // time window. void EchoGeneratingPower(size_t num_render_channels, const SpectrumBuffer& spectrum_buffer, const EchoCanceller3Config::EchoModel& echo_model, int filter_delay_blocks, rtc::ArrayView X2) { int idx_stop; int idx_start; GetRenderIndexesToAnalyze(spectrum_buffer, echo_model, filter_delay_blocks, &idx_start, &idx_stop); std::fill(X2.begin(), X2.end(), 0.f); if (num_render_channels == 1) { for (int k = idx_start; k != idx_stop; k = spectrum_buffer.IncIndex(k)) { for (size_t j = 0; j < kFftLengthBy2Plus1; ++j) { X2[j] = std::max(X2[j], spectrum_buffer.buffer[k][/*channel=*/0][j]); } } } else { for (int k = idx_start; k != idx_stop; k = spectrum_buffer.IncIndex(k)) { std::array render_power; render_power.fill(0.f); for (size_t ch = 0; ch < num_render_channels; ++ch) { const auto& channel_power = spectrum_buffer.buffer[k][ch]; for (size_t j = 0; j < kFftLengthBy2Plus1; ++j) { render_power[j] += channel_power[j]; } } for (size_t j = 0; j < kFftLengthBy2Plus1; ++j) { X2[j] = std::max(X2[j], render_power[j]); } } } } } // namespace ResidualEchoEstimator::ResidualEchoEstimator(const EchoCanceller3Config& config, size_t num_render_channels) : config_(config), num_render_channels_(num_render_channels), early_reflections_transparent_mode_gain_(GetTransparentModeGain()), late_reflections_transparent_mode_gain_(GetTransparentModeGain()), early_reflections_general_gain_( GetEarlyReflectionsDefaultModeGain(config_.ep_strength)), late_reflections_general_gain_( GetLateReflectionsDefaultModeGain(config_.ep_strength)) { Reset(); } ResidualEchoEstimator::~ResidualEchoEstimator() = default; void ResidualEchoEstimator::Estimate( const AecState& aec_state, const RenderBuffer& render_buffer, rtc::ArrayView> S2_linear, rtc::ArrayView> Y2, rtc::ArrayView> R2) { RTC_DCHECK_EQ(R2.size(), Y2.size()); RTC_DCHECK_EQ(R2.size(), S2_linear.size()); const size_t num_capture_channels = R2.size(); // Estimate the power of the stationary noise in the render signal. UpdateRenderNoisePower(render_buffer); // Estimate the residual echo power. if (aec_state.UsableLinearEstimate()) { // When there is saturated echo, assume the same spectral content as is // present in the microphone signal. if (aec_state.SaturatedEcho()) { for (size_t ch = 0; ch < num_capture_channels; ++ch) { std::copy(Y2[ch].begin(), Y2[ch].end(), R2[ch].begin()); } } else { absl::optional erle_uncertainty = aec_state.ErleUncertainty(); if (erle_uncertainty) { LinearEstimate(S2_linear, *erle_uncertainty, R2); } else { LinearEstimate(S2_linear, aec_state.Erle(), R2); } } AddReverb(ReverbType::kLinear, aec_state, render_buffer, R2); } else { const float echo_path_gain = GetEchoPathGain(aec_state, /*gain_for_early_reflections=*/true); // When there is saturated echo, assume the same spectral content as is // present in the microphone signal. if (aec_state.SaturatedEcho()) { for (size_t ch = 0; ch < num_capture_channels; ++ch) { std::copy(Y2[ch].begin(), Y2[ch].end(), R2[ch].begin()); } } else { // Estimate the echo generating signal power. std::array X2; EchoGeneratingPower(num_render_channels_, render_buffer.GetSpectrumBuffer(), config_.echo_model, aec_state.MinDirectPathFilterDelay(), X2); if (!aec_state.UseStationarityProperties()) { ApplyNoiseGate(config_.echo_model, X2); } // Subtract the stationary noise power to avoid stationary noise causing // excessive echo suppression. for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { X2[k] -= config_.echo_model.stationary_gate_slope * X2_noise_floor_[k]; X2[k] = std::max(0.f, X2[k]); } NonLinearEstimate(echo_path_gain, X2, R2); } if (config_.echo_model.model_reverb_in_nonlinear_mode && !aec_state.TransparentModeActive()) { AddReverb(ReverbType::kNonLinear, aec_state, render_buffer, R2); } } if (aec_state.UseStationarityProperties()) { // Scale the echo according to echo audibility. std::array residual_scaling; aec_state.GetResidualEchoScaling(residual_scaling); for (size_t ch = 0; ch < num_capture_channels; ++ch) { for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { R2[ch][k] *= residual_scaling[k]; } } } } void ResidualEchoEstimator::Reset() { echo_reverb_.Reset(); X2_noise_floor_counter_.fill(config_.echo_model.noise_floor_hold); X2_noise_floor_.fill(config_.echo_model.min_noise_floor_power); } void ResidualEchoEstimator::UpdateRenderNoisePower( const RenderBuffer& render_buffer) { std::array render_power_data; rtc::ArrayView> X2 = render_buffer.Spectrum(0); rtc::ArrayView render_power = X2[/*channel=*/0]; if (num_render_channels_ > 1) { render_power_data.fill(0.f); for (size_t ch = 0; ch < num_render_channels_; ++ch) { const auto& channel_power = X2[ch]; for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { render_power_data[k] += channel_power[k]; } } render_power = render_power_data; } // Estimate the stationary noise power in a minimum statistics manner. for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { // Decrease rapidly. if (render_power[k] < X2_noise_floor_[k]) { X2_noise_floor_[k] = render_power[k]; X2_noise_floor_counter_[k] = 0; } else { // Increase in a delayed, leaky manner. if (X2_noise_floor_counter_[k] >= static_cast(config_.echo_model.noise_floor_hold)) { X2_noise_floor_[k] = std::max(X2_noise_floor_[k] * 1.1f, config_.echo_model.min_noise_floor_power); } else { ++X2_noise_floor_counter_[k]; } } } } // Adds the estimated power of the reverb to the residual echo power. void ResidualEchoEstimator::AddReverb( ReverbType reverb_type, const AecState& aec_state, const RenderBuffer& render_buffer, rtc::ArrayView> R2) { const size_t num_capture_channels = R2.size(); // Choose reverb partition based on what type of echo power model is used. const size_t first_reverb_partition = reverb_type == ReverbType::kLinear ? aec_state.FilterLengthBlocks() + 1 : aec_state.MinDirectPathFilterDelay() + 1; // Compute render power for the reverb. std::array render_power_data; rtc::ArrayView> X2 = render_buffer.Spectrum(first_reverb_partition); rtc::ArrayView render_power = X2[/*channel=*/0]; if (num_render_channels_ > 1) { render_power_data.fill(0.f); for (size_t ch = 0; ch < num_render_channels_; ++ch) { const auto& channel_power = X2[ch]; for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { render_power_data[k] += channel_power[k]; } } render_power = render_power_data; } // Update the reverb estimate. if (reverb_type == ReverbType::kLinear) { echo_reverb_.UpdateReverb(render_power, aec_state.GetReverbFrequencyResponse(), aec_state.ReverbDecay()); } else { const float echo_path_gain = GetEchoPathGain(aec_state, /*gain_for_early_reflections=*/false); echo_reverb_.UpdateReverbNoFreqShaping(render_power, echo_path_gain, aec_state.ReverbDecay()); } // Add the reverb power. rtc::ArrayView reverb_power = echo_reverb_.reverb(); for (size_t ch = 0; ch < num_capture_channels; ++ch) { for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { R2[ch][k] += reverb_power[k]; } } } // Chooses the echo path gain to use. float ResidualEchoEstimator::GetEchoPathGain( const AecState& aec_state, bool gain_for_early_reflections) const { float gain_amplitude; if (aec_state.TransparentModeActive()) { gain_amplitude = gain_for_early_reflections ? early_reflections_transparent_mode_gain_ : late_reflections_transparent_mode_gain_; } else { gain_amplitude = gain_for_early_reflections ? early_reflections_general_gain_ : late_reflections_general_gain_; } return gain_amplitude * gain_amplitude; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/residual_echo_estimator.h0000664000175000017500000000545314475643423031051 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_RESIDUAL_ECHO_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_AEC3_RESIDUAL_ECHO_ESTIMATOR_H_ #include #include #include "absl/types/optional.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/aec_state.h" #include "modules/audio_processing/aec3/render_buffer.h" #include "modules/audio_processing/aec3/reverb_model.h" #include "modules/audio_processing/aec3/spectrum_buffer.h" #include "rtc_base/checks.h" namespace webrtc { class ResidualEchoEstimator { public: ResidualEchoEstimator(const EchoCanceller3Config& config, size_t num_render_channels); ~ResidualEchoEstimator(); ResidualEchoEstimator(const ResidualEchoEstimator&) = delete; ResidualEchoEstimator& operator=(const ResidualEchoEstimator&) = delete; void Estimate( const AecState& aec_state, const RenderBuffer& render_buffer, rtc::ArrayView> S2_linear, rtc::ArrayView> Y2, rtc::ArrayView> R2); private: enum class ReverbType { kLinear, kNonLinear }; // Resets the state. void Reset(); // Updates estimate for the power of the stationary noise component in the // render signal. void UpdateRenderNoisePower(const RenderBuffer& render_buffer); // Adds the estimated unmodelled echo power to the residual echo power // estimate. void AddReverb(ReverbType reverb_type, const AecState& aec_state, const RenderBuffer& render_buffer, rtc::ArrayView> R2); // Gets the echo path gain to apply. float GetEchoPathGain(const AecState& aec_state, bool gain_for_early_reflections) const; const EchoCanceller3Config config_; const size_t num_render_channels_; const float early_reflections_transparent_mode_gain_; const float late_reflections_transparent_mode_gain_; const float early_reflections_general_gain_; const float late_reflections_general_gain_; std::array X2_noise_floor_; std::array X2_noise_floor_counter_; ReverbModel echo_reverb_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_RESIDUAL_ECHO_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/reverb_decay_estimator.cc0000664000175000017500000003745014475643423031035 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/reverb_decay_estimator.h" #include #include #include #include #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" namespace webrtc { namespace { constexpr int kEarlyReverbMinSizeBlocks = 3; constexpr int kBlocksPerSection = 6; // Linear regression approach assumes symmetric index around 0. constexpr float kEarlyReverbFirstPointAtLinearRegressors = -0.5f * kBlocksPerSection * kFftLengthBy2 + 0.5f; // Averages the values in a block of size kFftLengthBy2; float BlockAverage(rtc::ArrayView v, size_t block_index) { constexpr float kOneByFftLengthBy2 = 1.f / kFftLengthBy2; const int i = block_index * kFftLengthBy2; RTC_DCHECK_GE(v.size(), i + kFftLengthBy2); const float sum = std::accumulate(v.begin() + i, v.begin() + i + kFftLengthBy2, 0.f); return sum * kOneByFftLengthBy2; } // Analyzes the gain in a block. void AnalyzeBlockGain(const std::array& h2, float floor_gain, float* previous_gain, bool* block_adapting, bool* decaying_gain) { float gain = std::max(BlockAverage(h2, 0), 1e-32f); *block_adapting = *previous_gain > 1.1f * gain || *previous_gain < 0.9f * gain; *decaying_gain = gain > floor_gain; *previous_gain = gain; } // Arithmetic sum of $2 \sum_{i=0.5}^{(N-1)/2}i^2$ calculated directly. constexpr float SymmetricArithmetricSum(int N) { return N * (N * N - 1.0f) * (1.f / 12.f); } // Returns the peak energy of an impulse response. float BlockEnergyPeak(rtc::ArrayView h, int peak_block) { RTC_DCHECK_LE((peak_block + 1) * kFftLengthBy2, h.size()); RTC_DCHECK_GE(peak_block, 0); float peak_value = *std::max_element(h.begin() + peak_block * kFftLengthBy2, h.begin() + (peak_block + 1) * kFftLengthBy2, [](float a, float b) { return a * a < b * b; }); return peak_value * peak_value; } // Returns the average energy of an impulse response block. float BlockEnergyAverage(rtc::ArrayView h, int block_index) { RTC_DCHECK_LE((block_index + 1) * kFftLengthBy2, h.size()); RTC_DCHECK_GE(block_index, 0); constexpr float kOneByFftLengthBy2 = 1.f / kFftLengthBy2; const auto sum_of_squares = [](float a, float b) { return a + b * b; }; return std::accumulate(h.begin() + block_index * kFftLengthBy2, h.begin() + (block_index + 1) * kFftLengthBy2, 0.f, sum_of_squares) * kOneByFftLengthBy2; } } // namespace ReverbDecayEstimator::ReverbDecayEstimator(const EchoCanceller3Config& config) : filter_length_blocks_(config.filter.refined.length_blocks), filter_length_coefficients_(GetTimeDomainLength(filter_length_blocks_)), use_adaptive_echo_decay_(config.ep_strength.default_len < 0.f), early_reverb_estimator_(config.filter.refined.length_blocks - kEarlyReverbMinSizeBlocks), late_reverb_start_(kEarlyReverbMinSizeBlocks), late_reverb_end_(kEarlyReverbMinSizeBlocks), previous_gains_(config.filter.refined.length_blocks, 0.f), decay_(std::fabs(config.ep_strength.default_len)) { RTC_DCHECK_GT(config.filter.refined.length_blocks, static_cast(kEarlyReverbMinSizeBlocks)); } ReverbDecayEstimator::~ReverbDecayEstimator() = default; void ReverbDecayEstimator::Update(rtc::ArrayView filter, const absl::optional& filter_quality, int filter_delay_blocks, bool usable_linear_filter, bool stationary_signal) { const int filter_size = static_cast(filter.size()); if (stationary_signal) { return; } bool estimation_feasible = filter_delay_blocks <= filter_length_blocks_ - kEarlyReverbMinSizeBlocks - 1; estimation_feasible = estimation_feasible && filter_size == filter_length_coefficients_; estimation_feasible = estimation_feasible && filter_delay_blocks > 0; estimation_feasible = estimation_feasible && usable_linear_filter; if (!estimation_feasible) { ResetDecayEstimation(); return; } if (!use_adaptive_echo_decay_) { return; } const float new_smoothing = filter_quality ? *filter_quality * 0.2f : 0.f; smoothing_constant_ = std::max(new_smoothing, smoothing_constant_); if (smoothing_constant_ == 0.f) { return; } if (block_to_analyze_ < filter_length_blocks_) { // Analyze the filter and accumulate data for reverb estimation. AnalyzeFilter(filter); ++block_to_analyze_; } else { // When the filter is fully analyzed, estimate the reverb decay and reset // the block_to_analyze_ counter. EstimateDecay(filter, filter_delay_blocks); } } void ReverbDecayEstimator::ResetDecayEstimation() { early_reverb_estimator_.Reset(); late_reverb_decay_estimator_.Reset(0); block_to_analyze_ = 0; estimation_region_candidate_size_ = 0; estimation_region_identified_ = false; smoothing_constant_ = 0.f; late_reverb_start_ = 0; late_reverb_end_ = 0; } void ReverbDecayEstimator::EstimateDecay(rtc::ArrayView filter, int peak_block) { auto& h = filter; RTC_DCHECK_EQ(0, h.size() % kFftLengthBy2); // Reset the block analysis counter. block_to_analyze_ = std::min(peak_block + kEarlyReverbMinSizeBlocks, filter_length_blocks_); // To estimate the reverb decay, the energy of the first filter section must // be substantially larger than the last. Also, the first filter section // energy must not deviate too much from the max peak. const float first_reverb_gain = BlockEnergyAverage(h, block_to_analyze_); const size_t h_size_blocks = h.size() >> kFftLengthBy2Log2; tail_gain_ = BlockEnergyAverage(h, h_size_blocks - 1); float peak_energy = BlockEnergyPeak(h, peak_block); const bool sufficient_reverb_decay = first_reverb_gain > 4.f * tail_gain_; const bool valid_filter = first_reverb_gain > 2.f * tail_gain_ && peak_energy < 100.f; // Estimate the size of the regions with early and late reflections. const int size_early_reverb = early_reverb_estimator_.Estimate(); const int size_late_reverb = std::max(estimation_region_candidate_size_ - size_early_reverb, 0); // Only update the reverb decay estimate if the size of the identified late // reverb is sufficiently large. if (size_late_reverb >= 5) { if (valid_filter && late_reverb_decay_estimator_.EstimateAvailable()) { float decay = std::pow( 2.0f, late_reverb_decay_estimator_.Estimate() * kFftLengthBy2); constexpr float kMaxDecay = 0.95f; // ~1 sec min RT60. constexpr float kMinDecay = 0.02f; // ~15 ms max RT60. decay = std::max(.97f * decay_, decay); decay = std::min(decay, kMaxDecay); decay = std::max(decay, kMinDecay); decay_ += smoothing_constant_ * (decay - decay_); } // Update length of decay. Must have enough data (number of sections) in // order to estimate decay rate. late_reverb_decay_estimator_.Reset(size_late_reverb * kFftLengthBy2); late_reverb_start_ = peak_block + kEarlyReverbMinSizeBlocks + size_early_reverb; late_reverb_end_ = block_to_analyze_ + estimation_region_candidate_size_ - 1; } else { late_reverb_decay_estimator_.Reset(0); late_reverb_start_ = 0; late_reverb_end_ = 0; } // Reset variables for the identification of the region for reverb decay // estimation. estimation_region_identified_ = !(valid_filter && sufficient_reverb_decay); estimation_region_candidate_size_ = 0; // Stop estimation of the decay until another good filter is received. smoothing_constant_ = 0.f; // Reset early reflections detector. early_reverb_estimator_.Reset(); } void ReverbDecayEstimator::AnalyzeFilter(rtc::ArrayView filter) { auto h = rtc::ArrayView( filter.begin() + block_to_analyze_ * kFftLengthBy2, kFftLengthBy2); // Compute squared filter coeffiecients for the block to analyze_; std::array h2; std::transform(h.begin(), h.end(), h2.begin(), [](float a) { return a * a; }); // Map out the region for estimating the reverb decay. bool adapting; bool above_noise_floor; AnalyzeBlockGain(h2, tail_gain_, &previous_gains_[block_to_analyze_], &adapting, &above_noise_floor); // Count consecutive number of "good" filter sections, where "good" means: // 1) energy is above noise floor. // 2) energy of current section has not changed too much from last check. estimation_region_identified_ = estimation_region_identified_ || adapting || !above_noise_floor; if (!estimation_region_identified_) { ++estimation_region_candidate_size_; } // Accumulate data for reverb decay estimation and for the estimation of early // reflections. if (block_to_analyze_ <= late_reverb_end_) { if (block_to_analyze_ >= late_reverb_start_) { for (float h2_k : h2) { float h2_log2 = FastApproxLog2f(h2_k + 1e-10); late_reverb_decay_estimator_.Accumulate(h2_log2); early_reverb_estimator_.Accumulate(h2_log2, smoothing_constant_); } } else { for (float h2_k : h2) { float h2_log2 = FastApproxLog2f(h2_k + 1e-10); early_reverb_estimator_.Accumulate(h2_log2, smoothing_constant_); } } } } void ReverbDecayEstimator::Dump(ApmDataDumper* data_dumper) const { data_dumper->DumpRaw("aec3_reverb_decay", decay_); data_dumper->DumpRaw("aec3_reverb_tail_energy", tail_gain_); data_dumper->DumpRaw("aec3_reverb_alpha", smoothing_constant_); data_dumper->DumpRaw("aec3_num_reverb_decay_blocks", late_reverb_end_ - late_reverb_start_); data_dumper->DumpRaw("aec3_late_reverb_start", late_reverb_start_); data_dumper->DumpRaw("aec3_late_reverb_end", late_reverb_end_); early_reverb_estimator_.Dump(data_dumper); } void ReverbDecayEstimator::LateReverbLinearRegressor::Reset( int num_data_points) { RTC_DCHECK_LE(0, num_data_points); RTC_DCHECK_EQ(0, num_data_points % 2); const int N = num_data_points; nz_ = 0.f; // Arithmetic sum of $2 \sum_{i=0.5}^{(N-1)/2}i^2$ calculated directly. nn_ = SymmetricArithmetricSum(N); // The linear regression approach assumes symmetric index around 0. count_ = N > 0 ? -N * 0.5f + 0.5f : 0.f; N_ = N; n_ = 0; } void ReverbDecayEstimator::LateReverbLinearRegressor::Accumulate(float z) { nz_ += count_ * z; ++count_; ++n_; } float ReverbDecayEstimator::LateReverbLinearRegressor::Estimate() { RTC_DCHECK(EstimateAvailable()); if (nn_ == 0.f) { RTC_NOTREACHED(); return 0.f; } return nz_ / nn_; } ReverbDecayEstimator::EarlyReverbLengthEstimator::EarlyReverbLengthEstimator( int max_blocks) : numerators_smooth_(max_blocks - kBlocksPerSection, 0.f), numerators_(numerators_smooth_.size(), 0.f), coefficients_counter_(0) { RTC_DCHECK_LE(0, max_blocks); } ReverbDecayEstimator::EarlyReverbLengthEstimator:: ~EarlyReverbLengthEstimator() = default; void ReverbDecayEstimator::EarlyReverbLengthEstimator::Reset() { coefficients_counter_ = 0; std::fill(numerators_.begin(), numerators_.end(), 0.f); block_counter_ = 0; } void ReverbDecayEstimator::EarlyReverbLengthEstimator::Accumulate( float value, float smoothing) { // Each section is composed by kBlocksPerSection blocks and each section // overlaps with the next one in (kBlocksPerSection - 1) blocks. For example, // the first section covers the blocks [0:5], the second covers the blocks // [1:6] and so on. As a result, for each value, kBlocksPerSection sections // need to be updated. int first_section_index = std::max(block_counter_ - kBlocksPerSection + 1, 0); int last_section_index = std::min(block_counter_, static_cast(numerators_.size() - 1)); float x_value = static_cast(coefficients_counter_) + kEarlyReverbFirstPointAtLinearRegressors; const float value_to_inc = kFftLengthBy2 * value; float value_to_add = x_value * value + (block_counter_ - last_section_index) * value_to_inc; for (int section = last_section_index; section >= first_section_index; --section, value_to_add += value_to_inc) { numerators_[section] += value_to_add; } // Check if this update was the last coefficient of the current block. In that // case, check if we are at the end of one of the sections and update the // numerator of the linear regressor that is computed in such section. if (++coefficients_counter_ == kFftLengthBy2) { if (block_counter_ >= (kBlocksPerSection - 1)) { size_t section = block_counter_ - (kBlocksPerSection - 1); RTC_DCHECK_GT(numerators_.size(), section); RTC_DCHECK_GT(numerators_smooth_.size(), section); numerators_smooth_[section] += smoothing * (numerators_[section] - numerators_smooth_[section]); n_sections_ = section + 1; } ++block_counter_; coefficients_counter_ = 0; } } // Estimates the size in blocks of the early reverb. The estimation is done by // comparing the tilt that is estimated in each section. As an optimization // detail and due to the fact that all the linear regressors that are computed // shared the same denominator, the comparison of the tilts is done by a // comparison of the numerator of the linear regressors. int ReverbDecayEstimator::EarlyReverbLengthEstimator::Estimate() { constexpr float N = kBlocksPerSection * kFftLengthBy2; constexpr float nn = SymmetricArithmetricSum(N); // numerator_11 refers to the quantity that the linear regressor needs in the // numerator for getting a decay equal to 1.1 (which is not a decay). // log2(1.1) * nn / kFftLengthBy2. constexpr float numerator_11 = 0.13750352374993502f * nn / kFftLengthBy2; // log2(0.8) * nn / kFftLengthBy2. constexpr float numerator_08 = -0.32192809488736229f * nn / kFftLengthBy2; constexpr int kNumSectionsToAnalyze = 9; if (n_sections_ < kNumSectionsToAnalyze) { return 0; } // Estimation of the blocks that correspond to early reverberations. The // estimation is done by analyzing the impulse response. The portions of the // impulse response whose energy is not decreasing over its coefficients are // considered to be part of the early reverberations. Furthermore, the blocks // where the energy is decreasing faster than what it does at the end of the // impulse response are also considered to be part of the early // reverberations. The estimation is limited to the first // kNumSectionsToAnalyze sections. RTC_DCHECK_LE(n_sections_, numerators_smooth_.size()); const float min_numerator_tail = *std::min_element(numerators_smooth_.begin() + kNumSectionsToAnalyze, numerators_smooth_.begin() + n_sections_); int early_reverb_size_minus_1 = 0; for (int k = 0; k < kNumSectionsToAnalyze; ++k) { if ((numerators_smooth_[k] > numerator_11) || (numerators_smooth_[k] < numerator_08 && numerators_smooth_[k] < 0.9f * min_numerator_tail)) { early_reverb_size_minus_1 = k; } } return early_reverb_size_minus_1 == 0 ? 0 : early_reverb_size_minus_1 + 1; } void ReverbDecayEstimator::EarlyReverbLengthEstimator::Dump( ApmDataDumper* data_dumper) const { data_dumper->DumpRaw("aec3_er_acum_numerator", numerators_smooth_); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/reverb_decay_estimator.h0000664000175000017500000000705214475643423030672 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_REVERB_DECAY_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_AEC3_REVERB_DECAY_ESTIMATOR_H_ #include #include #include "absl/types/optional.h" #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" // kMaxAdaptiveFilter... namespace webrtc { class ApmDataDumper; struct EchoCanceller3Config; // Class for estimating the decay of the late reverb. class ReverbDecayEstimator { public: explicit ReverbDecayEstimator(const EchoCanceller3Config& config); ~ReverbDecayEstimator(); // Updates the decay estimate. void Update(rtc::ArrayView filter, const absl::optional& filter_quality, int filter_delay_blocks, bool usable_linear_filter, bool stationary_signal); // Returns the decay for the exponential model. float Decay() const { return decay_; } // Dumps debug data. void Dump(ApmDataDumper* data_dumper) const; private: void EstimateDecay(rtc::ArrayView filter, int peak_block); void AnalyzeFilter(rtc::ArrayView filter); void ResetDecayEstimation(); // Class for estimating the decay of the late reverb from the linear filter. class LateReverbLinearRegressor { public: // Resets the estimator to receive a specified number of data points. void Reset(int num_data_points); // Accumulates estimation data. void Accumulate(float z); // Estimates the decay. float Estimate(); // Returns whether an estimate is available. bool EstimateAvailable() const { return n_ == N_ && N_ != 0; } public: float nz_ = 0.f; float nn_ = 0.f; float count_ = 0.f; int N_ = 0; int n_ = 0; }; // Class for identifying the length of the early reverb from the linear // filter. For identifying the early reverberations, the impulse response is // divided in sections and the tilt of each section is computed by a linear // regressor. class EarlyReverbLengthEstimator { public: explicit EarlyReverbLengthEstimator(int max_blocks); ~EarlyReverbLengthEstimator(); // Resets the estimator. void Reset(); // Accumulates estimation data. void Accumulate(float value, float smoothing); // Estimates the size in blocks of the early reverb. int Estimate(); // Dumps debug data. void Dump(ApmDataDumper* data_dumper) const; private: std::vector numerators_smooth_; std::vector numerators_; int coefficients_counter_; int block_counter_ = 0; int n_sections_ = 0; }; const int filter_length_blocks_; const int filter_length_coefficients_; const bool use_adaptive_echo_decay_; LateReverbLinearRegressor late_reverb_decay_estimator_; EarlyReverbLengthEstimator early_reverb_estimator_; int late_reverb_start_; int late_reverb_end_; int block_to_analyze_ = 0; int estimation_region_candidate_size_ = 0; bool estimation_region_identified_ = false; std::vector previous_gains_; float decay_; float tail_gain_ = 0.f; float smoothing_constant_ = 0.f; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_REVERB_DECAY_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/reverb_frequency_response.cc0000664000175000017500000000602614475643423031573 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/reverb_frequency_response.h" #include #include #include #include #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "rtc_base/checks.h" namespace webrtc { namespace { // Computes the ratio of the energies between the direct path and the tail. The // energy is computed in the power spectrum domain discarding the DC // contributions. float AverageDecayWithinFilter( rtc::ArrayView freq_resp_direct_path, rtc::ArrayView freq_resp_tail) { // Skipping the DC for the ratio computation constexpr size_t kSkipBins = 1; RTC_CHECK_EQ(freq_resp_direct_path.size(), freq_resp_tail.size()); float direct_path_energy = std::accumulate(freq_resp_direct_path.begin() + kSkipBins, freq_resp_direct_path.end(), 0.f); if (direct_path_energy == 0.f) { return 0.f; } float tail_energy = std::accumulate(freq_resp_tail.begin() + kSkipBins, freq_resp_tail.end(), 0.f); return tail_energy / direct_path_energy; } } // namespace ReverbFrequencyResponse::ReverbFrequencyResponse() { tail_response_.fill(0.f); } ReverbFrequencyResponse::~ReverbFrequencyResponse() = default; void ReverbFrequencyResponse::Update( const std::vector>& frequency_response, int filter_delay_blocks, const absl::optional& linear_filter_quality, bool stationary_block) { if (stationary_block || !linear_filter_quality) { return; } Update(frequency_response, filter_delay_blocks, *linear_filter_quality); } void ReverbFrequencyResponse::Update( const std::vector>& frequency_response, int filter_delay_blocks, float linear_filter_quality) { rtc::ArrayView freq_resp_tail( frequency_response[frequency_response.size() - 1]); rtc::ArrayView freq_resp_direct_path( frequency_response[filter_delay_blocks]); float average_decay = AverageDecayWithinFilter(freq_resp_direct_path, freq_resp_tail); const float smoothing = 0.2f * linear_filter_quality; average_decay_ += smoothing * (average_decay - average_decay_); for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { tail_response_[k] = freq_resp_direct_path[k] * average_decay_; } for (size_t k = 1; k < kFftLengthBy2; ++k) { const float avg_neighbour = 0.5f * (tail_response_[k - 1] + tail_response_[k + 1]); tail_response_[k] = std::max(tail_response_[k], avg_neighbour); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/reverb_frequency_response.h0000664000175000017500000000333414475643423031434 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_REVERB_FREQUENCY_RESPONSE_H_ #define MODULES_AUDIO_PROCESSING_AEC3_REVERB_FREQUENCY_RESPONSE_H_ #include #include #include #include "absl/types/optional.h" #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" namespace webrtc { // Class for updating the frequency response for the reverb. class ReverbFrequencyResponse { public: ReverbFrequencyResponse(); ~ReverbFrequencyResponse(); // Updates the frequency response estimate of the reverb. void Update(const std::vector>& frequency_response, int filter_delay_blocks, const absl::optional& linear_filter_quality, bool stationary_block); // Returns the estimated frequency response for the reverb. rtc::ArrayView FrequencyResponse() const { return tail_response_; } private: void Update(const std::vector>& frequency_response, int filter_delay_blocks, float linear_filter_quality); float average_decay_ = 0.f; std::array tail_response_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_REVERB_FREQUENCY_RESPONSE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/reverb_model.cc0000664000175000017500000000305714475643423026755 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/reverb_model.h" #include #include #include #include "api/array_view.h" namespace webrtc { ReverbModel::ReverbModel() { Reset(); } ReverbModel::~ReverbModel() = default; void ReverbModel::Reset() { reverb_.fill(0.); } void ReverbModel::UpdateReverbNoFreqShaping( rtc::ArrayView power_spectrum, float power_spectrum_scaling, float reverb_decay) { if (reverb_decay > 0) { // Update the estimate of the reverberant power. for (size_t k = 0; k < power_spectrum.size(); ++k) { reverb_[k] = (reverb_[k] + power_spectrum[k] * power_spectrum_scaling) * reverb_decay; } } } void ReverbModel::UpdateReverb( rtc::ArrayView power_spectrum, rtc::ArrayView power_spectrum_scaling, float reverb_decay) { if (reverb_decay > 0) { // Update the estimate of the reverberant power. for (size_t k = 0; k < power_spectrum.size(); ++k) { reverb_[k] = (reverb_[k] + power_spectrum[k] * power_spectrum_scaling[k]) * reverb_decay; } } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/reverb_model.h0000664000175000017500000000367514475643423026625 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_H_ #define MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_H_ #include #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" namespace webrtc { // The ReverbModel class describes an exponential reverberant model // that can be applied over power spectrums. class ReverbModel { public: ReverbModel(); ~ReverbModel(); // Resets the state. void Reset(); // Returns the reverb. rtc::ArrayView reverb() const { return reverb_; } // The methods UpdateReverbNoFreqShaping and UpdateReverb update the // estimate of the reverberation contribution to an input/output power // spectrum. Before applying the exponential reverberant model, the input // power spectrum is pre-scaled. Use the method UpdateReverb when a different // scaling should be applied per frequency and UpdateReverb_no_freq_shape if // the same scaling should be used for all the frequencies. void UpdateReverbNoFreqShaping(rtc::ArrayView power_spectrum, float power_spectrum_scaling, float reverb_decay); // Update the reverb based on new data. void UpdateReverb(rtc::ArrayView power_spectrum, rtc::ArrayView power_spectrum_scaling, float reverb_decay); private: std::array reverb_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/reverb_model_estimator.cc0000664000175000017500000000423414475643423031042 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/reverb_model_estimator.h" namespace webrtc { ReverbModelEstimator::ReverbModelEstimator(const EchoCanceller3Config& config, size_t num_capture_channels) : reverb_decay_estimators_(num_capture_channels), reverb_frequency_responses_(num_capture_channels) { for (size_t ch = 0; ch < reverb_decay_estimators_.size(); ++ch) { reverb_decay_estimators_[ch] = std::make_unique(config); } } ReverbModelEstimator::~ReverbModelEstimator() = default; void ReverbModelEstimator::Update( rtc::ArrayView> impulse_responses, rtc::ArrayView>> frequency_responses, rtc::ArrayView> linear_filter_qualities, rtc::ArrayView filter_delays_blocks, const std::vector& usable_linear_estimates, bool stationary_block) { const size_t num_capture_channels = reverb_decay_estimators_.size(); RTC_DCHECK_EQ(num_capture_channels, impulse_responses.size()); RTC_DCHECK_EQ(num_capture_channels, frequency_responses.size()); RTC_DCHECK_EQ(num_capture_channels, usable_linear_estimates.size()); for (size_t ch = 0; ch < num_capture_channels; ++ch) { // Estimate the frequency response for the reverb. reverb_frequency_responses_[ch].Update( frequency_responses[ch], filter_delays_blocks[ch], linear_filter_qualities[ch], stationary_block); // Estimate the reverb decay, reverb_decay_estimators_[ch]->Update( impulse_responses[ch], linear_filter_qualities[ch], filter_delays_blocks[ch], usable_linear_estimates[ch], stationary_block); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/reverb_model_estimator.h0000664000175000017500000000466514475643423030714 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_ESTIMATOR_H_ #include #include #include "absl/types/optional.h" #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" // kFftLengthBy2Plus1 #include "modules/audio_processing/aec3/reverb_decay_estimator.h" #include "modules/audio_processing/aec3/reverb_frequency_response.h" namespace webrtc { class ApmDataDumper; // Class for estimating the model parameters for the reverberant echo. class ReverbModelEstimator { public: ReverbModelEstimator(const EchoCanceller3Config& config, size_t num_capture_channels); ~ReverbModelEstimator(); // Updates the estimates based on new data. void Update( rtc::ArrayView> impulse_responses, rtc::ArrayView>> frequency_responses, rtc::ArrayView> linear_filter_qualities, rtc::ArrayView filter_delays_blocks, const std::vector& usable_linear_estimates, bool stationary_block); // Returns the exponential decay of the reverberant echo. // TODO(peah): Correct to properly support multiple channels. float ReverbDecay() const { return reverb_decay_estimators_[0]->Decay(); } // Return the frequency response of the reverberant echo. // TODO(peah): Correct to properly support multiple channels. rtc::ArrayView GetReverbFrequencyResponse() const { return reverb_frequency_responses_[0].FrequencyResponse(); } // Dumps debug data. void Dump(ApmDataDumper* data_dumper) const { reverb_decay_estimators_[0]->Dump(data_dumper); } private: std::vector> reverb_decay_estimators_; std::vector reverb_frequency_responses_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/signal_dependent_erle_estimator.cc0000664000175000017500000004301214475643423032704 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/signal_dependent_erle_estimator.h" #include #include #include #include "modules/audio_processing/aec3/spectrum_buffer.h" #include "rtc_base/numerics/safe_minmax.h" namespace webrtc { namespace { constexpr std::array kBandBoundaries = {1, 8, 16, 24, 32, 48, kFftLengthBy2Plus1}; std::array FormSubbandMap() { std::array map_band_to_subband; size_t subband = 1; for (size_t k = 0; k < map_band_to_subband.size(); ++k) { RTC_DCHECK_LT(subband, kBandBoundaries.size()); if (k >= kBandBoundaries[subband]) { subband++; RTC_DCHECK_LT(k, kBandBoundaries[subband]); } map_band_to_subband[k] = subband - 1; } return map_band_to_subband; } // Defines the size in blocks of the sections that are used for dividing the // linear filter. The sections are split in a non-linear manner so that lower // sections that typically represent the direct path have a larger resolution // than the higher sections which typically represent more reverberant acoustic // paths. std::vector DefineFilterSectionSizes(size_t delay_headroom_blocks, size_t num_blocks, size_t num_sections) { size_t filter_length_blocks = num_blocks - delay_headroom_blocks; std::vector section_sizes(num_sections); size_t remaining_blocks = filter_length_blocks; size_t remaining_sections = num_sections; size_t estimator_size = 2; size_t idx = 0; while (remaining_sections > 1 && remaining_blocks > estimator_size * remaining_sections) { RTC_DCHECK_LT(idx, section_sizes.size()); section_sizes[idx] = estimator_size; remaining_blocks -= estimator_size; remaining_sections--; estimator_size *= 2; idx++; } size_t last_groups_size = remaining_blocks / remaining_sections; for (; idx < num_sections; idx++) { section_sizes[idx] = last_groups_size; } section_sizes[num_sections - 1] += remaining_blocks - last_groups_size * remaining_sections; return section_sizes; } // Forms the limits in blocks for each filter section. Those sections // are used for analyzing the echo estimates and investigating which // linear filter sections contribute most to the echo estimate energy. std::vector SetSectionsBoundaries(size_t delay_headroom_blocks, size_t num_blocks, size_t num_sections) { std::vector estimator_boundaries_blocks(num_sections + 1); if (estimator_boundaries_blocks.size() == 2) { estimator_boundaries_blocks[0] = 0; estimator_boundaries_blocks[1] = num_blocks; return estimator_boundaries_blocks; } RTC_DCHECK_GT(estimator_boundaries_blocks.size(), 2); const std::vector section_sizes = DefineFilterSectionSizes(delay_headroom_blocks, num_blocks, estimator_boundaries_blocks.size() - 1); size_t idx = 0; size_t current_size_block = 0; RTC_DCHECK_EQ(section_sizes.size() + 1, estimator_boundaries_blocks.size()); estimator_boundaries_blocks[0] = delay_headroom_blocks; for (size_t k = delay_headroom_blocks; k < num_blocks; ++k) { current_size_block++; if (current_size_block >= section_sizes[idx]) { idx = idx + 1; if (idx == section_sizes.size()) { break; } estimator_boundaries_blocks[idx] = k + 1; current_size_block = 0; } } estimator_boundaries_blocks[section_sizes.size()] = num_blocks; return estimator_boundaries_blocks; } std::array SetMaxErleSubbands(float max_erle_l, float max_erle_h, size_t limit_subband_l) { std::array max_erle; std::fill(max_erle.begin(), max_erle.begin() + limit_subband_l, max_erle_l); std::fill(max_erle.begin() + limit_subband_l, max_erle.end(), max_erle_h); return max_erle; } } // namespace SignalDependentErleEstimator::SignalDependentErleEstimator( const EchoCanceller3Config& config, size_t num_capture_channels) : min_erle_(config.erle.min), num_sections_(config.erle.num_sections), num_blocks_(config.filter.refined.length_blocks), delay_headroom_blocks_(config.delay.delay_headroom_samples / kBlockSize), band_to_subband_(FormSubbandMap()), max_erle_(SetMaxErleSubbands(config.erle.max_l, config.erle.max_h, band_to_subband_[kFftLengthBy2 / 2])), section_boundaries_blocks_(SetSectionsBoundaries(delay_headroom_blocks_, num_blocks_, num_sections_)), erle_(num_capture_channels), S2_section_accum_( num_capture_channels, std::vector>(num_sections_)), erle_estimators_( num_capture_channels, std::vector>(num_sections_)), erle_ref_(num_capture_channels), correction_factors_( num_capture_channels, std::vector>(num_sections_)), num_updates_(num_capture_channels), n_active_sections_(num_capture_channels) { RTC_DCHECK_LE(num_sections_, num_blocks_); RTC_DCHECK_GE(num_sections_, 1); Reset(); } SignalDependentErleEstimator::~SignalDependentErleEstimator() = default; void SignalDependentErleEstimator::Reset() { for (size_t ch = 0; ch < erle_.size(); ++ch) { erle_[ch].fill(min_erle_); for (auto& erle_estimator : erle_estimators_[ch]) { erle_estimator.fill(min_erle_); } erle_ref_[ch].fill(min_erle_); for (auto& factor : correction_factors_[ch]) { factor.fill(1.0f); } num_updates_[ch].fill(0); n_active_sections_[ch].fill(0); } } // Updates the Erle estimate by analyzing the current input signals. It takes // the render buffer and the filter frequency response in order to do an // estimation of the number of sections of the linear filter that are needed // for getting the majority of the energy in the echo estimate. Based on that // number of sections, it updates the erle estimation by introducing a // correction factor to the erle that is given as an input to this method. void SignalDependentErleEstimator::Update( const RenderBuffer& render_buffer, rtc::ArrayView>> filter_frequency_responses, rtc::ArrayView X2, rtc::ArrayView> Y2, rtc::ArrayView> E2, rtc::ArrayView> average_erle, const std::vector& converged_filters) { RTC_DCHECK_GT(num_sections_, 1); // Gets the number of filter sections that are needed for achieving 90 % // of the power spectrum energy of the echo estimate. ComputeNumberOfActiveFilterSections(render_buffer, filter_frequency_responses); // Updates the correction factors that is used for correcting the erle and // adapt it to the particular characteristics of the input signal. UpdateCorrectionFactors(X2, Y2, E2, converged_filters); // Applies the correction factor to the input erle for getting a more refined // erle estimation for the current input signal. for (size_t ch = 0; ch < erle_.size(); ++ch) { for (size_t k = 0; k < kFftLengthBy2; ++k) { RTC_DCHECK_GT(correction_factors_[ch].size(), n_active_sections_[ch][k]); float correction_factor = correction_factors_[ch][n_active_sections_[ch][k]] [band_to_subband_[k]]; erle_[ch][k] = rtc::SafeClamp(average_erle[ch][k] * correction_factor, min_erle_, max_erle_[band_to_subband_[k]]); } } } void SignalDependentErleEstimator::Dump( const std::unique_ptr& data_dumper) const { for (auto& erle : erle_estimators_[0]) { data_dumper->DumpRaw("aec3_all_erle", erle); } data_dumper->DumpRaw("aec3_ref_erle", erle_ref_[0]); for (auto& factor : correction_factors_[0]) { data_dumper->DumpRaw("aec3_erle_correction_factor", factor); } } // Estimates for each band the smallest number of sections in the filter that // together constitute 90% of the estimated echo energy. void SignalDependentErleEstimator::ComputeNumberOfActiveFilterSections( const RenderBuffer& render_buffer, rtc::ArrayView>> filter_frequency_responses) { RTC_DCHECK_GT(num_sections_, 1); // Computes an approximation of the power spectrum if the filter would have // been limited to a certain number of filter sections. ComputeEchoEstimatePerFilterSection(render_buffer, filter_frequency_responses); // For each band, computes the number of filter sections that are needed for // achieving the 90 % energy in the echo estimate. ComputeActiveFilterSections(); } void SignalDependentErleEstimator::UpdateCorrectionFactors( rtc::ArrayView X2, rtc::ArrayView> Y2, rtc::ArrayView> E2, const std::vector& converged_filters) { for (size_t ch = 0; ch < converged_filters.size(); ++ch) { if (converged_filters[ch]) { constexpr float kX2BandEnergyThreshold = 44015068.0f; constexpr float kSmthConstantDecreases = 0.1f; constexpr float kSmthConstantIncreases = kSmthConstantDecreases / 2.f; auto subband_powers = [](rtc::ArrayView power_spectrum, rtc::ArrayView power_spectrum_subbands) { for (size_t subband = 0; subband < kSubbands; ++subband) { RTC_DCHECK_LE(kBandBoundaries[subband + 1], power_spectrum.size()); power_spectrum_subbands[subband] = std::accumulate( power_spectrum.begin() + kBandBoundaries[subband], power_spectrum.begin() + kBandBoundaries[subband + 1], 0.f); } }; std::array X2_subbands, E2_subbands, Y2_subbands; subband_powers(X2, X2_subbands); subband_powers(E2[ch], E2_subbands); subband_powers(Y2[ch], Y2_subbands); std::array idx_subbands; for (size_t subband = 0; subband < kSubbands; ++subband) { // When aggregating the number of active sections in the filter for // different bands we choose to take the minimum of all of them. As an // example, if for one of the bands it is the direct path its refined // contributor to the final echo estimate, we consider the direct path // is as well the refined contributor for the subband that contains that // particular band. That aggregate number of sections will be later used // as the identifier of the erle estimator that needs to be updated. RTC_DCHECK_LE(kBandBoundaries[subband + 1], n_active_sections_[ch].size()); idx_subbands[subband] = *std::min_element( n_active_sections_[ch].begin() + kBandBoundaries[subband], n_active_sections_[ch].begin() + kBandBoundaries[subband + 1]); } std::array new_erle; std::array is_erle_updated; is_erle_updated.fill(false); new_erle.fill(0.f); for (size_t subband = 0; subband < kSubbands; ++subband) { if (X2_subbands[subband] > kX2BandEnergyThreshold && E2_subbands[subband] > 0) { new_erle[subband] = Y2_subbands[subband] / E2_subbands[subband]; RTC_DCHECK_GT(new_erle[subband], 0); is_erle_updated[subband] = true; ++num_updates_[ch][subband]; } } for (size_t subband = 0; subband < kSubbands; ++subband) { const size_t idx = idx_subbands[subband]; RTC_DCHECK_LT(idx, erle_estimators_[ch].size()); float alpha = new_erle[subband] > erle_estimators_[ch][idx][subband] ? kSmthConstantIncreases : kSmthConstantDecreases; alpha = static_cast(is_erle_updated[subband]) * alpha; erle_estimators_[ch][idx][subband] += alpha * (new_erle[subband] - erle_estimators_[ch][idx][subband]); erle_estimators_[ch][idx][subband] = rtc::SafeClamp( erle_estimators_[ch][idx][subband], min_erle_, max_erle_[subband]); } for (size_t subband = 0; subband < kSubbands; ++subband) { float alpha = new_erle[subband] > erle_ref_[ch][subband] ? kSmthConstantIncreases : kSmthConstantDecreases; alpha = static_cast(is_erle_updated[subband]) * alpha; erle_ref_[ch][subband] += alpha * (new_erle[subband] - erle_ref_[ch][subband]); erle_ref_[ch][subband] = rtc::SafeClamp(erle_ref_[ch][subband], min_erle_, max_erle_[subband]); } for (size_t subband = 0; subband < kSubbands; ++subband) { constexpr int kNumUpdateThr = 50; if (is_erle_updated[subband] && num_updates_[ch][subband] > kNumUpdateThr) { const size_t idx = idx_subbands[subband]; RTC_DCHECK_GT(erle_ref_[ch][subband], 0.f); // Computes the ratio between the erle that is updated using all the // points and the erle that is updated only on signals that share the // same number of active filter sections. float new_correction_factor = erle_estimators_[ch][idx][subband] / erle_ref_[ch][subband]; correction_factors_[ch][idx][subband] += 0.1f * (new_correction_factor - correction_factors_[ch][idx][subband]); } } } } } void SignalDependentErleEstimator::ComputeEchoEstimatePerFilterSection( const RenderBuffer& render_buffer, rtc::ArrayView>> filter_frequency_responses) { const SpectrumBuffer& spectrum_render_buffer = render_buffer.GetSpectrumBuffer(); const size_t num_render_channels = spectrum_render_buffer.buffer[0].size(); const size_t num_capture_channels = S2_section_accum_.size(); const float one_by_num_render_channels = 1.f / num_render_channels; RTC_DCHECK_EQ(S2_section_accum_.size(), filter_frequency_responses.size()); for (size_t capture_ch = 0; capture_ch < num_capture_channels; ++capture_ch) { RTC_DCHECK_EQ(S2_section_accum_[capture_ch].size() + 1, section_boundaries_blocks_.size()); size_t idx_render = render_buffer.Position(); idx_render = spectrum_render_buffer.OffsetIndex( idx_render, section_boundaries_blocks_[0]); for (size_t section = 0; section < num_sections_; ++section) { std::array X2_section; std::array H2_section; X2_section.fill(0.f); H2_section.fill(0.f); const size_t block_limit = std::min(section_boundaries_blocks_[section + 1], filter_frequency_responses[capture_ch].size()); for (size_t block = section_boundaries_blocks_[section]; block < block_limit; ++block) { for (size_t render_ch = 0; render_ch < spectrum_render_buffer.buffer[idx_render].size(); ++render_ch) { for (size_t k = 0; k < X2_section.size(); ++k) { X2_section[k] += spectrum_render_buffer.buffer[idx_render][render_ch][k] * one_by_num_render_channels; } } std::transform(H2_section.begin(), H2_section.end(), filter_frequency_responses[capture_ch][block].begin(), H2_section.begin(), std::plus()); idx_render = spectrum_render_buffer.IncIndex(idx_render); } std::transform(X2_section.begin(), X2_section.end(), H2_section.begin(), S2_section_accum_[capture_ch][section].begin(), std::multiplies()); } for (size_t section = 1; section < num_sections_; ++section) { std::transform(S2_section_accum_[capture_ch][section - 1].begin(), S2_section_accum_[capture_ch][section - 1].end(), S2_section_accum_[capture_ch][section].begin(), S2_section_accum_[capture_ch][section].begin(), std::plus()); } } } void SignalDependentErleEstimator::ComputeActiveFilterSections() { for (size_t ch = 0; ch < n_active_sections_.size(); ++ch) { std::fill(n_active_sections_[ch].begin(), n_active_sections_[ch].end(), 0); for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { size_t section = num_sections_; float target = 0.9f * S2_section_accum_[ch][num_sections_ - 1][k]; while (section > 0 && S2_section_accum_[ch][section - 1][k] >= target) { n_active_sections_[ch][k] = --section; } } } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/signal_dependent_erle_estimator.h0000664000175000017500000000761314475643423032555 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_SIGNAL_DEPENDENT_ERLE_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_AEC3_SIGNAL_DEPENDENT_ERLE_ESTIMATOR_H_ #include #include #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/render_buffer.h" #include "modules/audio_processing/logging/apm_data_dumper.h" namespace webrtc { // This class estimates the dependency of the Erle to the input signal. By // looking at the input signal, an estimation on whether the current echo // estimate is due to the direct path or to a more reverberant one is performed. // Once that estimation is done, it is possible to refine the average Erle that // this class receive as an input. class SignalDependentErleEstimator { public: SignalDependentErleEstimator(const EchoCanceller3Config& config, size_t num_capture_channels); ~SignalDependentErleEstimator(); void Reset(); // Returns the Erle per frequency subband. rtc::ArrayView> Erle() const { return erle_; } // Updates the Erle estimate. The Erle that is passed as an input is required // to be an estimation of the average Erle achieved by the linear filter. void Update( const RenderBuffer& render_buffer, rtc::ArrayView>> filter_frequency_response, rtc::ArrayView X2, rtc::ArrayView> Y2, rtc::ArrayView> E2, rtc::ArrayView> average_erle, const std::vector& converged_filters); void Dump(const std::unique_ptr& data_dumper) const; static constexpr size_t kSubbands = 6; private: void ComputeNumberOfActiveFilterSections( const RenderBuffer& render_buffer, rtc::ArrayView>> filter_frequency_responses); void UpdateCorrectionFactors( rtc::ArrayView X2, rtc::ArrayView> Y2, rtc::ArrayView> E2, const std::vector& converged_filters); void ComputeEchoEstimatePerFilterSection( const RenderBuffer& render_buffer, rtc::ArrayView>> filter_frequency_responses); void ComputeActiveFilterSections(); const float min_erle_; const size_t num_sections_; const size_t num_blocks_; const size_t delay_headroom_blocks_; const std::array band_to_subband_; const std::array max_erle_; const std::vector section_boundaries_blocks_; std::vector> erle_; std::vector>> S2_section_accum_; std::vector>> erle_estimators_; std::vector> erle_ref_; std::vector>> correction_factors_; std::vector> num_updates_; std::vector> n_active_sections_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_SIGNAL_DEPENDENT_ERLE_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/spectrum_buffer.cc0000664000175000017500000000161014475643423027474 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/spectrum_buffer.h" #include namespace webrtc { SpectrumBuffer::SpectrumBuffer(size_t size, size_t num_channels) : size(static_cast(size)), buffer(size, std::vector>(num_channels)) { for (auto& channel : buffer) { for (auto& c : channel) { std::fill(c.begin(), c.end(), 0.f); } } } SpectrumBuffer::~SpectrumBuffer() = default; } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/spectrum_buffer.h0000664000175000017500000000372014475643423027342 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_SPECTRUM_BUFFER_H_ #define MODULES_AUDIO_PROCESSING_AEC3_SPECTRUM_BUFFER_H_ #include #include #include #include "modules/audio_processing/aec3/aec3_common.h" #include "rtc_base/checks.h" namespace webrtc { // Struct for bundling a circular buffer of one dimensional vector objects // together with the read and write indices. struct SpectrumBuffer { SpectrumBuffer(size_t size, size_t num_channels); ~SpectrumBuffer(); int IncIndex(int index) const { RTC_DCHECK_EQ(buffer.size(), static_cast(size)); return index < size - 1 ? index + 1 : 0; } int DecIndex(int index) const { RTC_DCHECK_EQ(buffer.size(), static_cast(size)); return index > 0 ? index - 1 : size - 1; } int OffsetIndex(int index, int offset) const { RTC_DCHECK_GE(size, offset); RTC_DCHECK_EQ(buffer.size(), static_cast(size)); RTC_DCHECK_GE(size + index + offset, 0); return (size + index + offset) % size; } void UpdateWriteIndex(int offset) { write = OffsetIndex(write, offset); } void IncWriteIndex() { write = IncIndex(write); } void DecWriteIndex() { write = DecIndex(write); } void UpdateReadIndex(int offset) { read = OffsetIndex(read, offset); } void IncReadIndex() { read = IncIndex(read); } void DecReadIndex() { read = DecIndex(read); } const int size; std::vector>> buffer; int write = 0; int read = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_SPECTRUM_BUFFER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/stationarity_estimator.cc0000664000175000017500000002050014475643423031121 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/stationarity_estimator.h" #include #include #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/spectrum_buffer.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/atomic_ops.h" namespace webrtc { namespace { constexpr float kMinNoisePower = 10.f; constexpr int kHangoverBlocks = kNumBlocksPerSecond / 20; constexpr int kNBlocksAverageInitPhase = 20; constexpr int kNBlocksInitialPhase = kNumBlocksPerSecond * 2.; } // namespace StationarityEstimator::StationarityEstimator() : data_dumper_( new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))) { Reset(); } StationarityEstimator::~StationarityEstimator() = default; void StationarityEstimator::Reset() { noise_.Reset(); hangovers_.fill(0); stationarity_flags_.fill(false); } // Update just the noise estimator. Usefull until the delay is known void StationarityEstimator::UpdateNoiseEstimator( rtc::ArrayView> spectrum) { noise_.Update(spectrum); data_dumper_->DumpRaw("aec3_stationarity_noise_spectrum", noise_.Spectrum()); data_dumper_->DumpRaw("aec3_stationarity_is_block_stationary", IsBlockStationary()); } void StationarityEstimator::UpdateStationarityFlags( const SpectrumBuffer& spectrum_buffer, rtc::ArrayView render_reverb_contribution_spectrum, int idx_current, int num_lookahead) { std::array indexes; int num_lookahead_bounded = std::min(num_lookahead, kWindowLength - 1); int idx = idx_current; if (num_lookahead_bounded < kWindowLength - 1) { int num_lookback = (kWindowLength - 1) - num_lookahead_bounded; idx = spectrum_buffer.OffsetIndex(idx_current, num_lookback); } // For estimating the stationarity properties of the current frame, the // power for each band is accumulated for several consecutive spectra in the // method EstimateBandStationarity. // In order to avoid getting the indexes of the spectra for every band with // its associated overhead, those indexes are stored in an array and then use // when the estimation is done. indexes[0] = idx; for (size_t k = 1; k < indexes.size(); ++k) { indexes[k] = spectrum_buffer.DecIndex(indexes[k - 1]); } RTC_DCHECK_EQ( spectrum_buffer.DecIndex(indexes[kWindowLength - 1]), spectrum_buffer.OffsetIndex(idx_current, -(num_lookahead_bounded + 1))); for (size_t k = 0; k < stationarity_flags_.size(); ++k) { stationarity_flags_[k] = EstimateBandStationarity( spectrum_buffer, render_reverb_contribution_spectrum, indexes, k); } UpdateHangover(); SmoothStationaryPerFreq(); } bool StationarityEstimator::IsBlockStationary() const { float acum_stationarity = 0.f; RTC_DCHECK_EQ(stationarity_flags_.size(), kFftLengthBy2Plus1); for (size_t band = 0; band < stationarity_flags_.size(); ++band) { bool st = IsBandStationary(band); acum_stationarity += static_cast(st); } return ((acum_stationarity * (1.f / kFftLengthBy2Plus1)) > 0.75f); } bool StationarityEstimator::EstimateBandStationarity( const SpectrumBuffer& spectrum_buffer, rtc::ArrayView average_reverb, const std::array& indexes, size_t band) const { constexpr float kThrStationarity = 10.f; float acum_power = 0.f; const int num_render_channels = static_cast(spectrum_buffer.buffer[0].size()); const float one_by_num_channels = 1.f / num_render_channels; for (auto idx : indexes) { for (int ch = 0; ch < num_render_channels; ++ch) { acum_power += spectrum_buffer.buffer[idx][ch][band] * one_by_num_channels; } } acum_power += average_reverb[band]; float noise = kWindowLength * GetStationarityPowerBand(band); RTC_CHECK_LT(0.f, noise); bool stationary = acum_power < kThrStationarity * noise; data_dumper_->DumpRaw("aec3_stationarity_long_ratio", acum_power / noise); return stationary; } bool StationarityEstimator::AreAllBandsStationary() { for (auto b : stationarity_flags_) { if (!b) return false; } return true; } void StationarityEstimator::UpdateHangover() { bool reduce_hangover = AreAllBandsStationary(); for (size_t k = 0; k < stationarity_flags_.size(); ++k) { if (!stationarity_flags_[k]) { hangovers_[k] = kHangoverBlocks; } else if (reduce_hangover) { hangovers_[k] = std::max(hangovers_[k] - 1, 0); } } } void StationarityEstimator::SmoothStationaryPerFreq() { std::array all_ahead_stationary_smooth; for (size_t k = 1; k < kFftLengthBy2Plus1 - 1; ++k) { all_ahead_stationary_smooth[k] = stationarity_flags_[k - 1] && stationarity_flags_[k] && stationarity_flags_[k + 1]; } all_ahead_stationary_smooth[0] = all_ahead_stationary_smooth[1]; all_ahead_stationary_smooth[kFftLengthBy2Plus1 - 1] = all_ahead_stationary_smooth[kFftLengthBy2Plus1 - 2]; stationarity_flags_ = all_ahead_stationary_smooth; } int StationarityEstimator::instance_count_ = 0; StationarityEstimator::NoiseSpectrum::NoiseSpectrum() { Reset(); } StationarityEstimator::NoiseSpectrum::~NoiseSpectrum() = default; void StationarityEstimator::NoiseSpectrum::Reset() { block_counter_ = 0; noise_spectrum_.fill(kMinNoisePower); } void StationarityEstimator::NoiseSpectrum::Update( rtc::ArrayView> spectrum) { RTC_DCHECK_LE(1, spectrum[0].size()); const int num_render_channels = static_cast(spectrum.size()); std::array avg_spectrum_data; rtc::ArrayView avg_spectrum; if (num_render_channels == 1) { avg_spectrum = spectrum[0]; } else { // For multiple channels, average the channel spectra before passing to the // noise spectrum estimator. avg_spectrum = avg_spectrum_data; std::copy(spectrum[0].begin(), spectrum[0].end(), avg_spectrum_data.begin()); for (int ch = 1; ch < num_render_channels; ++ch) { for (size_t k = 1; k < kFftLengthBy2Plus1; ++k) { avg_spectrum_data[k] += spectrum[ch][k]; } } const float one_by_num_channels = 1.f / num_render_channels; for (size_t k = 1; k < kFftLengthBy2Plus1; ++k) { avg_spectrum_data[k] *= one_by_num_channels; } } ++block_counter_; float alpha = GetAlpha(); for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { if (block_counter_ <= kNBlocksAverageInitPhase) { noise_spectrum_[k] += (1.f / kNBlocksAverageInitPhase) * avg_spectrum[k]; } else { noise_spectrum_[k] = UpdateBandBySmoothing(avg_spectrum[k], noise_spectrum_[k], alpha); } } } float StationarityEstimator::NoiseSpectrum::GetAlpha() const { constexpr float kAlpha = 0.004f; constexpr float kAlphaInit = 0.04f; constexpr float kTiltAlpha = (kAlphaInit - kAlpha) / kNBlocksInitialPhase; if (block_counter_ > (kNBlocksInitialPhase + kNBlocksAverageInitPhase)) { return kAlpha; } else { return kAlphaInit - kTiltAlpha * (block_counter_ - kNBlocksAverageInitPhase); } } float StationarityEstimator::NoiseSpectrum::UpdateBandBySmoothing( float power_band, float power_band_noise, float alpha) const { float power_band_noise_updated = power_band_noise; if (power_band_noise < power_band) { RTC_DCHECK_GT(power_band, 0.f); float alpha_inc = alpha * (power_band_noise / power_band); if (block_counter_ > kNBlocksInitialPhase) { if (10.f * power_band_noise < power_band) { alpha_inc *= 0.1f; } } power_band_noise_updated += alpha_inc * (power_band - power_band_noise); } else { power_band_noise_updated += alpha * (power_band - power_band_noise); power_band_noise_updated = std::max(power_band_noise_updated, kMinNoisePower); } return power_band_noise_updated; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/stationarity_estimator.h0000664000175000017500000001000414475643423030761 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_STATIONARITY_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_AEC3_STATIONARITY_ESTIMATOR_H_ #include #include #include #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" // kFftLengthBy2Plus1... #include "modules/audio_processing/aec3/reverb_model.h" #include "rtc_base/checks.h" namespace webrtc { class ApmDataDumper; struct SpectrumBuffer; class StationarityEstimator { public: StationarityEstimator(); ~StationarityEstimator(); // Reset the stationarity estimator. void Reset(); // Update just the noise estimator. Usefull until the delay is known void UpdateNoiseEstimator( rtc::ArrayView> spectrum); // Update the flag indicating whether this current frame is stationary. For // getting a more robust estimation, it looks at future and/or past frames. void UpdateStationarityFlags( const SpectrumBuffer& spectrum_buffer, rtc::ArrayView render_reverb_contribution_spectrum, int idx_current, int num_lookahead); // Returns true if the current band is stationary. bool IsBandStationary(size_t band) const { return stationarity_flags_[band] && (hangovers_[band] == 0); } // Returns true if the current block is estimated as stationary. bool IsBlockStationary() const; private: static constexpr int kWindowLength = 13; // Returns the power of the stationary noise spectrum at a band. float GetStationarityPowerBand(size_t k) const { return noise_.Power(k); } // Get an estimation of the stationarity for the current band by looking // at the past/present/future available data. bool EstimateBandStationarity(const SpectrumBuffer& spectrum_buffer, rtc::ArrayView average_reverb, const std::array& indexes, size_t band) const; // True if all bands at the current point are stationary. bool AreAllBandsStationary(); // Update the hangover depending on the stationary status of the current // frame. void UpdateHangover(); // Smooth the stationarity detection by looking at neighbouring frequency // bands. void SmoothStationaryPerFreq(); class NoiseSpectrum { public: NoiseSpectrum(); ~NoiseSpectrum(); // Reset the noise power spectrum estimate state. void Reset(); // Update the noise power spectrum with a new frame. void Update( rtc::ArrayView> spectrum); // Get the noise estimation power spectrum. rtc::ArrayView Spectrum() const { return noise_spectrum_; } // Get the noise power spectrum at a certain band. float Power(size_t band) const { RTC_DCHECK_LT(band, noise_spectrum_.size()); return noise_spectrum_[band]; } private: // Get the update coefficient to be used for the current frame. float GetAlpha() const; // Update the noise power spectrum at a certain band with a new frame. float UpdateBandBySmoothing(float power_band, float power_band_noise, float alpha) const; std::array noise_spectrum_; size_t block_counter_; }; static int instance_count_; std::unique_ptr data_dumper_; NoiseSpectrum noise_; std::array hangovers_; std::array stationarity_flags_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_STATIONARITY_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/subband_erle_estimator.cc0000664000175000017500000001646414475643423031032 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/subband_erle_estimator.h" #include #include #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_minmax.h" #include "system_wrappers/include/field_trial.h" namespace webrtc { namespace { constexpr float kX2BandEnergyThreshold = 44015068.0f; constexpr int kBlocksToHoldErle = 100; constexpr int kBlocksForOnsetDetection = kBlocksToHoldErle + 150; constexpr int kPointsToAccumulate = 6; std::array SetMaxErleBands(float max_erle_l, float max_erle_h) { std::array max_erle; std::fill(max_erle.begin(), max_erle.begin() + kFftLengthBy2 / 2, max_erle_l); std::fill(max_erle.begin() + kFftLengthBy2 / 2, max_erle.end(), max_erle_h); return max_erle; } bool EnableMinErleDuringOnsets() { return !field_trial::IsEnabled("WebRTC-Aec3MinErleDuringOnsetsKillSwitch"); } } // namespace SubbandErleEstimator::SubbandErleEstimator(const EchoCanceller3Config& config, size_t num_capture_channels) : use_onset_detection_(config.erle.onset_detection), min_erle_(config.erle.min), max_erle_(SetMaxErleBands(config.erle.max_l, config.erle.max_h)), use_min_erle_during_onsets_(EnableMinErleDuringOnsets()), accum_spectra_(num_capture_channels), erle_(num_capture_channels), erle_onsets_(num_capture_channels), coming_onset_(num_capture_channels), hold_counters_(num_capture_channels) { Reset(); } SubbandErleEstimator::~SubbandErleEstimator() = default; void SubbandErleEstimator::Reset() { for (auto& erle : erle_) { erle.fill(min_erle_); } for (size_t ch = 0; ch < erle_onsets_.size(); ++ch) { erle_onsets_[ch].fill(min_erle_); coming_onset_[ch].fill(true); hold_counters_[ch].fill(0); } ResetAccumulatedSpectra(); } void SubbandErleEstimator::Update( rtc::ArrayView X2, rtc::ArrayView> Y2, rtc::ArrayView> E2, const std::vector& converged_filters) { UpdateAccumulatedSpectra(X2, Y2, E2, converged_filters); UpdateBands(converged_filters); if (use_onset_detection_) { DecreaseErlePerBandForLowRenderSignals(); } for (auto& erle : erle_) { erle[0] = erle[1]; erle[kFftLengthBy2] = erle[kFftLengthBy2 - 1]; } } void SubbandErleEstimator::Dump( const std::unique_ptr& data_dumper) const { data_dumper->DumpRaw("aec3_erle_onset", ErleOnsets()[0]); } void SubbandErleEstimator::UpdateBands( const std::vector& converged_filters) { const int num_capture_channels = static_cast(accum_spectra_.Y2.size()); for (int ch = 0; ch < num_capture_channels; ++ch) { // Note that the use of the converged_filter flag already imposed // a minimum of the erle that can be estimated as that flag would // be false if the filter is performing poorly. if (!converged_filters[ch]) { continue; } std::array new_erle; std::array is_erle_updated; is_erle_updated.fill(false); for (size_t k = 1; k < kFftLengthBy2; ++k) { if (accum_spectra_.num_points[ch] == kPointsToAccumulate && accum_spectra_.E2[ch][k] > 0.f) { new_erle[k] = accum_spectra_.Y2[ch][k] / accum_spectra_.E2[ch][k]; is_erle_updated[k] = true; } } if (use_onset_detection_) { for (size_t k = 1; k < kFftLengthBy2; ++k) { if (is_erle_updated[k] && !accum_spectra_.low_render_energy[ch][k]) { if (coming_onset_[ch][k]) { coming_onset_[ch][k] = false; if (!use_min_erle_during_onsets_) { float alpha = new_erle[k] < erle_onsets_[ch][k] ? 0.3f : 0.15f; erle_onsets_[ch][k] = rtc::SafeClamp( erle_onsets_[ch][k] + alpha * (new_erle[k] - erle_onsets_[ch][k]), min_erle_, max_erle_[k]); } } hold_counters_[ch][k] = kBlocksForOnsetDetection; } } } for (size_t k = 1; k < kFftLengthBy2; ++k) { if (is_erle_updated[k]) { float alpha = 0.05f; if (new_erle[k] < erle_[ch][k]) { alpha = accum_spectra_.low_render_energy[ch][k] ? 0.f : 0.1f; } erle_[ch][k] = rtc::SafeClamp(erle_[ch][k] + alpha * (new_erle[k] - erle_[ch][k]), min_erle_, max_erle_[k]); } } } } void SubbandErleEstimator::DecreaseErlePerBandForLowRenderSignals() { const int num_capture_channels = static_cast(accum_spectra_.Y2.size()); for (int ch = 0; ch < num_capture_channels; ++ch) { for (size_t k = 1; k < kFftLengthBy2; ++k) { --hold_counters_[ch][k]; if (hold_counters_[ch][k] <= (kBlocksForOnsetDetection - kBlocksToHoldErle)) { if (erle_[ch][k] > erle_onsets_[ch][k]) { erle_[ch][k] = std::max(erle_onsets_[ch][k], 0.97f * erle_[ch][k]); RTC_DCHECK_LE(min_erle_, erle_[ch][k]); } if (hold_counters_[ch][k] <= 0) { coming_onset_[ch][k] = true; hold_counters_[ch][k] = 0; } } } } } void SubbandErleEstimator::ResetAccumulatedSpectra() { for (size_t ch = 0; ch < erle_onsets_.size(); ++ch) { accum_spectra_.Y2[ch].fill(0.f); accum_spectra_.E2[ch].fill(0.f); accum_spectra_.num_points[ch] = 0; accum_spectra_.low_render_energy[ch].fill(false); } } void SubbandErleEstimator::UpdateAccumulatedSpectra( rtc::ArrayView X2, rtc::ArrayView> Y2, rtc::ArrayView> E2, const std::vector& converged_filters) { auto& st = accum_spectra_; RTC_DCHECK_EQ(st.E2.size(), E2.size()); RTC_DCHECK_EQ(st.E2.size(), E2.size()); const int num_capture_channels = static_cast(Y2.size()); for (int ch = 0; ch < num_capture_channels; ++ch) { // Note that the use of the converged_filter flag already imposed // a minimum of the erle that can be estimated as that flag would // be false if the filter is performing poorly. if (!converged_filters[ch]) { continue; } if (st.num_points[ch] == kPointsToAccumulate) { st.num_points[ch] = 0; st.Y2[ch].fill(0.f); st.E2[ch].fill(0.f); st.low_render_energy[ch].fill(false); } std::transform(Y2[ch].begin(), Y2[ch].end(), st.Y2[ch].begin(), st.Y2[ch].begin(), std::plus()); std::transform(E2[ch].begin(), E2[ch].end(), st.E2[ch].begin(), st.E2[ch].begin(), std::plus()); for (size_t k = 0; k < X2.size(); ++k) { st.low_render_energy[ch][k] = st.low_render_energy[ch][k] || X2[k] < kX2BandEnergyThreshold; } ++st.num_points[ch]; } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/subband_erle_estimator.h0000664000175000017500000000636514475643423030673 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_SUBBAND_ERLE_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_AEC3_SUBBAND_ERLE_ESTIMATOR_H_ #include #include #include #include #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/logging/apm_data_dumper.h" namespace webrtc { // Estimates the echo return loss enhancement for each frequency subband. class SubbandErleEstimator { public: SubbandErleEstimator(const EchoCanceller3Config& config, size_t num_capture_channels); ~SubbandErleEstimator(); // Resets the ERLE estimator. void Reset(); // Updates the ERLE estimate. void Update(rtc::ArrayView X2, rtc::ArrayView> Y2, rtc::ArrayView> E2, const std::vector& converged_filters); // Returns the ERLE estimate. rtc::ArrayView> Erle() const { return erle_; } // Returns the ERLE estimate at onsets (only used for testing). rtc::ArrayView> ErleOnsets() const { return erle_onsets_; } void Dump(const std::unique_ptr& data_dumper) const; private: struct AccumulatedSpectra { explicit AccumulatedSpectra(size_t num_capture_channels) : Y2(num_capture_channels), E2(num_capture_channels), low_render_energy(num_capture_channels), num_points(num_capture_channels) {} std::vector> Y2; std::vector> E2; std::vector> low_render_energy; std::vector num_points; }; void UpdateAccumulatedSpectra( rtc::ArrayView X2, rtc::ArrayView> Y2, rtc::ArrayView> E2, const std::vector& converged_filters); void ResetAccumulatedSpectra(); void UpdateBands(const std::vector& converged_filters); void DecreaseErlePerBandForLowRenderSignals(); const bool use_onset_detection_; const float min_erle_; const std::array max_erle_; const bool use_min_erle_during_onsets_; AccumulatedSpectra accum_spectra_; std::vector> erle_; std::vector> erle_onsets_; std::vector> coming_onset_; std::vector> hold_counters_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_SUBBAND_ERLE_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/subband_nearend_detector.cc0000664000175000017500000000543714475643423031317 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/subband_nearend_detector.h" #include namespace webrtc { SubbandNearendDetector::SubbandNearendDetector( const EchoCanceller3Config::Suppressor::SubbandNearendDetection& config, size_t num_capture_channels) : config_(config), num_capture_channels_(num_capture_channels), nearend_smoothers_(num_capture_channels_, aec3::MovingAverage(kFftLengthBy2Plus1, config_.nearend_average_blocks)), one_over_subband_length1_( 1.f / (config_.subband1.high - config_.subband1.low + 1)), one_over_subband_length2_( 1.f / (config_.subband2.high - config_.subband2.low + 1)) {} void SubbandNearendDetector::Update( rtc::ArrayView> nearend_spectrum, rtc::ArrayView> residual_echo_spectrum, rtc::ArrayView> comfort_noise_spectrum, bool initial_state) { nearend_state_ = false; for (size_t ch = 0; ch < num_capture_channels_; ++ch) { const std::array& noise = comfort_noise_spectrum[ch]; std::array nearend; nearend_smoothers_[ch].Average(nearend_spectrum[ch], nearend); // Noise power of the first region. float noise_power = std::accumulate(noise.begin() + config_.subband1.low, noise.begin() + config_.subband1.high + 1, 0.f) * one_over_subband_length1_; // Nearend power of the first region. float nearend_power_subband1 = std::accumulate(nearend.begin() + config_.subband1.low, nearend.begin() + config_.subband1.high + 1, 0.f) * one_over_subband_length1_; // Nearend power of the second region. float nearend_power_subband2 = std::accumulate(nearend.begin() + config_.subband2.low, nearend.begin() + config_.subband2.high + 1, 0.f) * one_over_subband_length2_; // One channel is sufficient to trigger nearend state. nearend_state_ = nearend_state_ || (nearend_power_subband1 < config_.nearend_threshold * nearend_power_subband2 && (nearend_power_subband1 > config_.snr_threshold * noise_power)); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/subband_nearend_detector.h0000664000175000017500000000376414475643423031162 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_SUBBAND_NEAREND_DETECTOR_H_ #define MODULES_AUDIO_PROCESSING_AEC3_SUBBAND_NEAREND_DETECTOR_H_ #include #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/moving_average.h" #include "modules/audio_processing/aec3/nearend_detector.h" namespace webrtc { // Class for selecting whether the suppressor is in the nearend or echo state. class SubbandNearendDetector : public NearendDetector { public: SubbandNearendDetector( const EchoCanceller3Config::Suppressor::SubbandNearendDetection& config, size_t num_capture_channels); // Returns whether the current state is the nearend state. bool IsNearendState() const override { return nearend_state_; } // Updates the state selection based on latest spectral estimates. void Update(rtc::ArrayView> nearend_spectrum, rtc::ArrayView> residual_echo_spectrum, rtc::ArrayView> comfort_noise_spectrum, bool initial_state) override; private: const EchoCanceller3Config::Suppressor::SubbandNearendDetection config_; const size_t num_capture_channels_; std::vector nearend_smoothers_; const float one_over_subband_length1_; const float one_over_subband_length2_; bool nearend_state_ = false; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_SUBBAND_NEAREND_DETECTOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/subtractor.cc0000664000175000017500000003044614475643423026502 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/subtractor.h" #include #include #include "api/array_view.h" #include "modules/audio_processing/aec3/adaptive_fir_filter_erl.h" #include "modules/audio_processing/aec3/fft_data.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_minmax.h" namespace webrtc { namespace { void PredictionError(const Aec3Fft& fft, const FftData& S, rtc::ArrayView y, std::array* e, std::array* s) { std::array tmp; fft.Ifft(S, &tmp); constexpr float kScale = 1.0f / kFftLengthBy2; std::transform(y.begin(), y.end(), tmp.begin() + kFftLengthBy2, e->begin(), [&](float a, float b) { return a - b * kScale; }); if (s) { for (size_t k = 0; k < s->size(); ++k) { (*s)[k] = kScale * tmp[k + kFftLengthBy2]; } } } void ScaleFilterOutput(rtc::ArrayView y, float factor, rtc::ArrayView e, rtc::ArrayView s) { RTC_DCHECK_EQ(y.size(), e.size()); RTC_DCHECK_EQ(y.size(), s.size()); for (size_t k = 0; k < y.size(); ++k) { s[k] *= factor; e[k] = y[k] - s[k]; } } } // namespace Subtractor::Subtractor(const EchoCanceller3Config& config, size_t num_render_channels, size_t num_capture_channels, ApmDataDumper* data_dumper, Aec3Optimization optimization) : fft_(), data_dumper_(data_dumper), optimization_(optimization), config_(config), num_capture_channels_(num_capture_channels), refined_filters_(num_capture_channels_), coarse_filter_(num_capture_channels_), refined_gains_(num_capture_channels_), coarse_gains_(num_capture_channels_), filter_misadjustment_estimators_(num_capture_channels_), poor_coarse_filter_counters_(num_capture_channels_, 0), refined_frequency_responses_( num_capture_channels_, std::vector>( std::max(config_.filter.refined_initial.length_blocks, config_.filter.refined.length_blocks), std::array())), refined_impulse_responses_( num_capture_channels_, std::vector(GetTimeDomainLength(std::max( config_.filter.refined_initial.length_blocks, config_.filter.refined.length_blocks)), 0.f)) { for (size_t ch = 0; ch < num_capture_channels_; ++ch) { refined_filters_[ch] = std::make_unique( config_.filter.refined.length_blocks, config_.filter.refined_initial.length_blocks, config.filter.config_change_duration_blocks, num_render_channels, optimization, data_dumper_); coarse_filter_[ch] = std::make_unique( config_.filter.coarse.length_blocks, config_.filter.coarse_initial.length_blocks, config.filter.config_change_duration_blocks, num_render_channels, optimization, data_dumper_); refined_gains_[ch] = std::make_unique( config_.filter.refined_initial, config_.filter.config_change_duration_blocks); coarse_gains_[ch] = std::make_unique( config_.filter.coarse_initial, config.filter.config_change_duration_blocks); } RTC_DCHECK(data_dumper_); for (size_t ch = 0; ch < num_capture_channels_; ++ch) { for (auto& H2_k : refined_frequency_responses_[ch]) { H2_k.fill(0.f); } } } Subtractor::~Subtractor() = default; void Subtractor::HandleEchoPathChange( const EchoPathVariability& echo_path_variability) { const auto full_reset = [&]() { for (size_t ch = 0; ch < num_capture_channels_; ++ch) { refined_filters_[ch]->HandleEchoPathChange(); coarse_filter_[ch]->HandleEchoPathChange(); refined_gains_[ch]->HandleEchoPathChange(echo_path_variability); coarse_gains_[ch]->HandleEchoPathChange(); refined_gains_[ch]->SetConfig(config_.filter.refined_initial, true); coarse_gains_[ch]->SetConfig(config_.filter.coarse_initial, true); refined_filters_[ch]->SetSizePartitions( config_.filter.refined_initial.length_blocks, true); coarse_filter_[ch]->SetSizePartitions( config_.filter.coarse_initial.length_blocks, true); } }; if (echo_path_variability.delay_change != EchoPathVariability::DelayAdjustment::kNone) { full_reset(); } if (echo_path_variability.gain_change) { for (size_t ch = 0; ch < num_capture_channels_; ++ch) { refined_gains_[ch]->HandleEchoPathChange(echo_path_variability); } } } void Subtractor::ExitInitialState() { for (size_t ch = 0; ch < num_capture_channels_; ++ch) { refined_gains_[ch]->SetConfig(config_.filter.refined, false); coarse_gains_[ch]->SetConfig(config_.filter.coarse, false); refined_filters_[ch]->SetSizePartitions( config_.filter.refined.length_blocks, false); coarse_filter_[ch]->SetSizePartitions(config_.filter.coarse.length_blocks, false); } } void Subtractor::Process(const RenderBuffer& render_buffer, const std::vector>& capture, const RenderSignalAnalyzer& render_signal_analyzer, const AecState& aec_state, rtc::ArrayView outputs) { RTC_DCHECK_EQ(num_capture_channels_, capture.size()); // Compute the render powers. const bool same_filter_sizes = refined_filters_[0]->SizePartitions() == coarse_filter_[0]->SizePartitions(); std::array X2_refined; std::array X2_coarse_data; auto& X2_coarse = same_filter_sizes ? X2_refined : X2_coarse_data; if (same_filter_sizes) { render_buffer.SpectralSum(refined_filters_[0]->SizePartitions(), &X2_refined); } else if (refined_filters_[0]->SizePartitions() > coarse_filter_[0]->SizePartitions()) { render_buffer.SpectralSums(coarse_filter_[0]->SizePartitions(), refined_filters_[0]->SizePartitions(), &X2_coarse, &X2_refined); } else { render_buffer.SpectralSums(refined_filters_[0]->SizePartitions(), coarse_filter_[0]->SizePartitions(), &X2_refined, &X2_coarse); } // Process all capture channels for (size_t ch = 0; ch < num_capture_channels_; ++ch) { RTC_DCHECK_EQ(kBlockSize, capture[ch].size()); SubtractorOutput& output = outputs[ch]; rtc::ArrayView y = capture[ch]; FftData& E_refined = output.E_refined; FftData E_coarse; std::array& e_refined = output.e_refined; std::array& e_coarse = output.e_coarse; FftData S; FftData& G = S; // Form the outputs of the refined and coarse filters. refined_filters_[ch]->Filter(render_buffer, &S); PredictionError(fft_, S, y, &e_refined, &output.s_refined); coarse_filter_[ch]->Filter(render_buffer, &S); PredictionError(fft_, S, y, &e_coarse, &output.s_coarse); // Compute the signal powers in the subtractor output. output.ComputeMetrics(y); // Adjust the filter if needed. bool refined_filters_adjusted = false; filter_misadjustment_estimators_[ch].Update(output); if (filter_misadjustment_estimators_[ch].IsAdjustmentNeeded()) { float scale = filter_misadjustment_estimators_[ch].GetMisadjustment(); refined_filters_[ch]->ScaleFilter(scale); for (auto& h_k : refined_impulse_responses_[ch]) { h_k *= scale; } ScaleFilterOutput(y, scale, e_refined, output.s_refined); filter_misadjustment_estimators_[ch].Reset(); refined_filters_adjusted = true; } // Compute the FFts of the refined and coarse filter outputs. fft_.ZeroPaddedFft(e_refined, Aec3Fft::Window::kHanning, &E_refined); fft_.ZeroPaddedFft(e_coarse, Aec3Fft::Window::kHanning, &E_coarse); // Compute spectra for future use. E_coarse.Spectrum(optimization_, output.E2_coarse); E_refined.Spectrum(optimization_, output.E2_refined); // Update the refined filter. if (!refined_filters_adjusted) { std::array erl; ComputeErl(optimization_, refined_frequency_responses_[ch], erl); refined_gains_[ch]->Compute(X2_refined, render_signal_analyzer, output, erl, refined_filters_[ch]->SizePartitions(), aec_state.SaturatedCapture(), &G); } else { G.re.fill(0.f); G.im.fill(0.f); } refined_filters_[ch]->Adapt(render_buffer, G, &refined_impulse_responses_[ch]); refined_filters_[ch]->ComputeFrequencyResponse( &refined_frequency_responses_[ch]); if (ch == 0) { data_dumper_->DumpRaw("aec3_subtractor_G_refined", G.re); data_dumper_->DumpRaw("aec3_subtractor_G_refined", G.im); } // Update the coarse filter. poor_coarse_filter_counters_[ch] = output.e2_refined < output.e2_coarse ? poor_coarse_filter_counters_[ch] + 1 : 0; if (poor_coarse_filter_counters_[ch] < 5) { coarse_gains_[ch]->Compute(X2_coarse, render_signal_analyzer, E_coarse, coarse_filter_[ch]->SizePartitions(), aec_state.SaturatedCapture(), &G); } else { poor_coarse_filter_counters_[ch] = 0; coarse_filter_[ch]->SetFilter(refined_filters_[ch]->SizePartitions(), refined_filters_[ch]->GetFilter()); coarse_gains_[ch]->Compute(X2_coarse, render_signal_analyzer, E_refined, coarse_filter_[ch]->SizePartitions(), aec_state.SaturatedCapture(), &G); } coarse_filter_[ch]->Adapt(render_buffer, G); if (ch == 0) { data_dumper_->DumpRaw("aec3_subtractor_G_coarse", G.re); data_dumper_->DumpRaw("aec3_subtractor_G_coarse", G.im); filter_misadjustment_estimators_[ch].Dump(data_dumper_); DumpFilters(); } std::for_each(e_refined.begin(), e_refined.end(), [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); }); if (ch == 0) { data_dumper_->DumpWav("aec3_refined_filters_output", kBlockSize, &e_refined[0], 16000, 1); data_dumper_->DumpWav("aec3_coarse_filter_output", kBlockSize, &e_coarse[0], 16000, 1); } } } void Subtractor::FilterMisadjustmentEstimator::Update( const SubtractorOutput& output) { e2_acum_ += output.e2_refined; y2_acum_ += output.y2; if (++n_blocks_acum_ == n_blocks_) { if (y2_acum_ > n_blocks_ * 200.f * 200.f * kBlockSize) { float update = (e2_acum_ / y2_acum_); if (e2_acum_ > n_blocks_ * 7500.f * 7500.f * kBlockSize) { // Duration equal to blockSizeMs * n_blocks_ * 4. overhang_ = 4; } else { overhang_ = std::max(overhang_ - 1, 0); } if ((update < inv_misadjustment_) || (overhang_ > 0)) { inv_misadjustment_ += 0.1f * (update - inv_misadjustment_); } } e2_acum_ = 0.f; y2_acum_ = 0.f; n_blocks_acum_ = 0; } } void Subtractor::FilterMisadjustmentEstimator::Reset() { e2_acum_ = 0.f; y2_acum_ = 0.f; n_blocks_acum_ = 0; inv_misadjustment_ = 0.f; overhang_ = 0.f; } void Subtractor::FilterMisadjustmentEstimator::Dump( ApmDataDumper* data_dumper) const { data_dumper->DumpRaw("aec3_inv_misadjustment_factor", inv_misadjustment_); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/subtractor.h0000664000175000017500000001200514475643423026333 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_H_ #define MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_H_ #include #include #include #include #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/adaptive_fir_filter.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/aec3_fft.h" #include "modules/audio_processing/aec3/aec_state.h" #include "modules/audio_processing/aec3/coarse_filter_update_gain.h" #include "modules/audio_processing/aec3/echo_path_variability.h" #include "modules/audio_processing/aec3/refined_filter_update_gain.h" #include "modules/audio_processing/aec3/render_buffer.h" #include "modules/audio_processing/aec3/render_signal_analyzer.h" #include "modules/audio_processing/aec3/subtractor_output.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" namespace webrtc { // Proves linear echo cancellation functionality class Subtractor { public: Subtractor(const EchoCanceller3Config& config, size_t num_render_channels, size_t num_capture_channels, ApmDataDumper* data_dumper, Aec3Optimization optimization); ~Subtractor(); Subtractor(const Subtractor&) = delete; Subtractor& operator=(const Subtractor&) = delete; // Performs the echo subtraction. void Process(const RenderBuffer& render_buffer, const std::vector>& capture, const RenderSignalAnalyzer& render_signal_analyzer, const AecState& aec_state, rtc::ArrayView outputs); void HandleEchoPathChange(const EchoPathVariability& echo_path_variability); // Exits the initial state. void ExitInitialState(); // Returns the block-wise frequency responses for the refined adaptive // filters. const std::vector>>& FilterFrequencyResponses() const { return refined_frequency_responses_; } // Returns the estimates of the impulse responses for the refined adaptive // filters. const std::vector>& FilterImpulseResponses() const { return refined_impulse_responses_; } void DumpFilters() { data_dumper_->DumpRaw( "aec3_subtractor_h_refined", rtc::ArrayView( refined_impulse_responses_[0].data(), GetTimeDomainLength( refined_filters_[0]->max_filter_size_partitions()))); refined_filters_[0]->DumpFilter("aec3_subtractor_H_refined"); coarse_filter_[0]->DumpFilter("aec3_subtractor_H_coarse"); } private: class FilterMisadjustmentEstimator { public: FilterMisadjustmentEstimator() = default; ~FilterMisadjustmentEstimator() = default; // Update the misadjustment estimator. void Update(const SubtractorOutput& output); // GetMisadjustment() Returns a recommended scale for the filter so the // prediction error energy gets closer to the energy that is seen at the // microphone input. float GetMisadjustment() const { RTC_DCHECK_GT(inv_misadjustment_, 0.0f); // It is not aiming to adjust all the estimated mismatch. Instead, // it adjusts half of that estimated mismatch. return 2.f / sqrtf(inv_misadjustment_); } // Returns true if the prediciton error energy is significantly larger // than the microphone signal energy and, therefore, an adjustment is // recommended. bool IsAdjustmentNeeded() const { return inv_misadjustment_ > 10.f; } void Reset(); void Dump(ApmDataDumper* data_dumper) const; private: const int n_blocks_ = 4; int n_blocks_acum_ = 0; float e2_acum_ = 0.f; float y2_acum_ = 0.f; float inv_misadjustment_ = 0.f; int overhang_ = 0.f; }; const Aec3Fft fft_; ApmDataDumper* data_dumper_; const Aec3Optimization optimization_; const EchoCanceller3Config config_; const size_t num_capture_channels_; std::vector> refined_filters_; std::vector> coarse_filter_; std::vector> refined_gains_; std::vector> coarse_gains_; std::vector filter_misadjustment_estimators_; std::vector poor_coarse_filter_counters_; std::vector>> refined_frequency_responses_; std::vector> refined_impulse_responses_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/subtractor_output.cc0000664000175000017500000000361614475643423030121 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/subtractor_output.h" #include namespace webrtc { SubtractorOutput::SubtractorOutput() = default; SubtractorOutput::~SubtractorOutput() = default; void SubtractorOutput::Reset() { s_refined.fill(0.f); s_coarse.fill(0.f); e_refined.fill(0.f); e_coarse.fill(0.f); E_refined.re.fill(0.f); E_refined.im.fill(0.f); E2_refined.fill(0.f); E2_coarse.fill(0.f); e2_refined = 0.f; e2_coarse = 0.f; s2_refined = 0.f; s2_coarse = 0.f; y2 = 0.f; } void SubtractorOutput::ComputeMetrics(rtc::ArrayView y) { const auto sum_of_squares = [](float a, float b) { return a + b * b; }; y2 = std::accumulate(y.begin(), y.end(), 0.f, sum_of_squares); e2_refined = std::accumulate(e_refined.begin(), e_refined.end(), 0.f, sum_of_squares); e2_coarse = std::accumulate(e_coarse.begin(), e_coarse.end(), 0.f, sum_of_squares); s2_refined = std::accumulate(s_refined.begin(), s_refined.end(), 0.f, sum_of_squares); s2_coarse = std::accumulate(s_coarse.begin(), s_coarse.end(), 0.f, sum_of_squares); s_refined_max_abs = *std::max_element(s_refined.begin(), s_refined.end()); s_refined_max_abs = std::max(s_refined_max_abs, -(*std::min_element(s_refined.begin(), s_refined.end()))); s_coarse_max_abs = *std::max_element(s_coarse.begin(), s_coarse.end()); s_coarse_max_abs = std::max( s_coarse_max_abs, -(*std::min_element(s_coarse.begin(), s_coarse.end()))); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/subtractor_output.h0000664000175000017500000000306114475643423027755 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_OUTPUT_H_ #define MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_OUTPUT_H_ #include #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/fft_data.h" namespace webrtc { // Stores the values being returned from the echo subtractor for a single // capture channel. struct SubtractorOutput { SubtractorOutput(); ~SubtractorOutput(); std::array s_refined; std::array s_coarse; std::array e_refined; std::array e_coarse; FftData E_refined; std::array E2_refined; std::array E2_coarse; float s2_refined = 0.f; float s2_coarse = 0.f; float e2_refined = 0.f; float e2_coarse = 0.f; float y2 = 0.f; float s_refined_max_abs = 0.f; float s_coarse_max_abs = 0.f; // Reset the struct content. void Reset(); // Updates the powers of the signals. void ComputeMetrics(rtc::ArrayView y); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_OUTPUT_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/subtractor_output_analyzer.cc0000664000175000017500000000411414475643423032020 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/subtractor_output_analyzer.h" #include #include "modules/audio_processing/aec3/aec3_common.h" namespace webrtc { SubtractorOutputAnalyzer::SubtractorOutputAnalyzer(size_t num_capture_channels) : filters_converged_(num_capture_channels, false) {} void SubtractorOutputAnalyzer::Update( rtc::ArrayView subtractor_output, bool* any_filter_converged, bool* all_filters_diverged) { RTC_DCHECK(any_filter_converged); RTC_DCHECK(all_filters_diverged); RTC_DCHECK_EQ(subtractor_output.size(), filters_converged_.size()); *any_filter_converged = false; *all_filters_diverged = true; for (size_t ch = 0; ch < subtractor_output.size(); ++ch) { const float y2 = subtractor_output[ch].y2; const float e2_refined = subtractor_output[ch].e2_refined; const float e2_coarse = subtractor_output[ch].e2_coarse; constexpr float kConvergenceThreshold = 50 * 50 * kBlockSize; bool refined_filter_converged = e2_refined < 0.5f * y2 && y2 > kConvergenceThreshold; bool coarse_filter_converged = e2_coarse < 0.05f * y2 && y2 > kConvergenceThreshold; float min_e2 = std::min(e2_refined, e2_coarse); bool filter_diverged = min_e2 > 1.5f * y2 && y2 > 30.f * 30.f * kBlockSize; filters_converged_[ch] = refined_filter_converged || coarse_filter_converged; *any_filter_converged = *any_filter_converged || filters_converged_[ch]; *all_filters_diverged = *all_filters_diverged && filter_diverged; } } void SubtractorOutputAnalyzer::HandleEchoPathChange() { std::fill(filters_converged_.begin(), filters_converged_.end(), false); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/subtractor_output_analyzer.h0000664000175000017500000000251314475643423031663 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_OUTPUT_ANALYZER_H_ #define MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_OUTPUT_ANALYZER_H_ #include #include "modules/audio_processing/aec3/subtractor_output.h" namespace webrtc { // Class for analyzing the properties subtractor output. class SubtractorOutputAnalyzer { public: explicit SubtractorOutputAnalyzer(size_t num_capture_channels); ~SubtractorOutputAnalyzer() = default; // Analyses the subtractor output. void Update(rtc::ArrayView subtractor_output, bool* any_filter_converged, bool* all_filters_diverged); const std::vector& ConvergedFilters() const { return filters_converged_; } // Handle echo path change. void HandleEchoPathChange(); private: std::vector filters_converged_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_OUTPUT_ANALYZER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/suppression_filter.cc0000664000175000017500000001647214475643423030254 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/suppression_filter.h" #include #include #include #include #include #include "modules/audio_processing/aec3/vector_math.h" #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_minmax.h" namespace webrtc { namespace { // Hanning window from Matlab command win = sqrt(hanning(128)). const float kSqrtHanning[kFftLength] = { 0.00000000000000f, 0.02454122852291f, 0.04906767432742f, 0.07356456359967f, 0.09801714032956f, 0.12241067519922f, 0.14673047445536f, 0.17096188876030f, 0.19509032201613f, 0.21910124015687f, 0.24298017990326f, 0.26671275747490f, 0.29028467725446f, 0.31368174039889f, 0.33688985339222f, 0.35989503653499f, 0.38268343236509f, 0.40524131400499f, 0.42755509343028f, 0.44961132965461f, 0.47139673682600f, 0.49289819222978f, 0.51410274419322f, 0.53499761988710f, 0.55557023301960f, 0.57580819141785f, 0.59569930449243f, 0.61523159058063f, 0.63439328416365f, 0.65317284295378f, 0.67155895484702f, 0.68954054473707f, 0.70710678118655f, 0.72424708295147f, 0.74095112535496f, 0.75720884650648f, 0.77301045336274f, 0.78834642762661f, 0.80320753148064f, 0.81758481315158f, 0.83146961230255f, 0.84485356524971f, 0.85772861000027f, 0.87008699110871f, 0.88192126434835f, 0.89322430119552f, 0.90398929312344f, 0.91420975570353f, 0.92387953251129f, 0.93299279883474f, 0.94154406518302f, 0.94952818059304f, 0.95694033573221f, 0.96377606579544f, 0.97003125319454f, 0.97570213003853f, 0.98078528040323f, 0.98527764238894f, 0.98917650996478f, 0.99247953459871f, 0.99518472667220f, 0.99729045667869f, 0.99879545620517f, 0.99969881869620f, 1.00000000000000f, 0.99969881869620f, 0.99879545620517f, 0.99729045667869f, 0.99518472667220f, 0.99247953459871f, 0.98917650996478f, 0.98527764238894f, 0.98078528040323f, 0.97570213003853f, 0.97003125319454f, 0.96377606579544f, 0.95694033573221f, 0.94952818059304f, 0.94154406518302f, 0.93299279883474f, 0.92387953251129f, 0.91420975570353f, 0.90398929312344f, 0.89322430119552f, 0.88192126434835f, 0.87008699110871f, 0.85772861000027f, 0.84485356524971f, 0.83146961230255f, 0.81758481315158f, 0.80320753148064f, 0.78834642762661f, 0.77301045336274f, 0.75720884650648f, 0.74095112535496f, 0.72424708295147f, 0.70710678118655f, 0.68954054473707f, 0.67155895484702f, 0.65317284295378f, 0.63439328416365f, 0.61523159058063f, 0.59569930449243f, 0.57580819141785f, 0.55557023301960f, 0.53499761988710f, 0.51410274419322f, 0.49289819222978f, 0.47139673682600f, 0.44961132965461f, 0.42755509343028f, 0.40524131400499f, 0.38268343236509f, 0.35989503653499f, 0.33688985339222f, 0.31368174039889f, 0.29028467725446f, 0.26671275747490f, 0.24298017990326f, 0.21910124015687f, 0.19509032201613f, 0.17096188876030f, 0.14673047445536f, 0.12241067519922f, 0.09801714032956f, 0.07356456359967f, 0.04906767432742f, 0.02454122852291f}; } // namespace SuppressionFilter::SuppressionFilter(Aec3Optimization optimization, int sample_rate_hz, size_t num_capture_channels) : optimization_(optimization), sample_rate_hz_(sample_rate_hz), num_capture_channels_(num_capture_channels), fft_(), e_output_old_(NumBandsForRate(sample_rate_hz_), std::vector>( num_capture_channels_)) { RTC_DCHECK(ValidFullBandRate(sample_rate_hz_)); for (size_t b = 0; b < e_output_old_.size(); ++b) { for (size_t ch = 0; ch < e_output_old_[b].size(); ++ch) { e_output_old_[b][ch].fill(0.f); } } } SuppressionFilter::~SuppressionFilter() = default; void SuppressionFilter::ApplyGain( rtc::ArrayView comfort_noise, rtc::ArrayView comfort_noise_high_band, const std::array& suppression_gain, float high_bands_gain, rtc::ArrayView E_lowest_band, std::vector>>* e) { RTC_DCHECK(e); RTC_DCHECK_EQ(e->size(), NumBandsForRate(sample_rate_hz_)); // Comfort noise gain is sqrt(1-g^2), where g is the suppression gain. std::array noise_gain; for (size_t i = 0; i < kFftLengthBy2Plus1; ++i) { noise_gain[i] = 1.f - suppression_gain[i] * suppression_gain[i]; } aec3::VectorMath(optimization_).Sqrt(noise_gain); const float high_bands_noise_scaling = 0.4f * std::sqrt(1.f - high_bands_gain * high_bands_gain); for (size_t ch = 0; ch < num_capture_channels_; ++ch) { FftData E; // Analysis filterbank. E.Assign(E_lowest_band[ch]); for (size_t i = 0; i < kFftLengthBy2Plus1; ++i) { // Apply suppression gains. E.re[i] *= suppression_gain[i]; E.im[i] *= suppression_gain[i]; // Scale and add the comfort noise. E.re[i] += noise_gain[i] * comfort_noise[ch].re[i]; E.im[i] += noise_gain[i] * comfort_noise[ch].im[i]; } // Synthesis filterbank. std::array e_extended; constexpr float kIfftNormalization = 2.f / kFftLength; fft_.Ifft(E, &e_extended); auto& e0 = (*e)[0][ch]; auto& e0_old = e_output_old_[0][ch]; // Window and add the first half of e_extended with the second half of // e_extended from the previous block. for (size_t i = 0; i < kFftLengthBy2; ++i) { e0[i] = e0_old[i] * kSqrtHanning[kFftLengthBy2 + i]; e0[i] += e_extended[i] * kSqrtHanning[i]; e0[i] *= kIfftNormalization; } // The second half of e_extended is stored for the succeeding frame. std::copy(e_extended.begin() + kFftLengthBy2, e_extended.begin() + kFftLength, std::begin(e0_old)); // Apply suppression gain to upper bands. for (size_t b = 1; b < e->size(); ++b) { auto& e_band = (*e)[b][ch]; for (size_t i = 0; i < kFftLengthBy2; ++i) { e_band[i] *= high_bands_gain; } } // Add comfort noise to band 1. if (e->size() > 1) { E.Assign(comfort_noise_high_band[ch]); std::array time_domain_high_band_noise; fft_.Ifft(E, &time_domain_high_band_noise); auto& e1 = (*e)[1][ch]; const float gain = high_bands_noise_scaling * kIfftNormalization; for (size_t i = 0; i < kFftLengthBy2; ++i) { e1[i] += time_domain_high_band_noise[i] * gain; } } // Delay upper bands to match the delay of the filter bank. for (size_t b = 1; b < e->size(); ++b) { auto& e_band = (*e)[b][ch]; auto& e_band_old = e_output_old_[b][ch]; for (size_t i = 0; i < kFftLengthBy2; ++i) { std::swap(e_band[i], e_band_old[i]); } } // Clamp output of all bands. for (size_t b = 0; b < e->size(); ++b) { auto& e_band = (*e)[b][ch]; for (size_t i = 0; i < kFftLengthBy2; ++i) { e_band[i] = rtc::SafeClamp(e_band[i], -32768.f, 32767.f); } } } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/suppression_filter.h0000664000175000017500000000330614475643423030106 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_FILTER_H_ #define MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_FILTER_H_ #include #include #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/aec3_fft.h" #include "modules/audio_processing/aec3/fft_data.h" #include "rtc_base/constructor_magic.h" namespace webrtc { class SuppressionFilter { public: SuppressionFilter(Aec3Optimization optimization, int sample_rate_hz, size_t num_capture_channels_); ~SuppressionFilter(); void ApplyGain(rtc::ArrayView comfort_noise, rtc::ArrayView comfort_noise_high_bands, const std::array& suppression_gain, float high_bands_gain, rtc::ArrayView E_lowest_band, std::vector>>* e); private: const Aec3Optimization optimization_; const int sample_rate_hz_; const size_t num_capture_channels_; const Aec3Fft fft_; std::vector>> e_output_old_; RTC_DISALLOW_COPY_AND_ASSIGN(SuppressionFilter); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_FILTER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/suppression_gain.cc0000664000175000017500000004222614475643423027701 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/suppression_gain.h" #include #include #include #include #include "modules/audio_processing/aec3/dominant_nearend_detector.h" #include "modules/audio_processing/aec3/moving_average.h" #include "modules/audio_processing/aec3/subband_nearend_detector.h" #include "modules/audio_processing/aec3/vector_math.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/atomic_ops.h" #include "rtc_base/checks.h" namespace webrtc { namespace { void PostprocessGains(std::array* gain) { // TODO(gustaf): Investigate if this can be relaxed to achieve higher // transparency above 2 kHz. // Limit the low frequency gains to avoid the impact of the high-pass filter // on the lower-frequency gain influencing the overall achieved gain. (*gain)[0] = (*gain)[1] = std::min((*gain)[1], (*gain)[2]); // Limit the high frequency gains to avoid the impact of the anti-aliasing // filter on the upper-frequency gains influencing the overall achieved // gain. TODO(peah): Update this when new anti-aliasing filters are // implemented. constexpr size_t kAntiAliasingImpactLimit = (64 * 2000) / 8000; const float min_upper_gain = (*gain)[kAntiAliasingImpactLimit]; std::for_each( gain->begin() + kAntiAliasingImpactLimit, gain->end() - 1, [min_upper_gain](float& a) { a = std::min(a, min_upper_gain); }); (*gain)[kFftLengthBy2] = (*gain)[kFftLengthBy2Minus1]; // Limits the gain in the frequencies for which the adaptive filter has not // converged. // TODO(peah): Make adaptive to take the actual filter error into account. constexpr size_t kUpperAccurateBandPlus1 = 29; constexpr float oneByBandsInSum = 1 / static_cast(kUpperAccurateBandPlus1 - 20); const float hf_gain_bound = std::accumulate(gain->begin() + 20, gain->begin() + kUpperAccurateBandPlus1, 0.f) * oneByBandsInSum; std::for_each(gain->begin() + kUpperAccurateBandPlus1, gain->end(), [hf_gain_bound](float& a) { a = std::min(a, hf_gain_bound); }); } // Scales the echo according to assessed audibility at the other end. void WeightEchoForAudibility(const EchoCanceller3Config& config, rtc::ArrayView echo, rtc::ArrayView weighted_echo) { RTC_DCHECK_EQ(kFftLengthBy2Plus1, echo.size()); RTC_DCHECK_EQ(kFftLengthBy2Plus1, weighted_echo.size()); auto weigh = [](float threshold, float normalizer, size_t begin, size_t end, rtc::ArrayView echo, rtc::ArrayView weighted_echo) { for (size_t k = begin; k < end; ++k) { if (echo[k] < threshold) { float tmp = (threshold - echo[k]) * normalizer; weighted_echo[k] = echo[k] * std::max(0.f, 1.f - tmp * tmp); } else { weighted_echo[k] = echo[k]; } } }; float threshold = config.echo_audibility.floor_power * config.echo_audibility.audibility_threshold_lf; float normalizer = 1.f / (threshold - config.echo_audibility.floor_power); weigh(threshold, normalizer, 0, 3, echo, weighted_echo); threshold = config.echo_audibility.floor_power * config.echo_audibility.audibility_threshold_mf; normalizer = 1.f / (threshold - config.echo_audibility.floor_power); weigh(threshold, normalizer, 3, 7, echo, weighted_echo); threshold = config.echo_audibility.floor_power * config.echo_audibility.audibility_threshold_hf; normalizer = 1.f / (threshold - config.echo_audibility.floor_power); weigh(threshold, normalizer, 7, kFftLengthBy2Plus1, echo, weighted_echo); } } // namespace int SuppressionGain::instance_count_ = 0; float SuppressionGain::UpperBandsGain( rtc::ArrayView> echo_spectrum, rtc::ArrayView> comfort_noise_spectrum, const absl::optional& narrow_peak_band, bool saturated_echo, const std::vector>>& render, const std::array& low_band_gain) const { RTC_DCHECK_LT(0, render.size()); if (render.size() == 1) { return 1.f; } const size_t num_render_channels = render[0].size(); if (narrow_peak_band && (*narrow_peak_band > static_cast(kFftLengthBy2Plus1 - 10))) { return 0.001f; } constexpr size_t kLowBandGainLimit = kFftLengthBy2 / 2; const float gain_below_8_khz = *std::min_element( low_band_gain.begin() + kLowBandGainLimit, low_band_gain.end()); // Always attenuate the upper bands when there is saturated echo. if (saturated_echo) { return std::min(0.001f, gain_below_8_khz); } // Compute the upper and lower band energies. const auto sum_of_squares = [](float a, float b) { return a + b * b; }; float low_band_energy = 0.f; for (size_t ch = 0; ch < num_render_channels; ++ch) { const float channel_energy = std::accumulate( render[0][0].begin(), render[0][0].end(), 0.f, sum_of_squares); low_band_energy = std::max(low_band_energy, channel_energy); } float high_band_energy = 0.f; for (size_t k = 1; k < render.size(); ++k) { for (size_t ch = 0; ch < num_render_channels; ++ch) { const float energy = std::accumulate( render[k][ch].begin(), render[k][ch].end(), 0.f, sum_of_squares); high_band_energy = std::max(high_band_energy, energy); } } // If there is more power in the lower frequencies than the upper frequencies, // or if the power in upper frequencies is low, do not bound the gain in the // upper bands. float anti_howling_gain; const float activation_threshold = kBlockSize * config_.suppressor.high_bands_suppression .anti_howling_activation_threshold; if (high_band_energy < std::max(low_band_energy, activation_threshold)) { anti_howling_gain = 1.f; } else { // In all other cases, bound the gain for upper frequencies. RTC_DCHECK_LE(low_band_energy, high_band_energy); RTC_DCHECK_NE(0.f, high_band_energy); anti_howling_gain = config_.suppressor.high_bands_suppression.anti_howling_gain * sqrtf(low_band_energy / high_band_energy); } float gain_bound = 1.f; if (!dominant_nearend_detector_->IsNearendState()) { // Bound the upper gain during significant echo activity. const auto& cfg = config_.suppressor.high_bands_suppression; auto low_frequency_energy = [](rtc::ArrayView spectrum) { RTC_DCHECK_LE(16, spectrum.size()); return std::accumulate(spectrum.begin() + 1, spectrum.begin() + 16, 0.f); }; for (size_t ch = 0; ch < num_capture_channels_; ++ch) { const float echo_sum = low_frequency_energy(echo_spectrum[ch]); const float noise_sum = low_frequency_energy(comfort_noise_spectrum[ch]); if (echo_sum > cfg.enr_threshold * noise_sum) { gain_bound = cfg.max_gain_during_echo; break; } } } // Choose the gain as the minimum of the lower and upper gains. return std::min(std::min(gain_below_8_khz, anti_howling_gain), gain_bound); } // Computes the gain to reduce the echo to a non audible level. void SuppressionGain::GainToNoAudibleEcho( const std::array& nearend, const std::array& echo, const std::array& masker, std::array* gain) const { const auto& p = dominant_nearend_detector_->IsNearendState() ? nearend_params_ : normal_params_; for (size_t k = 0; k < gain->size(); ++k) { float enr = echo[k] / (nearend[k] + 1.f); // Echo-to-nearend ratio. float emr = echo[k] / (masker[k] + 1.f); // Echo-to-masker (noise) ratio. float g = 1.0f; if (enr > p.enr_transparent_[k] && emr > p.emr_transparent_[k]) { g = (p.enr_suppress_[k] - enr) / (p.enr_suppress_[k] - p.enr_transparent_[k]); g = std::max(g, p.emr_transparent_[k] / emr); } (*gain)[k] = g; } } // Compute the minimum gain as the attenuating gain to put the signal just // above the zero sample values. void SuppressionGain::GetMinGain( rtc::ArrayView weighted_residual_echo, rtc::ArrayView last_nearend, rtc::ArrayView last_echo, bool low_noise_render, bool saturated_echo, rtc::ArrayView min_gain) const { if (!saturated_echo) { const float min_echo_power = low_noise_render ? config_.echo_audibility.low_render_limit : config_.echo_audibility.normal_render_limit; for (size_t k = 0; k < min_gain.size(); ++k) { min_gain[k] = weighted_residual_echo[k] > 0.f ? min_echo_power / weighted_residual_echo[k] : 1.f; min_gain[k] = std::min(min_gain[k], 1.f); } const bool is_nearend_state = dominant_nearend_detector_->IsNearendState(); for (size_t k = 0; k < 6; ++k) { const auto& dec = is_nearend_state ? nearend_params_.max_dec_factor_lf : normal_params_.max_dec_factor_lf; // Make sure the gains of the low frequencies do not decrease too // quickly after strong nearend. if (last_nearend[k] > last_echo[k]) { min_gain[k] = std::max(min_gain[k], last_gain_[k] * dec); min_gain[k] = std::min(min_gain[k], 1.f); } } } else { std::fill(min_gain.begin(), min_gain.end(), 0.f); } } // Compute the maximum gain by limiting the gain increase from the previous // gain. void SuppressionGain::GetMaxGain(rtc::ArrayView max_gain) const { const auto& inc = dominant_nearend_detector_->IsNearendState() ? nearend_params_.max_inc_factor : normal_params_.max_inc_factor; const auto& floor = config_.suppressor.floor_first_increase; for (size_t k = 0; k < max_gain.size(); ++k) { max_gain[k] = std::min(std::max(last_gain_[k] * inc, floor), 1.f); } } void SuppressionGain::LowerBandGain( bool low_noise_render, const AecState& aec_state, rtc::ArrayView> suppressor_input, rtc::ArrayView> residual_echo, rtc::ArrayView> comfort_noise, std::array* gain) { gain->fill(1.f); const bool saturated_echo = aec_state.SaturatedEcho(); std::array max_gain; GetMaxGain(max_gain); for (size_t ch = 0; ch < num_capture_channels_; ++ch) { std::array G; std::array nearend; nearend_smoothers_[ch].Average(suppressor_input[ch], nearend); // Weight echo power in terms of audibility. std::array weighted_residual_echo; WeightEchoForAudibility(config_, residual_echo[ch], weighted_residual_echo); std::array min_gain; GetMinGain(weighted_residual_echo, last_nearend_[ch], last_echo_[ch], low_noise_render, saturated_echo, min_gain); GainToNoAudibleEcho(nearend, weighted_residual_echo, comfort_noise[0], &G); // Clamp gains. for (size_t k = 0; k < gain->size(); ++k) { G[k] = std::max(std::min(G[k], max_gain[k]), min_gain[k]); (*gain)[k] = std::min((*gain)[k], G[k]); } // Store data required for the gain computation of the next block. std::copy(nearend.begin(), nearend.end(), last_nearend_[ch].begin()); std::copy(weighted_residual_echo.begin(), weighted_residual_echo.end(), last_echo_[ch].begin()); } // Limit high-frequency gains. PostprocessGains(gain); // Store computed gains. std::copy(gain->begin(), gain->end(), last_gain_.begin()); // Transform gains to amplitude domain. aec3::VectorMath(optimization_).Sqrt(*gain); } SuppressionGain::SuppressionGain(const EchoCanceller3Config& config, Aec3Optimization optimization, int sample_rate_hz, size_t num_capture_channels) : data_dumper_( new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), optimization_(optimization), config_(config), num_capture_channels_(num_capture_channels), state_change_duration_blocks_( static_cast(config_.filter.config_change_duration_blocks)), last_nearend_(num_capture_channels_, {0}), last_echo_(num_capture_channels_, {0}), nearend_smoothers_( num_capture_channels_, aec3::MovingAverage(kFftLengthBy2Plus1, config.suppressor.nearend_average_blocks)), nearend_params_(config_.suppressor.nearend_tuning), normal_params_(config_.suppressor.normal_tuning) { RTC_DCHECK_LT(0, state_change_duration_blocks_); last_gain_.fill(1.f); if (config_.suppressor.use_subband_nearend_detection) { dominant_nearend_detector_ = std::make_unique( config_.suppressor.subband_nearend_detection, num_capture_channels_); } else { dominant_nearend_detector_ = std::make_unique( config_.suppressor.dominant_nearend_detection, num_capture_channels_); } RTC_DCHECK(dominant_nearend_detector_); } SuppressionGain::~SuppressionGain() = default; void SuppressionGain::GetGain( rtc::ArrayView> nearend_spectrum, rtc::ArrayView> echo_spectrum, rtc::ArrayView> residual_echo_spectrum, rtc::ArrayView> comfort_noise_spectrum, const RenderSignalAnalyzer& render_signal_analyzer, const AecState& aec_state, const std::vector>>& render, float* high_bands_gain, std::array* low_band_gain) { RTC_DCHECK(high_bands_gain); RTC_DCHECK(low_band_gain); // Update the nearend state selection. dominant_nearend_detector_->Update(nearend_spectrum, residual_echo_spectrum, comfort_noise_spectrum, initial_state_); // Compute gain for the lower band. bool low_noise_render = low_render_detector_.Detect(render); LowerBandGain(low_noise_render, aec_state, nearend_spectrum, residual_echo_spectrum, comfort_noise_spectrum, low_band_gain); // Compute the gain for the upper bands. const absl::optional narrow_peak_band = render_signal_analyzer.NarrowPeakBand(); *high_bands_gain = UpperBandsGain(echo_spectrum, comfort_noise_spectrum, narrow_peak_band, aec_state.SaturatedEcho(), render, *low_band_gain); } void SuppressionGain::SetInitialState(bool state) { initial_state_ = state; if (state) { initial_state_change_counter_ = state_change_duration_blocks_; } else { initial_state_change_counter_ = 0; } } // Detects when the render signal can be considered to have low power and // consist of stationary noise. bool SuppressionGain::LowNoiseRenderDetector::Detect( const std::vector>>& render) { float x2_sum = 0.f; float x2_max = 0.f; for (const auto& x_ch : render[0]) { for (const auto& x_k : x_ch) { const float x2 = x_k * x_k; x2_sum += x2; x2_max = std::max(x2_max, x2); } } const size_t num_render_channels = render[0].size(); x2_sum = x2_sum / num_render_channels; ; constexpr float kThreshold = 50.f * 50.f * 64.f; const bool low_noise_render = average_power_ < kThreshold && x2_max < 3 * average_power_; average_power_ = average_power_ * 0.9f + x2_sum * 0.1f; return low_noise_render; } SuppressionGain::GainParameters::GainParameters( const EchoCanceller3Config::Suppressor::Tuning& tuning) : max_inc_factor(tuning.max_inc_factor), max_dec_factor_lf(tuning.max_dec_factor_lf) { // Compute per-band masking thresholds. constexpr size_t kLastLfBand = 5; constexpr size_t kFirstHfBand = 8; RTC_DCHECK_LT(kLastLfBand, kFirstHfBand); auto& lf = tuning.mask_lf; auto& hf = tuning.mask_hf; RTC_DCHECK_LT(lf.enr_transparent, lf.enr_suppress); RTC_DCHECK_LT(hf.enr_transparent, hf.enr_suppress); for (size_t k = 0; k < kFftLengthBy2Plus1; k++) { float a; if (k <= kLastLfBand) { a = 0.f; } else if (k < kFirstHfBand) { a = (k - kLastLfBand) / static_cast(kFirstHfBand - kLastLfBand); } else { a = 1.f; } enr_transparent_[k] = (1 - a) * lf.enr_transparent + a * hf.enr_transparent; enr_suppress_[k] = (1 - a) * lf.enr_suppress + a * hf.enr_suppress; emr_transparent_[k] = (1 - a) * lf.emr_transparent + a * hf.emr_transparent; } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/suppression_gain.h0000664000175000017500000001205214475643423027535 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_GAIN_H_ #define MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_GAIN_H_ #include #include #include #include "absl/types/optional.h" #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/aec_state.h" #include "modules/audio_processing/aec3/fft_data.h" #include "modules/audio_processing/aec3/moving_average.h" #include "modules/audio_processing/aec3/nearend_detector.h" #include "modules/audio_processing/aec3/render_signal_analyzer.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/constructor_magic.h" namespace webrtc { class SuppressionGain { public: SuppressionGain(const EchoCanceller3Config& config, Aec3Optimization optimization, int sample_rate_hz, size_t num_capture_channels); ~SuppressionGain(); void GetGain( rtc::ArrayView> nearend_spectrum, rtc::ArrayView> echo_spectrum, rtc::ArrayView> residual_echo_spectrum, rtc::ArrayView> comfort_noise_spectrum, const RenderSignalAnalyzer& render_signal_analyzer, const AecState& aec_state, const std::vector>>& render, float* high_bands_gain, std::array* low_band_gain); // Toggles the usage of the initial state. void SetInitialState(bool state); private: // Computes the gain to apply for the bands beyond the first band. float UpperBandsGain( rtc::ArrayView> echo_spectrum, rtc::ArrayView> comfort_noise_spectrum, const absl::optional& narrow_peak_band, bool saturated_echo, const std::vector>>& render, const std::array& low_band_gain) const; void GainToNoAudibleEcho(const std::array& nearend, const std::array& echo, const std::array& masker, std::array* gain) const; void LowerBandGain( bool stationary_with_low_power, const AecState& aec_state, rtc::ArrayView> suppressor_input, rtc::ArrayView> residual_echo, rtc::ArrayView> comfort_noise, std::array* gain); void GetMinGain(rtc::ArrayView weighted_residual_echo, rtc::ArrayView last_nearend, rtc::ArrayView last_echo, bool low_noise_render, bool saturated_echo, rtc::ArrayView min_gain) const; void GetMaxGain(rtc::ArrayView max_gain) const; class LowNoiseRenderDetector { public: bool Detect(const std::vector>>& render); private: float average_power_ = 32768.f * 32768.f; }; struct GainParameters { explicit GainParameters( const EchoCanceller3Config::Suppressor::Tuning& tuning); const float max_inc_factor; const float max_dec_factor_lf; std::array enr_transparent_; std::array enr_suppress_; std::array emr_transparent_; }; static int instance_count_; std::unique_ptr data_dumper_; const Aec3Optimization optimization_; const EchoCanceller3Config config_; const size_t num_capture_channels_; const int state_change_duration_blocks_; std::array last_gain_; std::vector> last_nearend_; std::vector> last_echo_; LowNoiseRenderDetector low_render_detector_; bool initial_state_ = true; int initial_state_change_counter_ = 0; std::vector nearend_smoothers_; const GainParameters nearend_params_; const GainParameters normal_params_; std::unique_ptr dominant_nearend_detector_; RTC_DISALLOW_COPY_AND_ASSIGN(SuppressionGain); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_GAIN_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/transparent_mode.cc0000664000175000017500000002061314475643423027652 0ustar00arunarun/* * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/transparent_mode.h" #include "rtc_base/checks.h" #include "system_wrappers/include/field_trial.h" namespace webrtc { namespace { constexpr size_t kBlocksSinceConvergencedFilterInit = 10000; constexpr size_t kBlocksSinceConsistentEstimateInit = 10000; bool DeactivateTransparentMode() { return field_trial::IsEnabled("WebRTC-Aec3TransparentModeKillSwitch"); } bool DeactivateTransparentModeHmm() { return field_trial::IsEnabled("WebRTC-Aec3TransparentModeHmmKillSwitch"); } } // namespace // Classifier that toggles transparent mode which reduces echo suppression when // headsets are used. class TransparentModeImpl : public TransparentMode { public: bool Active() const override { return transparency_activated_; } void Reset() override { // Determines if transparent mode is used. transparency_activated_ = false; // The estimated probability of being transparent mode. prob_transparent_state_ = 0.f; } void Update(int filter_delay_blocks, bool any_filter_consistent, bool any_filter_converged, bool all_filters_diverged, bool active_render, bool saturated_capture) override { // The classifier is implemented as a Hidden Markov Model (HMM) with two // hidden states: "normal" and "transparent". The estimated probabilities of // the two states are updated by observing filter convergence during active // render. The filters are less likely to be reported as converged when // there is no echo present in the microphone signal. // The constants have been obtained by observing active_render and // any_filter_converged under varying call scenarios. They have further been // hand tuned to prefer normal state during uncertain regions (to avoid echo // leaks). // The model is only updated during active render. if (!active_render) return; // Probability of switching from one state to the other. constexpr float kSwitch = 0.000001f; // Probability of observing converged filters in states "normal" and // "transparent" during active render. constexpr float kConvergedNormal = 0.03f; constexpr float kConvergedTransparent = 0.005f; // Probability of transitioning to transparent state from normal state and // transparent state respectively. constexpr float kA[2] = {kSwitch, 1.f - kSwitch}; // Probability of the two observations (converged filter or not converged // filter) in normal state and transparent state respectively. constexpr float kB[2][2] = { {1.f - kConvergedNormal, kConvergedNormal}, {1.f - kConvergedTransparent, kConvergedTransparent}}; // Probability of the two states before the update. const float prob_transparent = prob_transparent_state_; const float prob_normal = 1.f - prob_transparent; // Probability of transitioning to transparent state. const float prob_transition_transparent = prob_normal * kA[0] + prob_transparent * kA[1]; const float prob_transition_normal = 1.f - prob_transition_transparent; // Observed output. const int out = any_filter_converged; // Joint probabilites of the observed output and respective states. const float prob_joint_normal = prob_transition_normal * kB[0][out]; const float prob_joint_transparent = prob_transition_transparent * kB[1][out]; // Conditional probability of transparent state and the observed output. RTC_DCHECK_GT(prob_joint_normal + prob_joint_transparent, 0.f); prob_transparent_state_ = prob_joint_transparent / (prob_joint_normal + prob_joint_transparent); // Transparent mode is only activated when its state probability is high. // Dead zone between activation/deactivation thresholds to avoid switching // back and forth. if (prob_transparent_state_ > 0.95f) { transparency_activated_ = true; } else if (prob_transparent_state_ < 0.5f) { transparency_activated_ = false; } } private: bool transparency_activated_ = false; float prob_transparent_state_ = 0.f; }; // Legacy classifier for toggling transparent mode. class LegacyTransparentModeImpl : public TransparentMode { public: explicit LegacyTransparentModeImpl(const EchoCanceller3Config& config) : linear_and_stable_echo_path_( config.echo_removal_control.linear_and_stable_echo_path), active_blocks_since_sane_filter_(kBlocksSinceConsistentEstimateInit), non_converged_sequence_size_(kBlocksSinceConvergencedFilterInit) {} bool Active() const override { return transparency_activated_; } void Reset() override { non_converged_sequence_size_ = kBlocksSinceConvergencedFilterInit; diverged_sequence_size_ = 0; strong_not_saturated_render_blocks_ = 0; if (linear_and_stable_echo_path_) { recent_convergence_during_activity_ = false; } } void Update(int filter_delay_blocks, bool any_filter_consistent, bool any_filter_converged, bool all_filters_diverged, bool active_render, bool saturated_capture) override { ++capture_block_counter_; strong_not_saturated_render_blocks_ += active_render && !saturated_capture ? 1 : 0; if (any_filter_consistent && filter_delay_blocks < 5) { sane_filter_observed_ = true; active_blocks_since_sane_filter_ = 0; } else if (active_render) { ++active_blocks_since_sane_filter_; } bool sane_filter_recently_seen; if (!sane_filter_observed_) { sane_filter_recently_seen = capture_block_counter_ <= 5 * kNumBlocksPerSecond; } else { sane_filter_recently_seen = active_blocks_since_sane_filter_ <= 30 * kNumBlocksPerSecond; } if (any_filter_converged) { recent_convergence_during_activity_ = true; active_non_converged_sequence_size_ = 0; non_converged_sequence_size_ = 0; ++num_converged_blocks_; } else { if (++non_converged_sequence_size_ > 20 * kNumBlocksPerSecond) { num_converged_blocks_ = 0; } if (active_render && ++active_non_converged_sequence_size_ > 60 * kNumBlocksPerSecond) { recent_convergence_during_activity_ = false; } } if (!all_filters_diverged) { diverged_sequence_size_ = 0; } else if (++diverged_sequence_size_ >= 60) { // TODO(peah): Change these lines to ensure proper triggering of usable // filter. non_converged_sequence_size_ = kBlocksSinceConvergencedFilterInit; } if (active_non_converged_sequence_size_ > 60 * kNumBlocksPerSecond) { finite_erl_recently_detected_ = false; } if (num_converged_blocks_ > 50) { finite_erl_recently_detected_ = true; } if (finite_erl_recently_detected_) { transparency_activated_ = false; } else if (sane_filter_recently_seen && recent_convergence_during_activity_) { transparency_activated_ = false; } else { const bool filter_should_have_converged = strong_not_saturated_render_blocks_ > 6 * kNumBlocksPerSecond; transparency_activated_ = filter_should_have_converged; } } private: const bool linear_and_stable_echo_path_; size_t capture_block_counter_ = 0; bool transparency_activated_ = false; size_t active_blocks_since_sane_filter_; bool sane_filter_observed_ = false; bool finite_erl_recently_detected_ = false; size_t non_converged_sequence_size_; size_t diverged_sequence_size_ = 0; size_t active_non_converged_sequence_size_ = 0; size_t num_converged_blocks_ = 0; bool recent_convergence_during_activity_ = false; size_t strong_not_saturated_render_blocks_ = 0; }; std::unique_ptr TransparentMode::Create( const EchoCanceller3Config& config) { if (config.ep_strength.bounded_erl || DeactivateTransparentMode()) { return nullptr; } if (DeactivateTransparentModeHmm()) { return std::make_unique(config); } return std::make_unique(); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/transparent_mode.h0000664000175000017500000000300614475643423027511 0ustar00arunarun/* * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_TRANSPARENT_MODE_H_ #define MODULES_AUDIO_PROCESSING_AEC3_TRANSPARENT_MODE_H_ #include #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" namespace webrtc { // Class for detecting and toggling the transparent mode which causes the // suppressor to apply less suppression. class TransparentMode { public: static std::unique_ptr Create( const EchoCanceller3Config& config); virtual ~TransparentMode() {} // Returns whether the transparent mode should be active. virtual bool Active() const = 0; // Resets the state of the detector. virtual void Reset() = 0; // Updates the detection decision based on new data. virtual void Update(int filter_delay_blocks, bool any_filter_consistent, bool any_filter_converged, bool all_filters_diverged, bool active_render, bool saturated_capture) = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_TRANSPARENT_MODE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/vector_math.h0000664000175000017500000001537414475643423026472 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC3_VECTOR_MATH_H_ #define MODULES_AUDIO_PROCESSING_AEC3_VECTOR_MATH_H_ // Defines WEBRTC_ARCH_X86_FAMILY, used below. #include "rtc_base/system/arch.h" #if defined(WEBRTC_HAS_NEON) #include #endif #if defined(WEBRTC_ARCH_X86_FAMILY) #include #endif #include #include #include #include #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" #include "rtc_base/checks.h" namespace webrtc { namespace aec3 { // Provides optimizations for mathematical operations based on vectors. class VectorMath { public: explicit VectorMath(Aec3Optimization optimization) : optimization_(optimization) {} // Elementwise square root. void SqrtAVX2(rtc::ArrayView x); void Sqrt(rtc::ArrayView x) { switch (optimization_) { #if defined(WEBRTC_ARCH_X86_FAMILY) case Aec3Optimization::kSse2: { const int x_size = static_cast(x.size()); const int vector_limit = x_size >> 2; int j = 0; for (; j < vector_limit * 4; j += 4) { __m128 g = _mm_loadu_ps(&x[j]); g = _mm_sqrt_ps(g); _mm_storeu_ps(&x[j], g); } for (; j < x_size; ++j) { x[j] = sqrtf(x[j]); } } break; case Aec3Optimization::kAvx2: SqrtAVX2(x); break; #endif #if defined(WEBRTC_HAS_NEON) case Aec3Optimization::kNeon: { const int x_size = static_cast(x.size()); const int vector_limit = x_size >> 2; int j = 0; for (; j < vector_limit * 4; j += 4) { float32x4_t g = vld1q_f32(&x[j]); #if !defined(WEBRTC_ARCH_ARM64) float32x4_t y = vrsqrteq_f32(g); // Code to handle sqrt(0). // If the input to sqrtf() is zero, a zero will be returned. // If the input to vrsqrteq_f32() is zero, positive infinity is // returned. const uint32x4_t vec_p_inf = vdupq_n_u32(0x7F800000); // check for divide by zero const uint32x4_t div_by_zero = vceqq_u32(vec_p_inf, vreinterpretq_u32_f32(y)); // zero out the positive infinity results y = vreinterpretq_f32_u32( vandq_u32(vmvnq_u32(div_by_zero), vreinterpretq_u32_f32(y))); // from arm documentation // The Newton-Raphson iteration: // y[n+1] = y[n] * (3 - d * (y[n] * y[n])) / 2) // converges to (1/√d) if y0 is the result of VRSQRTE applied to d. // // Note: The precision did not improve after 2 iterations. for (int i = 0; i < 2; i++) { y = vmulq_f32(vrsqrtsq_f32(vmulq_f32(y, y), g), y); } // sqrt(g) = g * 1/sqrt(g) g = vmulq_f32(g, y); #else g = vsqrtq_f32(g); #endif vst1q_f32(&x[j], g); } for (; j < x_size; ++j) { x[j] = sqrtf(x[j]); } } #endif break; default: std::for_each(x.begin(), x.end(), [](float& a) { a = sqrtf(a); }); } } // Elementwise vector multiplication z = x * y. void MultiplyAVX2(rtc::ArrayView x, rtc::ArrayView y, rtc::ArrayView z); void Multiply(rtc::ArrayView x, rtc::ArrayView y, rtc::ArrayView z) { RTC_DCHECK_EQ(z.size(), x.size()); RTC_DCHECK_EQ(z.size(), y.size()); switch (optimization_) { #if defined(WEBRTC_ARCH_X86_FAMILY) case Aec3Optimization::kSse2: { const int x_size = static_cast(x.size()); const int vector_limit = x_size >> 2; int j = 0; for (; j < vector_limit * 4; j += 4) { const __m128 x_j = _mm_loadu_ps(&x[j]); const __m128 y_j = _mm_loadu_ps(&y[j]); const __m128 z_j = _mm_mul_ps(x_j, y_j); _mm_storeu_ps(&z[j], z_j); } for (; j < x_size; ++j) { z[j] = x[j] * y[j]; } } break; case Aec3Optimization::kAvx2: MultiplyAVX2(x, y, z); break; #endif #if defined(WEBRTC_HAS_NEON) case Aec3Optimization::kNeon: { const int x_size = static_cast(x.size()); const int vector_limit = x_size >> 2; int j = 0; for (; j < vector_limit * 4; j += 4) { const float32x4_t x_j = vld1q_f32(&x[j]); const float32x4_t y_j = vld1q_f32(&y[j]); const float32x4_t z_j = vmulq_f32(x_j, y_j); vst1q_f32(&z[j], z_j); } for (; j < x_size; ++j) { z[j] = x[j] * y[j]; } } break; #endif default: std::transform(x.begin(), x.end(), y.begin(), z.begin(), std::multiplies()); } } // Elementwise vector accumulation z += x. void AccumulateAVX2(rtc::ArrayView x, rtc::ArrayView z); void Accumulate(rtc::ArrayView x, rtc::ArrayView z) { RTC_DCHECK_EQ(z.size(), x.size()); switch (optimization_) { #if defined(WEBRTC_ARCH_X86_FAMILY) case Aec3Optimization::kSse2: { const int x_size = static_cast(x.size()); const int vector_limit = x_size >> 2; int j = 0; for (; j < vector_limit * 4; j += 4) { const __m128 x_j = _mm_loadu_ps(&x[j]); __m128 z_j = _mm_loadu_ps(&z[j]); z_j = _mm_add_ps(x_j, z_j); _mm_storeu_ps(&z[j], z_j); } for (; j < x_size; ++j) { z[j] += x[j]; } } break; case Aec3Optimization::kAvx2: AccumulateAVX2(x, z); break; #endif #if defined(WEBRTC_HAS_NEON) case Aec3Optimization::kNeon: { const int x_size = static_cast(x.size()); const int vector_limit = x_size >> 2; int j = 0; for (; j < vector_limit * 4; j += 4) { const float32x4_t x_j = vld1q_f32(&x[j]); float32x4_t z_j = vld1q_f32(&z[j]); z_j = vaddq_f32(z_j, x_j); vst1q_f32(&z[j], z_j); } for (; j < x_size; ++j) { z[j] += x[j]; } } break; #endif default: std::transform(x.begin(), x.end(), z.begin(), z.begin(), std::plus()); } } private: Aec3Optimization optimization_; }; } // namespace aec3 } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC3_VECTOR_MATH_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec3/vector_math_avx2.cc0000664000175000017500000000435414475643423027564 0ustar00arunarun/* * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/vector_math.h" #include #include #include "api/array_view.h" #include "rtc_base/checks.h" namespace webrtc { namespace aec3 { // Elementwise square root. void VectorMath::SqrtAVX2(rtc::ArrayView x) { const int x_size = static_cast(x.size()); const int vector_limit = x_size >> 3; int j = 0; for (; j < vector_limit * 8; j += 8) { __m256 g = _mm256_loadu_ps(&x[j]); g = _mm256_sqrt_ps(g); _mm256_storeu_ps(&x[j], g); } for (; j < x_size; ++j) { x[j] = sqrtf(x[j]); } } // Elementwise vector multiplication z = x * y. void VectorMath::MultiplyAVX2(rtc::ArrayView x, rtc::ArrayView y, rtc::ArrayView z) { RTC_DCHECK_EQ(z.size(), x.size()); RTC_DCHECK_EQ(z.size(), y.size()); const int x_size = static_cast(x.size()); const int vector_limit = x_size >> 3; int j = 0; for (; j < vector_limit * 8; j += 8) { const __m256 x_j = _mm256_loadu_ps(&x[j]); const __m256 y_j = _mm256_loadu_ps(&y[j]); const __m256 z_j = _mm256_mul_ps(x_j, y_j); _mm256_storeu_ps(&z[j], z_j); } for (; j < x_size; ++j) { z[j] = x[j] * y[j]; } } // Elementwise vector accumulation z += x. void VectorMath::AccumulateAVX2(rtc::ArrayView x, rtc::ArrayView z) { RTC_DCHECK_EQ(z.size(), x.size()); const int x_size = static_cast(x.size()); const int vector_limit = x_size >> 3; int j = 0; for (; j < vector_limit * 8; j += 8) { const __m256 x_j = _mm256_loadu_ps(&x[j]); __m256 z_j = _mm256_loadu_ps(&z[j]); z_j = _mm256_add_ps(x_j, z_j); _mm256_storeu_ps(&z[j], z_j); } for (; j < x_size; ++j) { z[j] += x[j]; } } } // namespace aec3 } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec_dump/0000775000175000017500000000000014475643423024736 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec_dump/BUILD.gn0000664000175000017500000000524114475643423026125 0ustar00arunarun# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../../../webrtc.gni") # This contains def of 'rtc_enable_protobuf' rtc_source_set("aec_dump") { visibility = [ "*" ] sources = [ "aec_dump_factory.h" ] deps = [ "..:aec_dump_interface", "../../../rtc_base:rtc_base_approved", "../../../rtc_base/system:file_wrapper", "../../../rtc_base/system:rtc_export", ] } if (rtc_include_tests) { rtc_library("mock_aec_dump") { testonly = true sources = [ "mock_aec_dump.cc", "mock_aec_dump.h", ] deps = [ "..:aec_dump_interface", "..:audioproc_test_utils", "../", "../../../test:test_support", ] } rtc_library("mock_aec_dump_unittests") { testonly = true configs += [ "..:apm_debug_dump" ] sources = [ "aec_dump_integration_test.cc" ] deps = [ ":mock_aec_dump", "..:api", "..:audioproc_test_utils", "../", "../../../rtc_base:rtc_base_approved", "//testing/gtest", ] } } if (rtc_enable_protobuf) { rtc_library("aec_dump_impl") { sources = [ "aec_dump_impl.cc", "aec_dump_impl.h", "capture_stream_info.cc", "capture_stream_info.h", "write_to_file_task.cc", "write_to_file_task.h", ] deps = [ ":aec_dump", "..:aec_dump_interface", "../../../api/audio:audio_frame_api", "../../../api/task_queue", "../../../rtc_base:checks", "../../../rtc_base:ignore_wundef", "../../../rtc_base:protobuf_utils", "../../../rtc_base:rtc_base_approved", "../../../rtc_base:rtc_task_queue", "../../../rtc_base/system:file_wrapper", "../../../system_wrappers", ] deps += [ "../:audioproc_debug_proto" ] } if (rtc_include_tests) { rtc_library("aec_dump_unittests") { testonly = true defines = [] deps = [ ":aec_dump", ":aec_dump_impl", "..:audioproc_debug_proto", "../", "../../../rtc_base:task_queue_for_test", "../../../test:fileutils", "../../../test:test_support", "//testing/gtest", ] sources = [ "aec_dump_unittest.cc" ] } } } rtc_library("null_aec_dump_factory") { assert_no_deps = [ ":aec_dump_impl" ] sources = [ "null_aec_dump_factory.cc" ] deps = [ ":aec_dump", "..:aec_dump_interface", ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec_dump/aec_dump_factory.h0000664000175000017500000000354414475643423030421 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AEC_DUMP_AEC_DUMP_FACTORY_H_ #define MODULES_AUDIO_PROCESSING_AEC_DUMP_AEC_DUMP_FACTORY_H_ #include #include #include "modules/audio_processing/include/aec_dump.h" #include "rtc_base/system/file_wrapper.h" #include "rtc_base/system/rtc_export.h" namespace rtc { class TaskQueue; } // namespace rtc namespace webrtc { class RTC_EXPORT AecDumpFactory { public: // The |worker_queue| may not be null and must outlive the created // AecDump instance. |max_log_size_bytes == -1| means the log size // will be unlimited. |handle| may not be null. The AecDump takes // responsibility for |handle| and closes it in the destructor. A // non-null return value indicates that the file has been // sucessfully opened. static std::unique_ptr Create(webrtc::FileWrapper file, int64_t max_log_size_bytes, rtc::TaskQueue* worker_queue); static std::unique_ptr Create(std::string file_name, int64_t max_log_size_bytes, rtc::TaskQueue* worker_queue); static std::unique_ptr Create(FILE* handle, int64_t max_log_size_bytes, rtc::TaskQueue* worker_queue); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AEC_DUMP_AEC_DUMP_FACTORY_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aec_dump/null_aec_dump_factory.cc0000664000175000017500000000244214475643423031605 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec_dump/aec_dump_factory.h" #include "modules/audio_processing/include/aec_dump.h" namespace webrtc { std::unique_ptr AecDumpFactory::Create(webrtc::FileWrapper file, int64_t max_log_size_bytes, rtc::TaskQueue* worker_queue) { return nullptr; } std::unique_ptr AecDumpFactory::Create(std::string file_name, int64_t max_log_size_bytes, rtc::TaskQueue* worker_queue) { return nullptr; } std::unique_ptr AecDumpFactory::Create(FILE* handle, int64_t max_log_size_bytes, rtc::TaskQueue* worker_queue) { return nullptr; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aecm/0000775000175000017500000000000014475643423024066 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aecm/BUILD.gn0000664000175000017500000000234314475643423025255 0ustar00arunarun# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../../../webrtc.gni") rtc_library("aecm_core") { sources = [ "aecm_core.cc", "aecm_core.h", "aecm_defines.h", "echo_control_mobile.cc", "echo_control_mobile.h", ] deps = [ "../../../common_audio:common_audio_c", "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", "../../../rtc_base:sanitizer", "../../../system_wrappers", "../utility:legacy_delay_estimator", ] cflags = [] if (rtc_build_with_neon) { sources += [ "aecm_core_neon.cc" ] if (current_cpu != "arm64") { # Enable compilation for the NEON instruction set. suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ] cflags += [ "-mfpu=neon" ] } } if (current_cpu == "mipsel") { sources += [ "aecm_core_mips.cc" ] } else { sources += [ "aecm_core_c.cc" ] } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aecm/aecm_core.cc0000664000175000017500000012252314475643423026317 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aecm/aecm_core.h" #include #include #include extern "C" { #include "common_audio/ring_buffer.h" #include "common_audio/signal_processing/include/real_fft.h" } #include "common_audio/signal_processing/include/signal_processing_library.h" #include "modules/audio_processing/aecm/echo_control_mobile.h" #include "modules/audio_processing/utility/delay_estimator_wrapper.h" #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_conversions.h" namespace webrtc { namespace { #ifdef AEC_DEBUG FILE* dfile; FILE* testfile; #endif // Initialization table for echo channel in 8 kHz static const int16_t kChannelStored8kHz[PART_LEN1] = { 2040, 1815, 1590, 1498, 1405, 1395, 1385, 1418, 1451, 1506, 1562, 1644, 1726, 1804, 1882, 1918, 1953, 1982, 2010, 2025, 2040, 2034, 2027, 2021, 2014, 1997, 1980, 1925, 1869, 1800, 1732, 1683, 1635, 1604, 1572, 1545, 1517, 1481, 1444, 1405, 1367, 1331, 1294, 1270, 1245, 1239, 1233, 1247, 1260, 1282, 1303, 1338, 1373, 1407, 1441, 1470, 1499, 1524, 1549, 1565, 1582, 1601, 1621, 1649, 1676}; // Initialization table for echo channel in 16 kHz static const int16_t kChannelStored16kHz[PART_LEN1] = { 2040, 1590, 1405, 1385, 1451, 1562, 1726, 1882, 1953, 2010, 2040, 2027, 2014, 1980, 1869, 1732, 1635, 1572, 1517, 1444, 1367, 1294, 1245, 1233, 1260, 1303, 1373, 1441, 1499, 1549, 1582, 1621, 1676, 1741, 1802, 1861, 1921, 1983, 2040, 2102, 2170, 2265, 2375, 2515, 2651, 2781, 2922, 3075, 3253, 3471, 3738, 3976, 4151, 4258, 4308, 4288, 4270, 4253, 4237, 4179, 4086, 3947, 3757, 3484, 3153}; } // namespace const int16_t WebRtcAecm_kCosTable[] = { 8192, 8190, 8187, 8180, 8172, 8160, 8147, 8130, 8112, 8091, 8067, 8041, 8012, 7982, 7948, 7912, 7874, 7834, 7791, 7745, 7697, 7647, 7595, 7540, 7483, 7424, 7362, 7299, 7233, 7164, 7094, 7021, 6947, 6870, 6791, 6710, 6627, 6542, 6455, 6366, 6275, 6182, 6087, 5991, 5892, 5792, 5690, 5586, 5481, 5374, 5265, 5155, 5043, 4930, 4815, 4698, 4580, 4461, 4341, 4219, 4096, 3971, 3845, 3719, 3591, 3462, 3331, 3200, 3068, 2935, 2801, 2667, 2531, 2395, 2258, 2120, 1981, 1842, 1703, 1563, 1422, 1281, 1140, 998, 856, 713, 571, 428, 285, 142, 0, -142, -285, -428, -571, -713, -856, -998, -1140, -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395, -2531, -2667, -2801, -2935, -3068, -3200, -3331, -3462, -3591, -3719, -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698, -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586, -5690, -5792, -5892, -5991, -6087, -6182, -6275, -6366, -6455, -6542, -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164, -7233, -7299, -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745, -7791, -7834, -7874, -7912, -7948, -7982, -8012, -8041, -8067, -8091, -8112, -8130, -8147, -8160, -8172, -8180, -8187, -8190, -8191, -8190, -8187, -8180, -8172, -8160, -8147, -8130, -8112, -8091, -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834, -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362, -7299, -7233, -7164, -7094, -7021, -6947, -6870, -6791, -6710, -6627, -6542, -6455, -6366, -6275, -6182, -6087, -5991, -5892, -5792, -5690, -5586, -5481, -5374, -5265, -5155, -5043, -4930, -4815, -4698, -4580, -4461, -4341, -4219, -4096, -3971, -3845, -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801, -2667, -2531, -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422, -1281, -1140, -998, -856, -713, -571, -428, -285, -142, 0, 142, 285, 428, 571, 713, 856, 998, 1140, 1281, 1422, 1563, 1703, 1842, 1981, 2120, 2258, 2395, 2531, 2667, 2801, 2935, 3068, 3200, 3331, 3462, 3591, 3719, 3845, 3971, 4095, 4219, 4341, 4461, 4580, 4698, 4815, 4930, 5043, 5155, 5265, 5374, 5481, 5586, 5690, 5792, 5892, 5991, 6087, 6182, 6275, 6366, 6455, 6542, 6627, 6710, 6791, 6870, 6947, 7021, 7094, 7164, 7233, 7299, 7362, 7424, 7483, 7540, 7595, 7647, 7697, 7745, 7791, 7834, 7874, 7912, 7948, 7982, 8012, 8041, 8067, 8091, 8112, 8130, 8147, 8160, 8172, 8180, 8187, 8190}; const int16_t WebRtcAecm_kSinTable[] = { 0, 142, 285, 428, 571, 713, 856, 998, 1140, 1281, 1422, 1563, 1703, 1842, 1981, 2120, 2258, 2395, 2531, 2667, 2801, 2935, 3068, 3200, 3331, 3462, 3591, 3719, 3845, 3971, 4095, 4219, 4341, 4461, 4580, 4698, 4815, 4930, 5043, 5155, 5265, 5374, 5481, 5586, 5690, 5792, 5892, 5991, 6087, 6182, 6275, 6366, 6455, 6542, 6627, 6710, 6791, 6870, 6947, 7021, 7094, 7164, 7233, 7299, 7362, 7424, 7483, 7540, 7595, 7647, 7697, 7745, 7791, 7834, 7874, 7912, 7948, 7982, 8012, 8041, 8067, 8091, 8112, 8130, 8147, 8160, 8172, 8180, 8187, 8190, 8191, 8190, 8187, 8180, 8172, 8160, 8147, 8130, 8112, 8091, 8067, 8041, 8012, 7982, 7948, 7912, 7874, 7834, 7791, 7745, 7697, 7647, 7595, 7540, 7483, 7424, 7362, 7299, 7233, 7164, 7094, 7021, 6947, 6870, 6791, 6710, 6627, 6542, 6455, 6366, 6275, 6182, 6087, 5991, 5892, 5792, 5690, 5586, 5481, 5374, 5265, 5155, 5043, 4930, 4815, 4698, 4580, 4461, 4341, 4219, 4096, 3971, 3845, 3719, 3591, 3462, 3331, 3200, 3068, 2935, 2801, 2667, 2531, 2395, 2258, 2120, 1981, 1842, 1703, 1563, 1422, 1281, 1140, 998, 856, 713, 571, 428, 285, 142, 0, -142, -285, -428, -571, -713, -856, -998, -1140, -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395, -2531, -2667, -2801, -2935, -3068, -3200, -3331, -3462, -3591, -3719, -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698, -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586, -5690, -5792, -5892, -5991, -6087, -6182, -6275, -6366, -6455, -6542, -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164, -7233, -7299, -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745, -7791, -7834, -7874, -7912, -7948, -7982, -8012, -8041, -8067, -8091, -8112, -8130, -8147, -8160, -8172, -8180, -8187, -8190, -8191, -8190, -8187, -8180, -8172, -8160, -8147, -8130, -8112, -8091, -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834, -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362, -7299, -7233, -7164, -7094, -7021, -6947, -6870, -6791, -6710, -6627, -6542, -6455, -6366, -6275, -6182, -6087, -5991, -5892, -5792, -5690, -5586, -5481, -5374, -5265, -5155, -5043, -4930, -4815, -4698, -4580, -4461, -4341, -4219, -4096, -3971, -3845, -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801, -2667, -2531, -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422, -1281, -1140, -998, -856, -713, -571, -428, -285, -142}; // Moves the pointer to the next entry and inserts |far_spectrum| and // corresponding Q-domain in its buffer. // // Inputs: // - self : Pointer to the delay estimation instance // - far_spectrum : Pointer to the far end spectrum // - far_q : Q-domain of far end spectrum // void WebRtcAecm_UpdateFarHistory(AecmCore* self, uint16_t* far_spectrum, int far_q) { // Get new buffer position self->far_history_pos++; if (self->far_history_pos >= MAX_DELAY) { self->far_history_pos = 0; } // Update Q-domain buffer self->far_q_domains[self->far_history_pos] = far_q; // Update far end spectrum buffer memcpy(&(self->far_history[self->far_history_pos * PART_LEN1]), far_spectrum, sizeof(uint16_t) * PART_LEN1); } // Returns a pointer to the far end spectrum aligned to current near end // spectrum. The function WebRtc_DelayEstimatorProcessFix(...) should have been // called before AlignedFarend(...). Otherwise, you get the pointer to the // previous frame. The memory is only valid until the next call of // WebRtc_DelayEstimatorProcessFix(...). // // Inputs: // - self : Pointer to the AECM instance. // - delay : Current delay estimate. // // Output: // - far_q : The Q-domain of the aligned far end spectrum // // Return value: // - far_spectrum : Pointer to the aligned far end spectrum // NULL - Error // const uint16_t* WebRtcAecm_AlignedFarend(AecmCore* self, int* far_q, int delay) { int buffer_position = 0; RTC_DCHECK(self); buffer_position = self->far_history_pos - delay; // Check buffer position if (buffer_position < 0) { buffer_position += MAX_DELAY; } // Get Q-domain *far_q = self->far_q_domains[buffer_position]; // Return far end spectrum return &(self->far_history[buffer_position * PART_LEN1]); } // Declare function pointers. CalcLinearEnergies WebRtcAecm_CalcLinearEnergies; StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel; ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel; AecmCore* WebRtcAecm_CreateCore() { // Allocate zero-filled memory. AecmCore* aecm = static_cast(calloc(1, sizeof(AecmCore))); aecm->farFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(int16_t)); if (!aecm->farFrameBuf) { WebRtcAecm_FreeCore(aecm); return NULL; } aecm->nearNoisyFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(int16_t)); if (!aecm->nearNoisyFrameBuf) { WebRtcAecm_FreeCore(aecm); return NULL; } aecm->nearCleanFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(int16_t)); if (!aecm->nearCleanFrameBuf) { WebRtcAecm_FreeCore(aecm); return NULL; } aecm->outFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(int16_t)); if (!aecm->outFrameBuf) { WebRtcAecm_FreeCore(aecm); return NULL; } aecm->delay_estimator_farend = WebRtc_CreateDelayEstimatorFarend(PART_LEN1, MAX_DELAY); if (aecm->delay_estimator_farend == NULL) { WebRtcAecm_FreeCore(aecm); return NULL; } aecm->delay_estimator = WebRtc_CreateDelayEstimator(aecm->delay_estimator_farend, 0); if (aecm->delay_estimator == NULL) { WebRtcAecm_FreeCore(aecm); return NULL; } // TODO(bjornv): Explicitly disable robust delay validation until no // performance regression has been established. Then remove the line. WebRtc_enable_robust_validation(aecm->delay_estimator, 0); aecm->real_fft = WebRtcSpl_CreateRealFFT(PART_LEN_SHIFT); if (aecm->real_fft == NULL) { WebRtcAecm_FreeCore(aecm); return NULL; } // Init some aecm pointers. 16 and 32 byte alignment is only necessary // for Neon code currently. aecm->xBuf = (int16_t*)(((uintptr_t)aecm->xBuf_buf + 31) & ~31); aecm->dBufClean = (int16_t*)(((uintptr_t)aecm->dBufClean_buf + 31) & ~31); aecm->dBufNoisy = (int16_t*)(((uintptr_t)aecm->dBufNoisy_buf + 31) & ~31); aecm->outBuf = (int16_t*)(((uintptr_t)aecm->outBuf_buf + 15) & ~15); aecm->channelStored = (int16_t*)(((uintptr_t)aecm->channelStored_buf + 15) & ~15); aecm->channelAdapt16 = (int16_t*)(((uintptr_t)aecm->channelAdapt16_buf + 15) & ~15); aecm->channelAdapt32 = (int32_t*)(((uintptr_t)aecm->channelAdapt32_buf + 31) & ~31); return aecm; } void WebRtcAecm_InitEchoPathCore(AecmCore* aecm, const int16_t* echo_path) { int i = 0; // Reset the stored channel memcpy(aecm->channelStored, echo_path, sizeof(int16_t) * PART_LEN1); // Reset the adapted channels memcpy(aecm->channelAdapt16, echo_path, sizeof(int16_t) * PART_LEN1); for (i = 0; i < PART_LEN1; i++) { aecm->channelAdapt32[i] = (int32_t)aecm->channelAdapt16[i] << 16; } // Reset channel storing variables aecm->mseAdaptOld = 1000; aecm->mseStoredOld = 1000; aecm->mseThreshold = WEBRTC_SPL_WORD32_MAX; aecm->mseChannelCount = 0; } static void CalcLinearEnergiesC(AecmCore* aecm, const uint16_t* far_spectrum, int32_t* echo_est, uint32_t* far_energy, uint32_t* echo_energy_adapt, uint32_t* echo_energy_stored) { int i; // Get energy for the delayed far end signal and estimated // echo using both stored and adapted channels. for (i = 0; i < PART_LEN1; i++) { echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]); (*far_energy) += (uint32_t)(far_spectrum[i]); *echo_energy_adapt += aecm->channelAdapt16[i] * far_spectrum[i]; (*echo_energy_stored) += (uint32_t)echo_est[i]; } } static void StoreAdaptiveChannelC(AecmCore* aecm, const uint16_t* far_spectrum, int32_t* echo_est) { int i; // During startup we store the channel every block. memcpy(aecm->channelStored, aecm->channelAdapt16, sizeof(int16_t) * PART_LEN1); // Recalculate echo estimate for (i = 0; i < PART_LEN; i += 4) { echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]); echo_est[i + 1] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1], far_spectrum[i + 1]); echo_est[i + 2] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2], far_spectrum[i + 2]); echo_est[i + 3] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3], far_spectrum[i + 3]); } echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]); } static void ResetAdaptiveChannelC(AecmCore* aecm) { int i; // The stored channel has a significantly lower MSE than the adaptive one for // two consecutive calculations. Reset the adaptive channel. memcpy(aecm->channelAdapt16, aecm->channelStored, sizeof(int16_t) * PART_LEN1); // Restore the W32 channel for (i = 0; i < PART_LEN; i += 4) { aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16; aecm->channelAdapt32[i + 1] = (int32_t)aecm->channelStored[i + 1] << 16; aecm->channelAdapt32[i + 2] = (int32_t)aecm->channelStored[i + 2] << 16; aecm->channelAdapt32[i + 3] = (int32_t)aecm->channelStored[i + 3] << 16; } aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16; } // Initialize function pointers for ARM Neon platform. #if defined(WEBRTC_HAS_NEON) static void WebRtcAecm_InitNeon(void) { WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannelNeon; WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannelNeon; WebRtcAecm_CalcLinearEnergies = WebRtcAecm_CalcLinearEnergiesNeon; } #endif // Initialize function pointers for MIPS platform. #if defined(MIPS32_LE) static void WebRtcAecm_InitMips(void) { #if defined(MIPS_DSP_R1_LE) WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannel_mips; WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannel_mips; #endif WebRtcAecm_CalcLinearEnergies = WebRtcAecm_CalcLinearEnergies_mips; } #endif // WebRtcAecm_InitCore(...) // // This function initializes the AECM instant created with // WebRtcAecm_CreateCore(...) Input: // - aecm : Pointer to the Echo Suppression instance // - samplingFreq : Sampling Frequency // // Output: // - aecm : Initialized instance // // Return value : 0 - Ok // -1 - Error // int WebRtcAecm_InitCore(AecmCore* const aecm, int samplingFreq) { int i = 0; int32_t tmp32 = PART_LEN1 * PART_LEN1; int16_t tmp16 = PART_LEN1; if (samplingFreq != 8000 && samplingFreq != 16000) { samplingFreq = 8000; return -1; } // sanity check of sampling frequency aecm->mult = (int16_t)samplingFreq / 8000; aecm->farBufWritePos = 0; aecm->farBufReadPos = 0; aecm->knownDelay = 0; aecm->lastKnownDelay = 0; WebRtc_InitBuffer(aecm->farFrameBuf); WebRtc_InitBuffer(aecm->nearNoisyFrameBuf); WebRtc_InitBuffer(aecm->nearCleanFrameBuf); WebRtc_InitBuffer(aecm->outFrameBuf); memset(aecm->xBuf_buf, 0, sizeof(aecm->xBuf_buf)); memset(aecm->dBufClean_buf, 0, sizeof(aecm->dBufClean_buf)); memset(aecm->dBufNoisy_buf, 0, sizeof(aecm->dBufNoisy_buf)); memset(aecm->outBuf_buf, 0, sizeof(aecm->outBuf_buf)); aecm->seed = 666; aecm->totCount = 0; if (WebRtc_InitDelayEstimatorFarend(aecm->delay_estimator_farend) != 0) { return -1; } if (WebRtc_InitDelayEstimator(aecm->delay_estimator) != 0) { return -1; } // Set far end histories to zero memset(aecm->far_history, 0, sizeof(uint16_t) * PART_LEN1 * MAX_DELAY); memset(aecm->far_q_domains, 0, sizeof(int) * MAX_DELAY); aecm->far_history_pos = MAX_DELAY; aecm->nlpFlag = 1; aecm->fixedDelay = -1; aecm->dfaCleanQDomain = 0; aecm->dfaCleanQDomainOld = 0; aecm->dfaNoisyQDomain = 0; aecm->dfaNoisyQDomainOld = 0; memset(aecm->nearLogEnergy, 0, sizeof(aecm->nearLogEnergy)); aecm->farLogEnergy = 0; memset(aecm->echoAdaptLogEnergy, 0, sizeof(aecm->echoAdaptLogEnergy)); memset(aecm->echoStoredLogEnergy, 0, sizeof(aecm->echoStoredLogEnergy)); // Initialize the echo channels with a stored shape. if (samplingFreq == 8000) { WebRtcAecm_InitEchoPathCore(aecm, kChannelStored8kHz); } else { WebRtcAecm_InitEchoPathCore(aecm, kChannelStored16kHz); } memset(aecm->echoFilt, 0, sizeof(aecm->echoFilt)); memset(aecm->nearFilt, 0, sizeof(aecm->nearFilt)); aecm->noiseEstCtr = 0; aecm->cngMode = AecmTrue; memset(aecm->noiseEstTooLowCtr, 0, sizeof(aecm->noiseEstTooLowCtr)); memset(aecm->noiseEstTooHighCtr, 0, sizeof(aecm->noiseEstTooHighCtr)); // Shape the initial noise level to an approximate pink noise. for (i = 0; i < (PART_LEN1 >> 1) - 1; i++) { aecm->noiseEst[i] = (tmp32 << 8); tmp16--; tmp32 -= (int32_t)((tmp16 << 1) + 1); } for (; i < PART_LEN1; i++) { aecm->noiseEst[i] = (tmp32 << 8); } aecm->farEnergyMin = WEBRTC_SPL_WORD16_MAX; aecm->farEnergyMax = WEBRTC_SPL_WORD16_MIN; aecm->farEnergyMaxMin = 0; aecm->farEnergyVAD = FAR_ENERGY_MIN; // This prevents false speech detection // at the beginning. aecm->farEnergyMSE = 0; aecm->currentVADValue = 0; aecm->vadUpdateCount = 0; aecm->firstVAD = 1; aecm->startupState = 0; aecm->supGain = SUPGAIN_DEFAULT; aecm->supGainOld = SUPGAIN_DEFAULT; aecm->supGainErrParamA = SUPGAIN_ERROR_PARAM_A; aecm->supGainErrParamD = SUPGAIN_ERROR_PARAM_D; aecm->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B; aecm->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D; // Assert a preprocessor definition at compile-time. It's an assumption // used in assembly code, so check the assembly files before any change. static_assert(PART_LEN % 16 == 0, "PART_LEN is not a multiple of 16"); // Initialize function pointers. WebRtcAecm_CalcLinearEnergies = CalcLinearEnergiesC; WebRtcAecm_StoreAdaptiveChannel = StoreAdaptiveChannelC; WebRtcAecm_ResetAdaptiveChannel = ResetAdaptiveChannelC; #if defined(WEBRTC_HAS_NEON) WebRtcAecm_InitNeon(); #endif #if defined(MIPS32_LE) WebRtcAecm_InitMips(); #endif return 0; } // TODO(bjornv): This function is currently not used. Add support for these // parameters from a higher level int WebRtcAecm_Control(AecmCore* aecm, int delay, int nlpFlag) { aecm->nlpFlag = nlpFlag; aecm->fixedDelay = delay; return 0; } void WebRtcAecm_FreeCore(AecmCore* aecm) { if (aecm == NULL) { return; } WebRtc_FreeBuffer(aecm->farFrameBuf); WebRtc_FreeBuffer(aecm->nearNoisyFrameBuf); WebRtc_FreeBuffer(aecm->nearCleanFrameBuf); WebRtc_FreeBuffer(aecm->outFrameBuf); WebRtc_FreeDelayEstimator(aecm->delay_estimator); WebRtc_FreeDelayEstimatorFarend(aecm->delay_estimator_farend); WebRtcSpl_FreeRealFFT(aecm->real_fft); free(aecm); } int WebRtcAecm_ProcessFrame(AecmCore* aecm, const int16_t* farend, const int16_t* nearendNoisy, const int16_t* nearendClean, int16_t* out) { int16_t outBlock_buf[PART_LEN + 8]; // Align buffer to 8-byte boundary. int16_t* outBlock = (int16_t*)(((uintptr_t)outBlock_buf + 15) & ~15); int16_t farFrame[FRAME_LEN]; const int16_t* out_ptr = NULL; int size = 0; // Buffer the current frame. // Fetch an older one corresponding to the delay. WebRtcAecm_BufferFarFrame(aecm, farend, FRAME_LEN); WebRtcAecm_FetchFarFrame(aecm, farFrame, FRAME_LEN, aecm->knownDelay); // Buffer the synchronized far and near frames, // to pass the smaller blocks individually. WebRtc_WriteBuffer(aecm->farFrameBuf, farFrame, FRAME_LEN); WebRtc_WriteBuffer(aecm->nearNoisyFrameBuf, nearendNoisy, FRAME_LEN); if (nearendClean != NULL) { WebRtc_WriteBuffer(aecm->nearCleanFrameBuf, nearendClean, FRAME_LEN); } // Process as many blocks as possible. while (WebRtc_available_read(aecm->farFrameBuf) >= PART_LEN) { int16_t far_block[PART_LEN]; const int16_t* far_block_ptr = NULL; int16_t near_noisy_block[PART_LEN]; const int16_t* near_noisy_block_ptr = NULL; WebRtc_ReadBuffer(aecm->farFrameBuf, (void**)&far_block_ptr, far_block, PART_LEN); WebRtc_ReadBuffer(aecm->nearNoisyFrameBuf, (void**)&near_noisy_block_ptr, near_noisy_block, PART_LEN); if (nearendClean != NULL) { int16_t near_clean_block[PART_LEN]; const int16_t* near_clean_block_ptr = NULL; WebRtc_ReadBuffer(aecm->nearCleanFrameBuf, (void**)&near_clean_block_ptr, near_clean_block, PART_LEN); if (WebRtcAecm_ProcessBlock(aecm, far_block_ptr, near_noisy_block_ptr, near_clean_block_ptr, outBlock) == -1) { return -1; } } else { if (WebRtcAecm_ProcessBlock(aecm, far_block_ptr, near_noisy_block_ptr, NULL, outBlock) == -1) { return -1; } } WebRtc_WriteBuffer(aecm->outFrameBuf, outBlock, PART_LEN); } // Stuff the out buffer if we have less than a frame to output. // This should only happen for the first frame. size = (int)WebRtc_available_read(aecm->outFrameBuf); if (size < FRAME_LEN) { WebRtc_MoveReadPtr(aecm->outFrameBuf, size - FRAME_LEN); } // Obtain an output frame. WebRtc_ReadBuffer(aecm->outFrameBuf, (void**)&out_ptr, out, FRAME_LEN); if (out_ptr != out) { // ReadBuffer() hasn't copied to |out| in this case. memcpy(out, out_ptr, FRAME_LEN * sizeof(int16_t)); } return 0; } // WebRtcAecm_AsymFilt(...) // // Performs asymmetric filtering. // // Inputs: // - filtOld : Previous filtered value. // - inVal : New input value. // - stepSizePos : Step size when we have a positive contribution. // - stepSizeNeg : Step size when we have a negative contribution. // // Output: // // Return: - Filtered value. // int16_t WebRtcAecm_AsymFilt(const int16_t filtOld, const int16_t inVal, const int16_t stepSizePos, const int16_t stepSizeNeg) { int16_t retVal; if ((filtOld == WEBRTC_SPL_WORD16_MAX) | (filtOld == WEBRTC_SPL_WORD16_MIN)) { return inVal; } retVal = filtOld; if (filtOld > inVal) { retVal -= (filtOld - inVal) >> stepSizeNeg; } else { retVal += (inVal - filtOld) >> stepSizePos; } return retVal; } // ExtractFractionPart(a, zeros) // // returns the fraction part of |a|, with |zeros| number of leading zeros, as an // int16_t scaled to Q8. There is no sanity check of |a| in the sense that the // number of zeros match. static int16_t ExtractFractionPart(uint32_t a, int zeros) { return (int16_t)(((a << zeros) & 0x7FFFFFFF) >> 23); } // Calculates and returns the log of |energy| in Q8. The input |energy| is // supposed to be in Q(|q_domain|). static int16_t LogOfEnergyInQ8(uint32_t energy, int q_domain) { static const int16_t kLogLowValue = PART_LEN_SHIFT << 7; int16_t log_energy_q8 = kLogLowValue; if (energy > 0) { int zeros = WebRtcSpl_NormU32(energy); int16_t frac = ExtractFractionPart(energy, zeros); // log2 of |energy| in Q8. log_energy_q8 += ((31 - zeros) << 8) + frac - (q_domain << 8); } return log_energy_q8; } // WebRtcAecm_CalcEnergies(...) // // This function calculates the log of energies for nearend, farend and // estimated echoes. There is also an update of energy decision levels, i.e. // internal VAD. // // // @param aecm [i/o] Handle of the AECM instance. // @param far_spectrum [in] Pointer to farend spectrum. // @param far_q [in] Q-domain of farend spectrum. // @param nearEner [in] Near end energy for current block in // Q(aecm->dfaQDomain). // @param echoEst [out] Estimated echo in Q(xfa_q+RESOLUTION_CHANNEL16). // void WebRtcAecm_CalcEnergies(AecmCore* aecm, const uint16_t* far_spectrum, const int16_t far_q, const uint32_t nearEner, int32_t* echoEst) { // Local variables uint32_t tmpAdapt = 0; uint32_t tmpStored = 0; uint32_t tmpFar = 0; int i; int16_t tmp16; int16_t increase_max_shifts = 4; int16_t decrease_max_shifts = 11; int16_t increase_min_shifts = 11; int16_t decrease_min_shifts = 3; // Get log of near end energy and store in buffer // Shift buffer memmove(aecm->nearLogEnergy + 1, aecm->nearLogEnergy, sizeof(int16_t) * (MAX_BUF_LEN - 1)); // Logarithm of integrated magnitude spectrum (nearEner) aecm->nearLogEnergy[0] = LogOfEnergyInQ8(nearEner, aecm->dfaNoisyQDomain); WebRtcAecm_CalcLinearEnergies(aecm, far_spectrum, echoEst, &tmpFar, &tmpAdapt, &tmpStored); // Shift buffers memmove(aecm->echoAdaptLogEnergy + 1, aecm->echoAdaptLogEnergy, sizeof(int16_t) * (MAX_BUF_LEN - 1)); memmove(aecm->echoStoredLogEnergy + 1, aecm->echoStoredLogEnergy, sizeof(int16_t) * (MAX_BUF_LEN - 1)); // Logarithm of delayed far end energy aecm->farLogEnergy = LogOfEnergyInQ8(tmpFar, far_q); // Logarithm of estimated echo energy through adapted channel aecm->echoAdaptLogEnergy[0] = LogOfEnergyInQ8(tmpAdapt, RESOLUTION_CHANNEL16 + far_q); // Logarithm of estimated echo energy through stored channel aecm->echoStoredLogEnergy[0] = LogOfEnergyInQ8(tmpStored, RESOLUTION_CHANNEL16 + far_q); // Update farend energy levels (min, max, vad, mse) if (aecm->farLogEnergy > FAR_ENERGY_MIN) { if (aecm->startupState == 0) { increase_max_shifts = 2; decrease_min_shifts = 2; increase_min_shifts = 8; } aecm->farEnergyMin = WebRtcAecm_AsymFilt(aecm->farEnergyMin, aecm->farLogEnergy, increase_min_shifts, decrease_min_shifts); aecm->farEnergyMax = WebRtcAecm_AsymFilt(aecm->farEnergyMax, aecm->farLogEnergy, increase_max_shifts, decrease_max_shifts); aecm->farEnergyMaxMin = (aecm->farEnergyMax - aecm->farEnergyMin); // Dynamic VAD region size tmp16 = 2560 - aecm->farEnergyMin; if (tmp16 > 0) { tmp16 = (int16_t)((tmp16 * FAR_ENERGY_VAD_REGION) >> 9); } else { tmp16 = 0; } tmp16 += FAR_ENERGY_VAD_REGION; if ((aecm->startupState == 0) | (aecm->vadUpdateCount > 1024)) { // In startup phase or VAD update halted aecm->farEnergyVAD = aecm->farEnergyMin + tmp16; } else { if (aecm->farEnergyVAD > aecm->farLogEnergy) { aecm->farEnergyVAD += (aecm->farLogEnergy + tmp16 - aecm->farEnergyVAD) >> 6; aecm->vadUpdateCount = 0; } else { aecm->vadUpdateCount++; } } // Put MSE threshold higher than VAD aecm->farEnergyMSE = aecm->farEnergyVAD + (1 << 8); } // Update VAD variables if (aecm->farLogEnergy > aecm->farEnergyVAD) { if ((aecm->startupState == 0) | (aecm->farEnergyMaxMin > FAR_ENERGY_DIFF)) { // We are in startup or have significant dynamics in input speech level aecm->currentVADValue = 1; } } else { aecm->currentVADValue = 0; } if ((aecm->currentVADValue) && (aecm->firstVAD)) { aecm->firstVAD = 0; if (aecm->echoAdaptLogEnergy[0] > aecm->nearLogEnergy[0]) { // The estimated echo has higher energy than the near end signal. // This means that the initialization was too aggressive. Scale // down by a factor 8 for (i = 0; i < PART_LEN1; i++) { aecm->channelAdapt16[i] >>= 3; } // Compensate the adapted echo energy level accordingly. aecm->echoAdaptLogEnergy[0] -= (3 << 8); aecm->firstVAD = 1; } } } // WebRtcAecm_CalcStepSize(...) // // This function calculates the step size used in channel estimation // // // @param aecm [in] Handle of the AECM instance. // @param mu [out] (Return value) Stepsize in log2(), i.e. number of // shifts. // // int16_t WebRtcAecm_CalcStepSize(AecmCore* const aecm) { int32_t tmp32; int16_t tmp16; int16_t mu = MU_MAX; // Here we calculate the step size mu used in the // following NLMS based Channel estimation algorithm if (!aecm->currentVADValue) { // Far end energy level too low, no channel update mu = 0; } else if (aecm->startupState > 0) { if (aecm->farEnergyMin >= aecm->farEnergyMax) { mu = MU_MIN; } else { tmp16 = (aecm->farLogEnergy - aecm->farEnergyMin); tmp32 = tmp16 * MU_DIFF; tmp32 = WebRtcSpl_DivW32W16(tmp32, aecm->farEnergyMaxMin); mu = MU_MIN - 1 - (int16_t)(tmp32); // The -1 is an alternative to rounding. This way we get a larger // stepsize, so we in some sense compensate for truncation in NLMS } if (mu < MU_MAX) { mu = MU_MAX; // Equivalent with maximum step size of 2^-MU_MAX } } return mu; } // WebRtcAecm_UpdateChannel(...) // // This function performs channel estimation. NLMS and decision on channel // storage. // // // @param aecm [i/o] Handle of the AECM instance. // @param far_spectrum [in] Absolute value of the farend signal in Q(far_q) // @param far_q [in] Q-domain of the farend signal // @param dfa [in] Absolute value of the nearend signal // (Q[aecm->dfaQDomain]) // @param mu [in] NLMS step size. // @param echoEst [i/o] Estimated echo in Q(far_q+RESOLUTION_CHANNEL16). // void WebRtcAecm_UpdateChannel(AecmCore* aecm, const uint16_t* far_spectrum, const int16_t far_q, const uint16_t* const dfa, const int16_t mu, int32_t* echoEst) { uint32_t tmpU32no1, tmpU32no2; int32_t tmp32no1, tmp32no2; int32_t mseStored; int32_t mseAdapt; int i; int16_t zerosFar, zerosNum, zerosCh, zerosDfa; int16_t shiftChFar, shiftNum, shift2ResChan; int16_t tmp16no1; int16_t xfaQ, dfaQ; // This is the channel estimation algorithm. It is base on NLMS but has a // variable step length, which was calculated above. if (mu) { for (i = 0; i < PART_LEN1; i++) { // Determine norm of channel and farend to make sure we don't get overflow // in multiplication zerosCh = WebRtcSpl_NormU32(aecm->channelAdapt32[i]); zerosFar = WebRtcSpl_NormU32((uint32_t)far_spectrum[i]); if (zerosCh + zerosFar > 31) { // Multiplication is safe tmpU32no1 = WEBRTC_SPL_UMUL_32_16(aecm->channelAdapt32[i], far_spectrum[i]); shiftChFar = 0; } else { // We need to shift down before multiplication shiftChFar = 32 - zerosCh - zerosFar; // If zerosCh == zerosFar == 0, shiftChFar is 32. A // right shift of 32 is undefined. To avoid that, we // do this check. tmpU32no1 = rtc::dchecked_cast( shiftChFar >= 32 ? 0 : aecm->channelAdapt32[i] >> shiftChFar) * far_spectrum[i]; } // Determine Q-domain of numerator zerosNum = WebRtcSpl_NormU32(tmpU32no1); if (dfa[i]) { zerosDfa = WebRtcSpl_NormU32((uint32_t)dfa[i]); } else { zerosDfa = 32; } tmp16no1 = zerosDfa - 2 + aecm->dfaNoisyQDomain - RESOLUTION_CHANNEL32 - far_q + shiftChFar; if (zerosNum > tmp16no1 + 1) { xfaQ = tmp16no1; dfaQ = zerosDfa - 2; } else { xfaQ = zerosNum - 2; dfaQ = RESOLUTION_CHANNEL32 + far_q - aecm->dfaNoisyQDomain - shiftChFar + xfaQ; } // Add in the same Q-domain tmpU32no1 = WEBRTC_SPL_SHIFT_W32(tmpU32no1, xfaQ); tmpU32no2 = WEBRTC_SPL_SHIFT_W32((uint32_t)dfa[i], dfaQ); tmp32no1 = (int32_t)tmpU32no2 - (int32_t)tmpU32no1; zerosNum = WebRtcSpl_NormW32(tmp32no1); if ((tmp32no1) && (far_spectrum[i] > (CHANNEL_VAD << far_q))) { // // Update is needed // // This is what we would like to compute // // tmp32no1 = dfa[i] - (aecm->channelAdapt[i] * far_spectrum[i]) // tmp32norm = (i + 1) // aecm->channelAdapt[i] += (2^mu) * tmp32no1 // / (tmp32norm * far_spectrum[i]) // // Make sure we don't get overflow in multiplication. if (zerosNum + zerosFar > 31) { if (tmp32no1 > 0) { tmp32no2 = (int32_t)WEBRTC_SPL_UMUL_32_16(tmp32no1, far_spectrum[i]); } else { tmp32no2 = -(int32_t)WEBRTC_SPL_UMUL_32_16(-tmp32no1, far_spectrum[i]); } shiftNum = 0; } else { shiftNum = 32 - (zerosNum + zerosFar); if (tmp32no1 > 0) { tmp32no2 = (tmp32no1 >> shiftNum) * far_spectrum[i]; } else { tmp32no2 = -((-tmp32no1 >> shiftNum) * far_spectrum[i]); } } // Normalize with respect to frequency bin tmp32no2 = WebRtcSpl_DivW32W16(tmp32no2, i + 1); // Make sure we are in the right Q-domain shift2ResChan = shiftNum + shiftChFar - xfaQ - mu - ((30 - zerosFar) << 1); if (WebRtcSpl_NormW32(tmp32no2) < shift2ResChan) { tmp32no2 = WEBRTC_SPL_WORD32_MAX; } else { tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, shift2ResChan); } aecm->channelAdapt32[i] = WebRtcSpl_AddSatW32(aecm->channelAdapt32[i], tmp32no2); if (aecm->channelAdapt32[i] < 0) { // We can never have negative channel gain aecm->channelAdapt32[i] = 0; } aecm->channelAdapt16[i] = (int16_t)(aecm->channelAdapt32[i] >> 16); } } } // END: Adaptive channel update // Determine if we should store or restore the channel if ((aecm->startupState == 0) & (aecm->currentVADValue)) { // During startup we store the channel every block, // and we recalculate echo estimate WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst); } else { if (aecm->farLogEnergy < aecm->farEnergyMSE) { aecm->mseChannelCount = 0; } else { aecm->mseChannelCount++; } // Enough data for validation. Store channel if we can. if (aecm->mseChannelCount >= (MIN_MSE_COUNT + 10)) { // We have enough data. // Calculate MSE of "Adapt" and "Stored" versions. // It is actually not MSE, but average absolute error. mseStored = 0; mseAdapt = 0; for (i = 0; i < MIN_MSE_COUNT; i++) { tmp32no1 = ((int32_t)aecm->echoStoredLogEnergy[i] - (int32_t)aecm->nearLogEnergy[i]); tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1); mseStored += tmp32no2; tmp32no1 = ((int32_t)aecm->echoAdaptLogEnergy[i] - (int32_t)aecm->nearLogEnergy[i]); tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1); mseAdapt += tmp32no2; } if (((mseStored << MSE_RESOLUTION) < (MIN_MSE_DIFF * mseAdapt)) & ((aecm->mseStoredOld << MSE_RESOLUTION) < (MIN_MSE_DIFF * aecm->mseAdaptOld))) { // The stored channel has a significantly lower MSE than the adaptive // one for two consecutive calculations. Reset the adaptive channel. WebRtcAecm_ResetAdaptiveChannel(aecm); } else if (((MIN_MSE_DIFF * mseStored) > (mseAdapt << MSE_RESOLUTION)) & (mseAdapt < aecm->mseThreshold) & (aecm->mseAdaptOld < aecm->mseThreshold)) { // The adaptive channel has a significantly lower MSE than the stored // one. The MSE for the adaptive channel has also been low for two // consecutive calculations. Store the adaptive channel. WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst); // Update threshold if (aecm->mseThreshold == WEBRTC_SPL_WORD32_MAX) { aecm->mseThreshold = (mseAdapt + aecm->mseAdaptOld); } else { int scaled_threshold = aecm->mseThreshold * 5 / 8; aecm->mseThreshold += ((mseAdapt - scaled_threshold) * 205) >> 8; } } // Reset counter aecm->mseChannelCount = 0; // Store the MSE values. aecm->mseStoredOld = mseStored; aecm->mseAdaptOld = mseAdapt; } } // END: Determine if we should store or reset channel estimate. } // CalcSuppressionGain(...) // // This function calculates the suppression gain that is used in the Wiener // filter. // // // @param aecm [i/n] Handle of the AECM instance. // @param supGain [out] (Return value) Suppression gain with which to scale // the noise // level (Q14). // // int16_t WebRtcAecm_CalcSuppressionGain(AecmCore* const aecm) { int32_t tmp32no1; int16_t supGain = SUPGAIN_DEFAULT; int16_t tmp16no1; int16_t dE = 0; // Determine suppression gain used in the Wiener filter. The gain is based on // a mix of far end energy and echo estimation error. Adjust for the far end // signal level. A low signal level indicates no far end signal, hence we set // the suppression gain to 0 if (!aecm->currentVADValue) { supGain = 0; } else { // Adjust for possible double talk. If we have large variations in // estimation error we likely have double talk (or poor channel). tmp16no1 = (aecm->nearLogEnergy[0] - aecm->echoStoredLogEnergy[0] - ENERGY_DEV_OFFSET); dE = WEBRTC_SPL_ABS_W16(tmp16no1); if (dE < ENERGY_DEV_TOL) { // Likely no double talk. The better estimation, the more we can suppress // signal. Update counters if (dE < SUPGAIN_EPC_DT) { tmp32no1 = aecm->supGainErrParamDiffAB * dE; tmp32no1 += (SUPGAIN_EPC_DT >> 1); tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(tmp32no1, SUPGAIN_EPC_DT); supGain = aecm->supGainErrParamA - tmp16no1; } else { tmp32no1 = aecm->supGainErrParamDiffBD * (ENERGY_DEV_TOL - dE); tmp32no1 += ((ENERGY_DEV_TOL - SUPGAIN_EPC_DT) >> 1); tmp16no1 = (int16_t)WebRtcSpl_DivW32W16( tmp32no1, (ENERGY_DEV_TOL - SUPGAIN_EPC_DT)); supGain = aecm->supGainErrParamD + tmp16no1; } } else { // Likely in double talk. Use default value supGain = aecm->supGainErrParamD; } } if (supGain > aecm->supGainOld) { tmp16no1 = supGain; } else { tmp16no1 = aecm->supGainOld; } aecm->supGainOld = supGain; if (tmp16no1 < aecm->supGain) { aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4); } else { aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4); } // END: Update suppression gain return aecm->supGain; } void WebRtcAecm_BufferFarFrame(AecmCore* const aecm, const int16_t* const farend, const int farLen) { int writeLen = farLen, writePos = 0; // Check if the write position must be wrapped while (aecm->farBufWritePos + writeLen > FAR_BUF_LEN) { // Write to remaining buffer space before wrapping writeLen = FAR_BUF_LEN - aecm->farBufWritePos; memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos, sizeof(int16_t) * writeLen); aecm->farBufWritePos = 0; writePos = writeLen; writeLen = farLen - writeLen; } memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos, sizeof(int16_t) * writeLen); aecm->farBufWritePos += writeLen; } void WebRtcAecm_FetchFarFrame(AecmCore* const aecm, int16_t* const farend, const int farLen, const int knownDelay) { int readLen = farLen; int readPos = 0; int delayChange = knownDelay - aecm->lastKnownDelay; aecm->farBufReadPos -= delayChange; // Check if delay forces a read position wrap while (aecm->farBufReadPos < 0) { aecm->farBufReadPos += FAR_BUF_LEN; } while (aecm->farBufReadPos > FAR_BUF_LEN - 1) { aecm->farBufReadPos -= FAR_BUF_LEN; } aecm->lastKnownDelay = knownDelay; // Check if read position must be wrapped while (aecm->farBufReadPos + readLen > FAR_BUF_LEN) { // Read from remaining buffer space before wrapping readLen = FAR_BUF_LEN - aecm->farBufReadPos; memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos, sizeof(int16_t) * readLen); aecm->farBufReadPos = 0; readPos = readLen; readLen = farLen - readLen; } memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos, sizeof(int16_t) * readLen); aecm->farBufReadPos += readLen; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aecm/aecm_core.h0000664000175000017500000003572714475643423026172 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Performs echo control (suppression) with fft routines in fixed-point. #ifndef MODULES_AUDIO_PROCESSING_AECM_AECM_CORE_H_ #define MODULES_AUDIO_PROCESSING_AECM_AECM_CORE_H_ extern "C" { #include "common_audio/ring_buffer.h" #include "common_audio/signal_processing/include/signal_processing_library.h" } #include "modules/audio_processing/aecm/aecm_defines.h" struct RealFFT; namespace webrtc { #ifdef _MSC_VER // visual c++ #define ALIGN8_BEG __declspec(align(8)) #define ALIGN8_END #else // gcc or icc #define ALIGN8_BEG #define ALIGN8_END __attribute__((aligned(8))) #endif typedef struct { int16_t real; int16_t imag; } ComplexInt16; typedef struct { int farBufWritePos; int farBufReadPos; int knownDelay; int lastKnownDelay; int firstVAD; // Parameter to control poorly initialized channels RingBuffer* farFrameBuf; RingBuffer* nearNoisyFrameBuf; RingBuffer* nearCleanFrameBuf; RingBuffer* outFrameBuf; int16_t farBuf[FAR_BUF_LEN]; int16_t mult; uint32_t seed; // Delay estimation variables void* delay_estimator_farend; void* delay_estimator; uint16_t currentDelay; // Far end history variables // TODO(bjornv): Replace |far_history| with ring_buffer. uint16_t far_history[PART_LEN1 * MAX_DELAY]; int far_history_pos; int far_q_domains[MAX_DELAY]; int16_t nlpFlag; int16_t fixedDelay; uint32_t totCount; int16_t dfaCleanQDomain; int16_t dfaCleanQDomainOld; int16_t dfaNoisyQDomain; int16_t dfaNoisyQDomainOld; int16_t nearLogEnergy[MAX_BUF_LEN]; int16_t farLogEnergy; int16_t echoAdaptLogEnergy[MAX_BUF_LEN]; int16_t echoStoredLogEnergy[MAX_BUF_LEN]; // The extra 16 or 32 bytes in the following buffers are for alignment based // Neon code. // It's designed this way since the current GCC compiler can't align a // buffer in 16 or 32 byte boundaries properly. int16_t channelStored_buf[PART_LEN1 + 8]; int16_t channelAdapt16_buf[PART_LEN1 + 8]; int32_t channelAdapt32_buf[PART_LEN1 + 8]; int16_t xBuf_buf[PART_LEN2 + 16]; // farend int16_t dBufClean_buf[PART_LEN2 + 16]; // nearend int16_t dBufNoisy_buf[PART_LEN2 + 16]; // nearend int16_t outBuf_buf[PART_LEN + 8]; // Pointers to the above buffers int16_t* channelStored; int16_t* channelAdapt16; int32_t* channelAdapt32; int16_t* xBuf; int16_t* dBufClean; int16_t* dBufNoisy; int16_t* outBuf; int32_t echoFilt[PART_LEN1]; int16_t nearFilt[PART_LEN1]; int32_t noiseEst[PART_LEN1]; int noiseEstTooLowCtr[PART_LEN1]; int noiseEstTooHighCtr[PART_LEN1]; int16_t noiseEstCtr; int16_t cngMode; int32_t mseAdaptOld; int32_t mseStoredOld; int32_t mseThreshold; int16_t farEnergyMin; int16_t farEnergyMax; int16_t farEnergyMaxMin; int16_t farEnergyVAD; int16_t farEnergyMSE; int currentVADValue; int16_t vadUpdateCount; int16_t startupState; int16_t mseChannelCount; int16_t supGain; int16_t supGainOld; int16_t supGainErrParamA; int16_t supGainErrParamD; int16_t supGainErrParamDiffAB; int16_t supGainErrParamDiffBD; struct RealFFT* real_fft; #ifdef AEC_DEBUG FILE* farFile; FILE* nearFile; FILE* outFile; #endif } AecmCore; //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_CreateCore() // // Allocates the memory needed by the AECM. The memory needs to be // initialized separately using the WebRtcAecm_InitCore() function. // Returns a pointer to the instance and a nullptr at failure. AecmCore* WebRtcAecm_CreateCore(); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_InitCore(...) // // This function initializes the AECM instant created with // WebRtcAecm_CreateCore() // Input: // - aecm : Pointer to the AECM instance // - samplingFreq : Sampling Frequency // // Output: // - aecm : Initialized instance // // Return value : 0 - Ok // -1 - Error // int WebRtcAecm_InitCore(AecmCore* const aecm, int samplingFreq); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_FreeCore(...) // // This function releases the memory allocated by WebRtcAecm_CreateCore() // Input: // - aecm : Pointer to the AECM instance // void WebRtcAecm_FreeCore(AecmCore* aecm); int WebRtcAecm_Control(AecmCore* aecm, int delay, int nlpFlag); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_InitEchoPathCore(...) // // This function resets the echo channel adaptation with the specified channel. // Input: // - aecm : Pointer to the AECM instance // - echo_path : Pointer to the data that should initialize the echo // path // // Output: // - aecm : Initialized instance // void WebRtcAecm_InitEchoPathCore(AecmCore* aecm, const int16_t* echo_path); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_ProcessFrame(...) // // This function processes frames and sends blocks to // WebRtcAecm_ProcessBlock(...) // // Inputs: // - aecm : Pointer to the AECM instance // - farend : In buffer containing one frame of echo signal // - nearendNoisy : In buffer containing one frame of nearend+echo signal // without NS // - nearendClean : In buffer containing one frame of nearend+echo signal // with NS // // Output: // - out : Out buffer, one frame of nearend signal : // // int WebRtcAecm_ProcessFrame(AecmCore* aecm, const int16_t* farend, const int16_t* nearendNoisy, const int16_t* nearendClean, int16_t* out); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_ProcessBlock(...) // // This function is called for every block within one frame // This function is called by WebRtcAecm_ProcessFrame(...) // // Inputs: // - aecm : Pointer to the AECM instance // - farend : In buffer containing one block of echo signal // - nearendNoisy : In buffer containing one frame of nearend+echo signal // without NS // - nearendClean : In buffer containing one frame of nearend+echo signal // with NS // // Output: // - out : Out buffer, one block of nearend signal : // // int WebRtcAecm_ProcessBlock(AecmCore* aecm, const int16_t* farend, const int16_t* nearendNoisy, const int16_t* noisyClean, int16_t* out); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_BufferFarFrame() // // Inserts a frame of data into farend buffer. // // Inputs: // - aecm : Pointer to the AECM instance // - farend : In buffer containing one frame of farend signal // - farLen : Length of frame // void WebRtcAecm_BufferFarFrame(AecmCore* const aecm, const int16_t* const farend, const int farLen); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_FetchFarFrame() // // Read the farend buffer to account for known delay // // Inputs: // - aecm : Pointer to the AECM instance // - farend : In buffer containing one frame of farend signal // - farLen : Length of frame // - knownDelay : known delay // void WebRtcAecm_FetchFarFrame(AecmCore* const aecm, int16_t* const farend, const int farLen, const int knownDelay); // All the functions below are intended to be private //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_UpdateFarHistory() // // Moves the pointer to the next entry and inserts |far_spectrum| and // corresponding Q-domain in its buffer. // // Inputs: // - self : Pointer to the delay estimation instance // - far_spectrum : Pointer to the far end spectrum // - far_q : Q-domain of far end spectrum // void WebRtcAecm_UpdateFarHistory(AecmCore* self, uint16_t* far_spectrum, int far_q); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_AlignedFarend() // // Returns a pointer to the far end spectrum aligned to current near end // spectrum. The function WebRtc_DelayEstimatorProcessFix(...) should have been // called before AlignedFarend(...). Otherwise, you get the pointer to the // previous frame. The memory is only valid until the next call of // WebRtc_DelayEstimatorProcessFix(...). // // Inputs: // - self : Pointer to the AECM instance. // - delay : Current delay estimate. // // Output: // - far_q : The Q-domain of the aligned far end spectrum // // Return value: // - far_spectrum : Pointer to the aligned far end spectrum // NULL - Error // const uint16_t* WebRtcAecm_AlignedFarend(AecmCore* self, int* far_q, int delay); /////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_CalcSuppressionGain() // // This function calculates the suppression gain that is used in the // Wiener filter. // // Inputs: // - aecm : Pointer to the AECM instance. // // Return value: // - supGain : Suppression gain with which to scale the noise // level (Q14). // int16_t WebRtcAecm_CalcSuppressionGain(AecmCore* const aecm); /////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_CalcEnergies() // // This function calculates the log of energies for nearend, farend and // estimated echoes. There is also an update of energy decision levels, // i.e. internal VAD. // // Inputs: // - aecm : Pointer to the AECM instance. // - far_spectrum : Pointer to farend spectrum. // - far_q : Q-domain of farend spectrum. // - nearEner : Near end energy for current block in // Q(aecm->dfaQDomain). // // Output: // - echoEst : Estimated echo in Q(xfa_q+RESOLUTION_CHANNEL16). // void WebRtcAecm_CalcEnergies(AecmCore* aecm, const uint16_t* far_spectrum, const int16_t far_q, const uint32_t nearEner, int32_t* echoEst); /////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_CalcStepSize() // // This function calculates the step size used in channel estimation // // Inputs: // - aecm : Pointer to the AECM instance. // // Return value: // - mu : Stepsize in log2(), i.e. number of shifts. // int16_t WebRtcAecm_CalcStepSize(AecmCore* const aecm); /////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_UpdateChannel(...) // // This function performs channel estimation. // NLMS and decision on channel storage. // // Inputs: // - aecm : Pointer to the AECM instance. // - far_spectrum : Absolute value of the farend signal in Q(far_q) // - far_q : Q-domain of the farend signal // - dfa : Absolute value of the nearend signal // (Q[aecm->dfaQDomain]) // - mu : NLMS step size. // Input/Output: // - echoEst : Estimated echo in Q(far_q+RESOLUTION_CHANNEL16). // void WebRtcAecm_UpdateChannel(AecmCore* aecm, const uint16_t* far_spectrum, const int16_t far_q, const uint16_t* const dfa, const int16_t mu, int32_t* echoEst); extern const int16_t WebRtcAecm_kCosTable[]; extern const int16_t WebRtcAecm_kSinTable[]; /////////////////////////////////////////////////////////////////////////////// // Some function pointers, for internal functions shared by ARM NEON and // generic C code. // typedef void (*CalcLinearEnergies)(AecmCore* aecm, const uint16_t* far_spectrum, int32_t* echoEst, uint32_t* far_energy, uint32_t* echo_energy_adapt, uint32_t* echo_energy_stored); extern CalcLinearEnergies WebRtcAecm_CalcLinearEnergies; typedef void (*StoreAdaptiveChannel)(AecmCore* aecm, const uint16_t* far_spectrum, int32_t* echo_est); extern StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel; typedef void (*ResetAdaptiveChannel)(AecmCore* aecm); extern ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel; // For the above function pointers, functions for generic platforms are declared // and defined as static in file aecm_core.c, while those for ARM Neon platforms // are declared below and defined in file aecm_core_neon.c. #if defined(WEBRTC_HAS_NEON) void WebRtcAecm_CalcLinearEnergiesNeon(AecmCore* aecm, const uint16_t* far_spectrum, int32_t* echo_est, uint32_t* far_energy, uint32_t* echo_energy_adapt, uint32_t* echo_energy_stored); void WebRtcAecm_StoreAdaptiveChannelNeon(AecmCore* aecm, const uint16_t* far_spectrum, int32_t* echo_est); void WebRtcAecm_ResetAdaptiveChannelNeon(AecmCore* aecm); #endif #if defined(MIPS32_LE) void WebRtcAecm_CalcLinearEnergies_mips(AecmCore* aecm, const uint16_t* far_spectrum, int32_t* echo_est, uint32_t* far_energy, uint32_t* echo_energy_adapt, uint32_t* echo_energy_stored); #if defined(MIPS_DSP_R1_LE) void WebRtcAecm_StoreAdaptiveChannel_mips(AecmCore* aecm, const uint16_t* far_spectrum, int32_t* echo_est); void WebRtcAecm_ResetAdaptiveChannel_mips(AecmCore* aecm); #endif #endif } // namespace webrtc #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aecm/aecm_core_c.cc0000664000175000017500000005562314475643423026627 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include #include #include "modules/audio_processing/aecm/aecm_core.h" extern "C" { #include "common_audio/ring_buffer.h" #include "common_audio/signal_processing/include/real_fft.h" } #include "modules/audio_processing/aecm/echo_control_mobile.h" #include "modules/audio_processing/utility/delay_estimator_wrapper.h" extern "C" { #include "system_wrappers/include/cpu_features_wrapper.h" } #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/sanitizer.h" namespace webrtc { namespace { // Square root of Hanning window in Q14. static const ALIGN8_BEG int16_t WebRtcAecm_kSqrtHanning[] ALIGN8_END = { 0, 399, 798, 1196, 1594, 1990, 2386, 2780, 3172, 3562, 3951, 4337, 4720, 5101, 5478, 5853, 6224, 6591, 6954, 7313, 7668, 8019, 8364, 8705, 9040, 9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514, 11795, 12068, 12335, 12594, 12845, 13089, 13325, 13553, 13773, 13985, 14189, 14384, 14571, 14749, 14918, 15079, 15231, 15373, 15506, 15631, 15746, 15851, 15947, 16034, 16111, 16179, 16237, 16286, 16325, 16354, 16373, 16384}; #ifdef AECM_WITH_ABS_APPROX // Q15 alpha = 0.99439986968132 const Factor for magnitude approximation static const uint16_t kAlpha1 = 32584; // Q15 beta = 0.12967166976970 const Factor for magnitude approximation static const uint16_t kBeta1 = 4249; // Q15 alpha = 0.94234827210087 const Factor for magnitude approximation static const uint16_t kAlpha2 = 30879; // Q15 beta = 0.33787806009150 const Factor for magnitude approximation static const uint16_t kBeta2 = 11072; // Q15 alpha = 0.82247698684306 const Factor for magnitude approximation static const uint16_t kAlpha3 = 26951; // Q15 beta = 0.57762063060713 const Factor for magnitude approximation static const uint16_t kBeta3 = 18927; #endif static const int16_t kNoiseEstQDomain = 15; static const int16_t kNoiseEstIncCount = 5; static void ComfortNoise(AecmCore* aecm, const uint16_t* dfa, ComplexInt16* out, const int16_t* lambda) { int16_t i; int16_t tmp16; int32_t tmp32; int16_t randW16[PART_LEN]; int16_t uReal[PART_LEN1]; int16_t uImag[PART_LEN1]; int32_t outLShift32; int16_t noiseRShift16[PART_LEN1]; int16_t shiftFromNearToNoise = kNoiseEstQDomain - aecm->dfaCleanQDomain; int16_t minTrackShift; RTC_DCHECK_GE(shiftFromNearToNoise, 0); RTC_DCHECK_LT(shiftFromNearToNoise, 16); if (aecm->noiseEstCtr < 100) { // Track the minimum more quickly initially. aecm->noiseEstCtr++; minTrackShift = 6; } else { minTrackShift = 9; } // Estimate noise power. for (i = 0; i < PART_LEN1; i++) { // Shift to the noise domain. tmp32 = (int32_t)dfa[i]; outLShift32 = tmp32 << shiftFromNearToNoise; if (outLShift32 < aecm->noiseEst[i]) { // Reset "too low" counter aecm->noiseEstTooLowCtr[i] = 0; // Track the minimum. if (aecm->noiseEst[i] < (1 << minTrackShift)) { // For small values, decrease noiseEst[i] every // |kNoiseEstIncCount| block. The regular approach below can not // go further down due to truncation. aecm->noiseEstTooHighCtr[i]++; if (aecm->noiseEstTooHighCtr[i] >= kNoiseEstIncCount) { aecm->noiseEst[i]--; aecm->noiseEstTooHighCtr[i] = 0; // Reset the counter } } else { aecm->noiseEst[i] -= ((aecm->noiseEst[i] - outLShift32) >> minTrackShift); } } else { // Reset "too high" counter aecm->noiseEstTooHighCtr[i] = 0; // Ramp slowly upwards until we hit the minimum again. if ((aecm->noiseEst[i] >> 19) > 0) { // Avoid overflow. // Multiplication with 2049 will cause wrap around. Scale // down first and then multiply aecm->noiseEst[i] >>= 11; aecm->noiseEst[i] *= 2049; } else if ((aecm->noiseEst[i] >> 11) > 0) { // Large enough for relative increase aecm->noiseEst[i] *= 2049; aecm->noiseEst[i] >>= 11; } else { // Make incremental increases based on size every // |kNoiseEstIncCount| block aecm->noiseEstTooLowCtr[i]++; if (aecm->noiseEstTooLowCtr[i] >= kNoiseEstIncCount) { aecm->noiseEst[i] += (aecm->noiseEst[i] >> 9) + 1; aecm->noiseEstTooLowCtr[i] = 0; // Reset counter } } } } for (i = 0; i < PART_LEN1; i++) { tmp32 = aecm->noiseEst[i] >> shiftFromNearToNoise; if (tmp32 > 32767) { tmp32 = 32767; aecm->noiseEst[i] = tmp32 << shiftFromNearToNoise; } noiseRShift16[i] = (int16_t)tmp32; tmp16 = ONE_Q14 - lambda[i]; noiseRShift16[i] = (int16_t)((tmp16 * noiseRShift16[i]) >> 14); } // Generate a uniform random array on [0 2^15-1]. WebRtcSpl_RandUArray(randW16, PART_LEN, &aecm->seed); // Generate noise according to estimated energy. uReal[0] = 0; // Reject LF noise. uImag[0] = 0; for (i = 1; i < PART_LEN1; i++) { // Get a random index for the cos and sin tables over [0 359]. tmp16 = (int16_t)((359 * randW16[i - 1]) >> 15); // Tables are in Q13. uReal[i] = (int16_t)((noiseRShift16[i] * WebRtcAecm_kCosTable[tmp16]) >> 13); uImag[i] = (int16_t)((-noiseRShift16[i] * WebRtcAecm_kSinTable[tmp16]) >> 13); } uImag[PART_LEN] = 0; for (i = 0; i < PART_LEN1; i++) { out[i].real = WebRtcSpl_AddSatW16(out[i].real, uReal[i]); out[i].imag = WebRtcSpl_AddSatW16(out[i].imag, uImag[i]); } } static void WindowAndFFT(AecmCore* aecm, int16_t* fft, const int16_t* time_signal, ComplexInt16* freq_signal, int time_signal_scaling) { int i = 0; // FFT of signal for (i = 0; i < PART_LEN; i++) { // Window time domain signal and insert into real part of // transformation array |fft| int16_t scaled_time_signal = time_signal[i] * (1 << time_signal_scaling); fft[i] = (int16_t)((scaled_time_signal * WebRtcAecm_kSqrtHanning[i]) >> 14); scaled_time_signal = time_signal[i + PART_LEN] * (1 << time_signal_scaling); fft[PART_LEN + i] = (int16_t)( (scaled_time_signal * WebRtcAecm_kSqrtHanning[PART_LEN - i]) >> 14); } // Do forward FFT, then take only the first PART_LEN complex samples, // and change signs of the imaginary parts. WebRtcSpl_RealForwardFFT(aecm->real_fft, fft, (int16_t*)freq_signal); for (i = 0; i < PART_LEN; i++) { freq_signal[i].imag = -freq_signal[i].imag; } } static void InverseFFTAndWindow(AecmCore* aecm, int16_t* fft, ComplexInt16* efw, int16_t* output, const int16_t* nearendClean) { int i, j, outCFFT; int32_t tmp32no1; // Reuse |efw| for the inverse FFT output after transferring // the contents to |fft|. int16_t* ifft_out = (int16_t*)efw; // Synthesis for (i = 1, j = 2; i < PART_LEN; i += 1, j += 2) { fft[j] = efw[i].real; fft[j + 1] = -efw[i].imag; } fft[0] = efw[0].real; fft[1] = -efw[0].imag; fft[PART_LEN2] = efw[PART_LEN].real; fft[PART_LEN2 + 1] = -efw[PART_LEN].imag; // Inverse FFT. Keep outCFFT to scale the samples in the next block. outCFFT = WebRtcSpl_RealInverseFFT(aecm->real_fft, fft, ifft_out); for (i = 0; i < PART_LEN; i++) { ifft_out[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( ifft_out[i], WebRtcAecm_kSqrtHanning[i], 14); tmp32no1 = WEBRTC_SPL_SHIFT_W32((int32_t)ifft_out[i], outCFFT - aecm->dfaCleanQDomain); output[i] = (int16_t)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, tmp32no1 + aecm->outBuf[i], WEBRTC_SPL_WORD16_MIN); tmp32no1 = (ifft_out[PART_LEN + i] * WebRtcAecm_kSqrtHanning[PART_LEN - i]) >> 14; tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1, outCFFT - aecm->dfaCleanQDomain); aecm->outBuf[i] = (int16_t)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, tmp32no1, WEBRTC_SPL_WORD16_MIN); } // Copy the current block to the old position // (aecm->outBuf is shifted elsewhere) memcpy(aecm->xBuf, aecm->xBuf + PART_LEN, sizeof(int16_t) * PART_LEN); memcpy(aecm->dBufNoisy, aecm->dBufNoisy + PART_LEN, sizeof(int16_t) * PART_LEN); if (nearendClean != NULL) { memcpy(aecm->dBufClean, aecm->dBufClean + PART_LEN, sizeof(int16_t) * PART_LEN); } } // Transforms a time domain signal into the frequency domain, outputting the // complex valued signal, absolute value and sum of absolute values. // // time_signal [in] Pointer to time domain signal // freq_signal_real [out] Pointer to real part of frequency domain array // freq_signal_imag [out] Pointer to imaginary part of frequency domain // array // freq_signal_abs [out] Pointer to absolute value of frequency domain // array // freq_signal_sum_abs [out] Pointer to the sum of all absolute values in // the frequency domain array // return value The Q-domain of current frequency values // static int TimeToFrequencyDomain(AecmCore* aecm, const int16_t* time_signal, ComplexInt16* freq_signal, uint16_t* freq_signal_abs, uint32_t* freq_signal_sum_abs) { int i = 0; int time_signal_scaling = 0; int32_t tmp32no1 = 0; int32_t tmp32no2 = 0; // In fft_buf, +16 for 32-byte alignment. int16_t fft_buf[PART_LEN4 + 16]; int16_t* fft = (int16_t*)(((uintptr_t)fft_buf + 31) & ~31); int16_t tmp16no1; #ifndef WEBRTC_ARCH_ARM_V7 int16_t tmp16no2; #endif #ifdef AECM_WITH_ABS_APPROX int16_t max_value = 0; int16_t min_value = 0; uint16_t alpha = 0; uint16_t beta = 0; #endif #ifdef AECM_DYNAMIC_Q tmp16no1 = WebRtcSpl_MaxAbsValueW16(time_signal, PART_LEN2); time_signal_scaling = WebRtcSpl_NormW16(tmp16no1); #endif WindowAndFFT(aecm, fft, time_signal, freq_signal, time_signal_scaling); // Extract imaginary and real part, calculate the magnitude for // all frequency bins freq_signal[0].imag = 0; freq_signal[PART_LEN].imag = 0; freq_signal_abs[0] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[0].real); freq_signal_abs[PART_LEN] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[PART_LEN].real); (*freq_signal_sum_abs) = (uint32_t)(freq_signal_abs[0]) + (uint32_t)(freq_signal_abs[PART_LEN]); for (i = 1; i < PART_LEN; i++) { if (freq_signal[i].real == 0) { freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[i].imag); } else if (freq_signal[i].imag == 0) { freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[i].real); } else { // Approximation for magnitude of complex fft output // magn = sqrt(real^2 + imag^2) // magn ~= alpha * max(|imag|,|real|) + beta * min(|imag|,|real|) // // The parameters alpha and beta are stored in Q15 #ifdef AECM_WITH_ABS_APPROX tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real); tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag); if (tmp16no1 > tmp16no2) { max_value = tmp16no1; min_value = tmp16no2; } else { max_value = tmp16no2; min_value = tmp16no1; } // Magnitude in Q(-6) if ((max_value >> 2) > min_value) { alpha = kAlpha1; beta = kBeta1; } else if ((max_value >> 1) > min_value) { alpha = kAlpha2; beta = kBeta2; } else { alpha = kAlpha3; beta = kBeta3; } tmp16no1 = (int16_t)((max_value * alpha) >> 15); tmp16no2 = (int16_t)((min_value * beta) >> 15); freq_signal_abs[i] = (uint16_t)tmp16no1 + (uint16_t)tmp16no2; #else #ifdef WEBRTC_ARCH_ARM_V7 __asm __volatile( "smulbb %[tmp32no1], %[real], %[real]\n\t" "smlabb %[tmp32no2], %[imag], %[imag], %[tmp32no1]\n\t" : [tmp32no1] "+&r"(tmp32no1), [tmp32no2] "=r"(tmp32no2) : [real] "r"(freq_signal[i].real), [imag] "r"(freq_signal[i].imag)); #else tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real); tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag); tmp32no1 = tmp16no1 * tmp16no1; tmp32no2 = tmp16no2 * tmp16no2; tmp32no2 = WebRtcSpl_AddSatW32(tmp32no1, tmp32no2); #endif // WEBRTC_ARCH_ARM_V7 tmp32no1 = WebRtcSpl_SqrtFloor(tmp32no2); freq_signal_abs[i] = (uint16_t)tmp32no1; #endif // AECM_WITH_ABS_APPROX } (*freq_signal_sum_abs) += (uint32_t)freq_signal_abs[i]; } return time_signal_scaling; } } // namespace int RTC_NO_SANITIZE("signed-integer-overflow") // bugs.webrtc.org/8200 WebRtcAecm_ProcessBlock(AecmCore* aecm, const int16_t* farend, const int16_t* nearendNoisy, const int16_t* nearendClean, int16_t* output) { int i; uint32_t xfaSum; uint32_t dfaNoisySum; uint32_t dfaCleanSum; uint32_t echoEst32Gained; uint32_t tmpU32; int32_t tmp32no1; uint16_t xfa[PART_LEN1]; uint16_t dfaNoisy[PART_LEN1]; uint16_t dfaClean[PART_LEN1]; uint16_t* ptrDfaClean = dfaClean; const uint16_t* far_spectrum_ptr = NULL; // 32 byte aligned buffers (with +8 or +16). // TODO(kma): define fft with ComplexInt16. int16_t fft_buf[PART_LEN4 + 2 + 16]; // +2 to make a loop safe. int32_t echoEst32_buf[PART_LEN1 + 8]; int32_t dfw_buf[PART_LEN2 + 8]; int32_t efw_buf[PART_LEN2 + 8]; int16_t* fft = (int16_t*)(((uintptr_t)fft_buf + 31) & ~31); int32_t* echoEst32 = (int32_t*)(((uintptr_t)echoEst32_buf + 31) & ~31); ComplexInt16* dfw = (ComplexInt16*)(((uintptr_t)dfw_buf + 31) & ~31); ComplexInt16* efw = (ComplexInt16*)(((uintptr_t)efw_buf + 31) & ~31); int16_t hnl[PART_LEN1]; int16_t numPosCoef = 0; int16_t nlpGain = ONE_Q14; int delay; int16_t tmp16no1; int16_t tmp16no2; int16_t mu; int16_t supGain; int16_t zeros32, zeros16; int16_t zerosDBufNoisy, zerosDBufClean, zerosXBuf; int far_q; int16_t resolutionDiff, qDomainDiff, dfa_clean_q_domain_diff; const int kMinPrefBand = 4; const int kMaxPrefBand = 24; int32_t avgHnl32 = 0; // Determine startup state. There are three states: // (0) the first CONV_LEN blocks // (1) another CONV_LEN blocks // (2) the rest if (aecm->startupState < 2) { aecm->startupState = (aecm->totCount >= CONV_LEN) + (aecm->totCount >= CONV_LEN2); } // END: Determine startup state // Buffer near and far end signals memcpy(aecm->xBuf + PART_LEN, farend, sizeof(int16_t) * PART_LEN); memcpy(aecm->dBufNoisy + PART_LEN, nearendNoisy, sizeof(int16_t) * PART_LEN); if (nearendClean != NULL) { memcpy(aecm->dBufClean + PART_LEN, nearendClean, sizeof(int16_t) * PART_LEN); } // Transform far end signal from time domain to frequency domain. far_q = TimeToFrequencyDomain(aecm, aecm->xBuf, dfw, xfa, &xfaSum); // Transform noisy near end signal from time domain to frequency domain. zerosDBufNoisy = TimeToFrequencyDomain(aecm, aecm->dBufNoisy, dfw, dfaNoisy, &dfaNoisySum); aecm->dfaNoisyQDomainOld = aecm->dfaNoisyQDomain; aecm->dfaNoisyQDomain = (int16_t)zerosDBufNoisy; if (nearendClean == NULL) { ptrDfaClean = dfaNoisy; aecm->dfaCleanQDomainOld = aecm->dfaNoisyQDomainOld; aecm->dfaCleanQDomain = aecm->dfaNoisyQDomain; dfaCleanSum = dfaNoisySum; } else { // Transform clean near end signal from time domain to frequency domain. zerosDBufClean = TimeToFrequencyDomain(aecm, aecm->dBufClean, dfw, dfaClean, &dfaCleanSum); aecm->dfaCleanQDomainOld = aecm->dfaCleanQDomain; aecm->dfaCleanQDomain = (int16_t)zerosDBufClean; } // Get the delay // Save far-end history and estimate delay WebRtcAecm_UpdateFarHistory(aecm, xfa, far_q); if (WebRtc_AddFarSpectrumFix(aecm->delay_estimator_farend, xfa, PART_LEN1, far_q) == -1) { return -1; } delay = WebRtc_DelayEstimatorProcessFix(aecm->delay_estimator, dfaNoisy, PART_LEN1, zerosDBufNoisy); if (delay == -1) { return -1; } else if (delay == -2) { // If the delay is unknown, we assume zero. // NOTE: this will have to be adjusted if we ever add lookahead. delay = 0; } if (aecm->fixedDelay >= 0) { // Use fixed delay delay = aecm->fixedDelay; } // Get aligned far end spectrum far_spectrum_ptr = WebRtcAecm_AlignedFarend(aecm, &far_q, delay); zerosXBuf = (int16_t)far_q; if (far_spectrum_ptr == NULL) { return -1; } // Calculate log(energy) and update energy threshold levels WebRtcAecm_CalcEnergies(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisySum, echoEst32); // Calculate stepsize mu = WebRtcAecm_CalcStepSize(aecm); // Update counters aecm->totCount++; // This is the channel estimation algorithm. // It is base on NLMS but has a variable step length, // which was calculated above. WebRtcAecm_UpdateChannel(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisy, mu, echoEst32); supGain = WebRtcAecm_CalcSuppressionGain(aecm); // Calculate Wiener filter hnl[] for (i = 0; i < PART_LEN1; i++) { // Far end signal through channel estimate in Q8 // How much can we shift right to preserve resolution tmp32no1 = echoEst32[i] - aecm->echoFilt[i]; aecm->echoFilt[i] += rtc::dchecked_cast((int64_t{tmp32no1} * 50) >> 8); zeros32 = WebRtcSpl_NormW32(aecm->echoFilt[i]) + 1; zeros16 = WebRtcSpl_NormW16(supGain) + 1; if (zeros32 + zeros16 > 16) { // Multiplication is safe // Result in // Q(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN+ // aecm->xfaQDomainBuf[diff]) echoEst32Gained = WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i], (uint16_t)supGain); resolutionDiff = 14 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN; resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf); } else { tmp16no1 = 17 - zeros32 - zeros16; resolutionDiff = 14 + tmp16no1 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN; resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf); if (zeros32 > tmp16no1) { echoEst32Gained = WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i], supGain >> tmp16no1); } else { // Result in Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16) echoEst32Gained = (aecm->echoFilt[i] >> tmp16no1) * supGain; } } zeros16 = WebRtcSpl_NormW16(aecm->nearFilt[i]); RTC_DCHECK_GE(zeros16, 0); // |zeros16| is a norm, hence non-negative. dfa_clean_q_domain_diff = aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld; if (zeros16 < dfa_clean_q_domain_diff && aecm->nearFilt[i]) { tmp16no1 = aecm->nearFilt[i] * (1 << zeros16); qDomainDiff = zeros16 - dfa_clean_q_domain_diff; tmp16no2 = ptrDfaClean[i] >> -qDomainDiff; } else { tmp16no1 = dfa_clean_q_domain_diff < 0 ? aecm->nearFilt[i] >> -dfa_clean_q_domain_diff : aecm->nearFilt[i] * (1 << dfa_clean_q_domain_diff); qDomainDiff = 0; tmp16no2 = ptrDfaClean[i]; } tmp32no1 = (int32_t)(tmp16no2 - tmp16no1); tmp16no2 = (int16_t)(tmp32no1 >> 4); tmp16no2 += tmp16no1; zeros16 = WebRtcSpl_NormW16(tmp16no2); if ((tmp16no2) & (-qDomainDiff > zeros16)) { aecm->nearFilt[i] = WEBRTC_SPL_WORD16_MAX; } else { aecm->nearFilt[i] = qDomainDiff < 0 ? tmp16no2 * (1 << -qDomainDiff) : tmp16no2 >> qDomainDiff; } // Wiener filter coefficients, resulting hnl in Q14 if (echoEst32Gained == 0) { hnl[i] = ONE_Q14; } else if (aecm->nearFilt[i] == 0) { hnl[i] = 0; } else { // Multiply the suppression gain // Rounding echoEst32Gained += (uint32_t)(aecm->nearFilt[i] >> 1); tmpU32 = WebRtcSpl_DivU32U16(echoEst32Gained, (uint16_t)aecm->nearFilt[i]); // Current resolution is // Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN- max(0,17-zeros16- zeros32)) // Make sure we are in Q14 tmp32no1 = (int32_t)WEBRTC_SPL_SHIFT_W32(tmpU32, resolutionDiff); if (tmp32no1 > ONE_Q14) { hnl[i] = 0; } else if (tmp32no1 < 0) { hnl[i] = ONE_Q14; } else { // 1-echoEst/dfa hnl[i] = ONE_Q14 - (int16_t)tmp32no1; if (hnl[i] < 0) { hnl[i] = 0; } } } if (hnl[i]) { numPosCoef++; } } // Only in wideband. Prevent the gain in upper band from being larger than // in lower band. if (aecm->mult == 2) { // TODO(bjornv): Investigate if the scaling of hnl[i] below can cause // speech distortion in double-talk. for (i = 0; i < PART_LEN1; i++) { hnl[i] = (int16_t)((hnl[i] * hnl[i]) >> 14); } for (i = kMinPrefBand; i <= kMaxPrefBand; i++) { avgHnl32 += (int32_t)hnl[i]; } RTC_DCHECK_GT(kMaxPrefBand - kMinPrefBand + 1, 0); avgHnl32 /= (kMaxPrefBand - kMinPrefBand + 1); for (i = kMaxPrefBand; i < PART_LEN1; i++) { if (hnl[i] > (int16_t)avgHnl32) { hnl[i] = (int16_t)avgHnl32; } } } // Calculate NLP gain, result is in Q14 if (aecm->nlpFlag) { for (i = 0; i < PART_LEN1; i++) { // Truncate values close to zero and one. if (hnl[i] > NLP_COMP_HIGH) { hnl[i] = ONE_Q14; } else if (hnl[i] < NLP_COMP_LOW) { hnl[i] = 0; } // Remove outliers if (numPosCoef < 3) { nlpGain = 0; } else { nlpGain = ONE_Q14; } // NLP if ((hnl[i] == ONE_Q14) && (nlpGain == ONE_Q14)) { hnl[i] = ONE_Q14; } else { hnl[i] = (int16_t)((hnl[i] * nlpGain) >> 14); } // multiply with Wiener coefficients efw[i].real = (int16_t)( WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real, hnl[i], 14)); efw[i].imag = (int16_t)( WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag, hnl[i], 14)); } } else { // multiply with Wiener coefficients for (i = 0; i < PART_LEN1; i++) { efw[i].real = (int16_t)( WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real, hnl[i], 14)); efw[i].imag = (int16_t)( WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag, hnl[i], 14)); } } if (aecm->cngMode == AecmTrue) { ComfortNoise(aecm, ptrDfaClean, efw, hnl); } InverseFFTAndWindow(aecm, fft, efw, output, nearendClean); return 0; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aecm/aecm_core_mips.cc0000664000175000017500000022622714475643423027355 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aecm/aecm_core.h" #include "modules/audio_processing/aecm/echo_control_mobile.h" #include "modules/audio_processing/utility/delay_estimator_wrapper.h" #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_conversions.h" namespace webrtc { namespace { static const ALIGN8_BEG int16_t WebRtcAecm_kSqrtHanning[] ALIGN8_END = { 0, 399, 798, 1196, 1594, 1990, 2386, 2780, 3172, 3562, 3951, 4337, 4720, 5101, 5478, 5853, 6224, 6591, 6954, 7313, 7668, 8019, 8364, 8705, 9040, 9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514, 11795, 12068, 12335, 12594, 12845, 13089, 13325, 13553, 13773, 13985, 14189, 14384, 14571, 14749, 14918, 15079, 15231, 15373, 15506, 15631, 15746, 15851, 15947, 16034, 16111, 16179, 16237, 16286, 16325, 16354, 16373, 16384}; static const int16_t kNoiseEstQDomain = 15; static const int16_t kNoiseEstIncCount = 5; static int16_t coefTable[] = { 0, 4, 256, 260, 128, 132, 384, 388, 64, 68, 320, 324, 192, 196, 448, 452, 32, 36, 288, 292, 160, 164, 416, 420, 96, 100, 352, 356, 224, 228, 480, 484, 16, 20, 272, 276, 144, 148, 400, 404, 80, 84, 336, 340, 208, 212, 464, 468, 48, 52, 304, 308, 176, 180, 432, 436, 112, 116, 368, 372, 240, 244, 496, 500, 8, 12, 264, 268, 136, 140, 392, 396, 72, 76, 328, 332, 200, 204, 456, 460, 40, 44, 296, 300, 168, 172, 424, 428, 104, 108, 360, 364, 232, 236, 488, 492, 24, 28, 280, 284, 152, 156, 408, 412, 88, 92, 344, 348, 216, 220, 472, 476, 56, 60, 312, 316, 184, 188, 440, 444, 120, 124, 376, 380, 248, 252, 504, 508}; static int16_t coefTable_ifft[] = { 0, 512, 256, 508, 128, 252, 384, 380, 64, 124, 320, 444, 192, 188, 448, 316, 32, 60, 288, 476, 160, 220, 416, 348, 96, 92, 352, 412, 224, 156, 480, 284, 16, 28, 272, 492, 144, 236, 400, 364, 80, 108, 336, 428, 208, 172, 464, 300, 48, 44, 304, 460, 176, 204, 432, 332, 112, 76, 368, 396, 240, 140, 496, 268, 8, 12, 264, 500, 136, 244, 392, 372, 72, 116, 328, 436, 200, 180, 456, 308, 40, 52, 296, 468, 168, 212, 424, 340, 104, 84, 360, 404, 232, 148, 488, 276, 24, 20, 280, 484, 152, 228, 408, 356, 88, 100, 344, 420, 216, 164, 472, 292, 56, 36, 312, 452, 184, 196, 440, 324, 120, 68, 376, 388, 248, 132, 504, 260}; } // namespace static void ComfortNoise(AecmCore* aecm, const uint16_t* dfa, ComplexInt16* out, const int16_t* lambda); static void WindowAndFFT(AecmCore* aecm, int16_t* fft, const int16_t* time_signal, ComplexInt16* freq_signal, int time_signal_scaling) { int i, j; int32_t tmp1, tmp2, tmp3, tmp4; int16_t* pfrfi; ComplexInt16* pfreq_signal; int16_t f_coef, s_coef; int32_t load_ptr, store_ptr1, store_ptr2, shift, shift1; int32_t hann, hann1, coefs; memset(fft, 0, sizeof(int16_t) * PART_LEN4); // FFT of signal __asm __volatile( ".set push \n\t" ".set noreorder \n\t" "addiu %[shift], %[time_signal_scaling], -14 \n\t" "addiu %[i], $zero, 64 \n\t" "addiu %[load_ptr], %[time_signal], 0 \n\t" "addiu %[hann], %[hanning], 0 \n\t" "addiu %[hann1], %[hanning], 128 \n\t" "addiu %[coefs], %[coefTable], 0 \n\t" "bltz %[shift], 2f \n\t" " negu %[shift1], %[shift] \n\t" "1: " "\n\t" "lh %[tmp1], 0(%[load_ptr]) \n\t" "lh %[tmp2], 0(%[hann]) \n\t" "lh %[tmp3], 128(%[load_ptr]) \n\t" "lh %[tmp4], 0(%[hann1]) \n\t" "addiu %[i], %[i], -1 \n\t" "mul %[tmp1], %[tmp1], %[tmp2] \n\t" "mul %[tmp3], %[tmp3], %[tmp4] \n\t" "lh %[f_coef], 0(%[coefs]) \n\t" "lh %[s_coef], 2(%[coefs]) \n\t" "addiu %[load_ptr], %[load_ptr], 2 \n\t" "addiu %[hann], %[hann], 2 \n\t" "addiu %[hann1], %[hann1], -2 \n\t" "addu %[store_ptr1], %[fft], %[f_coef] \n\t" "addu %[store_ptr2], %[fft], %[s_coef] \n\t" "sllv %[tmp1], %[tmp1], %[shift] \n\t" "sllv %[tmp3], %[tmp3], %[shift] \n\t" "sh %[tmp1], 0(%[store_ptr1]) \n\t" "sh %[tmp3], 0(%[store_ptr2]) \n\t" "bgtz %[i], 1b \n\t" " addiu %[coefs], %[coefs], 4 \n\t" "b 3f \n\t" " nop \n\t" "2: " "\n\t" "lh %[tmp1], 0(%[load_ptr]) \n\t" "lh %[tmp2], 0(%[hann]) \n\t" "lh %[tmp3], 128(%[load_ptr]) \n\t" "lh %[tmp4], 0(%[hann1]) \n\t" "addiu %[i], %[i], -1 \n\t" "mul %[tmp1], %[tmp1], %[tmp2] \n\t" "mul %[tmp3], %[tmp3], %[tmp4] \n\t" "lh %[f_coef], 0(%[coefs]) \n\t" "lh %[s_coef], 2(%[coefs]) \n\t" "addiu %[load_ptr], %[load_ptr], 2 \n\t" "addiu %[hann], %[hann], 2 \n\t" "addiu %[hann1], %[hann1], -2 \n\t" "addu %[store_ptr1], %[fft], %[f_coef] \n\t" "addu %[store_ptr2], %[fft], %[s_coef] \n\t" "srav %[tmp1], %[tmp1], %[shift1] \n\t" "srav %[tmp3], %[tmp3], %[shift1] \n\t" "sh %[tmp1], 0(%[store_ptr1]) \n\t" "sh %[tmp3], 0(%[store_ptr2]) \n\t" "bgtz %[i], 2b \n\t" " addiu %[coefs], %[coefs], 4 \n\t" "3: " "\n\t" ".set pop \n\t" : [load_ptr] "=&r"(load_ptr), [shift] "=&r"(shift), [hann] "=&r"(hann), [hann1] "=&r"(hann1), [shift1] "=&r"(shift1), [coefs] "=&r"(coefs), [tmp1] "=&r"(tmp1), [tmp2] "=&r"(tmp2), [tmp3] "=&r"(tmp3), [tmp4] "=&r"(tmp4), [i] "=&r"(i), [f_coef] "=&r"(f_coef), [s_coef] "=&r"(s_coef), [store_ptr1] "=&r"(store_ptr1), [store_ptr2] "=&r"(store_ptr2) : [time_signal] "r"(time_signal), [coefTable] "r"(coefTable), [time_signal_scaling] "r"(time_signal_scaling), [hanning] "r"(WebRtcAecm_kSqrtHanning), [fft] "r"(fft) : "memory", "hi", "lo"); WebRtcSpl_ComplexFFT(fft, PART_LEN_SHIFT, 1); pfrfi = fft; pfreq_signal = freq_signal; __asm __volatile( ".set push " "\n\t" ".set noreorder " "\n\t" "addiu %[j], $zero, 128 " "\n\t" "1: " "\n\t" "lh %[tmp1], 0(%[pfrfi]) " "\n\t" "lh %[tmp2], 2(%[pfrfi]) " "\n\t" "lh %[tmp3], 4(%[pfrfi]) " "\n\t" "lh %[tmp4], 6(%[pfrfi]) " "\n\t" "subu %[tmp2], $zero, %[tmp2] " "\n\t" "sh %[tmp1], 0(%[pfreq_signal]) " "\n\t" "sh %[tmp2], 2(%[pfreq_signal]) " "\n\t" "subu %[tmp4], $zero, %[tmp4] " "\n\t" "sh %[tmp3], 4(%[pfreq_signal]) " "\n\t" "sh %[tmp4], 6(%[pfreq_signal]) " "\n\t" "lh %[tmp1], 8(%[pfrfi]) " "\n\t" "lh %[tmp2], 10(%[pfrfi]) " "\n\t" "lh %[tmp3], 12(%[pfrfi]) " "\n\t" "lh %[tmp4], 14(%[pfrfi]) " "\n\t" "addiu %[j], %[j], -8 " "\n\t" "subu %[tmp2], $zero, %[tmp2] " "\n\t" "sh %[tmp1], 8(%[pfreq_signal]) " "\n\t" "sh %[tmp2], 10(%[pfreq_signal]) " "\n\t" "subu %[tmp4], $zero, %[tmp4] " "\n\t" "sh %[tmp3], 12(%[pfreq_signal]) " "\n\t" "sh %[tmp4], 14(%[pfreq_signal]) " "\n\t" "addiu %[pfreq_signal], %[pfreq_signal], 16 " "\n\t" "bgtz %[j], 1b " "\n\t" " addiu %[pfrfi], %[pfrfi], 16 " "\n\t" ".set pop " "\n\t" : [tmp1] "=&r"(tmp1), [tmp2] "=&r"(tmp2), [tmp3] "=&r"(tmp3), [j] "=&r"(j), [pfrfi] "+r"(pfrfi), [pfreq_signal] "+r"(pfreq_signal), [tmp4] "=&r"(tmp4) : : "memory"); } static void InverseFFTAndWindow(AecmCore* aecm, int16_t* fft, ComplexInt16* efw, int16_t* output, const int16_t* nearendClean) { int i, outCFFT; int32_t tmp1, tmp2, tmp3, tmp4, tmp_re, tmp_im; int16_t* pcoefTable_ifft = coefTable_ifft; int16_t* pfft = fft; int16_t* ppfft = fft; ComplexInt16* pefw = efw; int32_t out_aecm; int16_t* paecm_buf = aecm->outBuf; const int16_t* p_kSqrtHanning = WebRtcAecm_kSqrtHanning; const int16_t* pp_kSqrtHanning = &WebRtcAecm_kSqrtHanning[PART_LEN]; int16_t* output1 = output; __asm __volatile( ".set push " "\n\t" ".set noreorder " "\n\t" "addiu %[i], $zero, 64 " "\n\t" "1: " "\n\t" "lh %[tmp1], 0(%[pcoefTable_ifft]) " "\n\t" "lh %[tmp2], 2(%[pcoefTable_ifft]) " "\n\t" "lh %[tmp_re], 0(%[pefw]) " "\n\t" "lh %[tmp_im], 2(%[pefw]) " "\n\t" "addu %[pfft], %[fft], %[tmp2] " "\n\t" "sh %[tmp_re], 0(%[pfft]) " "\n\t" "sh %[tmp_im], 2(%[pfft]) " "\n\t" "addu %[pfft], %[fft], %[tmp1] " "\n\t" "sh %[tmp_re], 0(%[pfft]) " "\n\t" "subu %[tmp_im], $zero, %[tmp_im] " "\n\t" "sh %[tmp_im], 2(%[pfft]) " "\n\t" "lh %[tmp1], 4(%[pcoefTable_ifft]) " "\n\t" "lh %[tmp2], 6(%[pcoefTable_ifft]) " "\n\t" "lh %[tmp_re], 4(%[pefw]) " "\n\t" "lh %[tmp_im], 6(%[pefw]) " "\n\t" "addu %[pfft], %[fft], %[tmp2] " "\n\t" "sh %[tmp_re], 0(%[pfft]) " "\n\t" "sh %[tmp_im], 2(%[pfft]) " "\n\t" "addu %[pfft], %[fft], %[tmp1] " "\n\t" "sh %[tmp_re], 0(%[pfft]) " "\n\t" "subu %[tmp_im], $zero, %[tmp_im] " "\n\t" "sh %[tmp_im], 2(%[pfft]) " "\n\t" "lh %[tmp1], 8(%[pcoefTable_ifft]) " "\n\t" "lh %[tmp2], 10(%[pcoefTable_ifft]) " "\n\t" "lh %[tmp_re], 8(%[pefw]) " "\n\t" "lh %[tmp_im], 10(%[pefw]) " "\n\t" "addu %[pfft], %[fft], %[tmp2] " "\n\t" "sh %[tmp_re], 0(%[pfft]) " "\n\t" "sh %[tmp_im], 2(%[pfft]) " "\n\t" "addu %[pfft], %[fft], %[tmp1] " "\n\t" "sh %[tmp_re], 0(%[pfft]) " "\n\t" "subu %[tmp_im], $zero, %[tmp_im] " "\n\t" "sh %[tmp_im], 2(%[pfft]) " "\n\t" "lh %[tmp1], 12(%[pcoefTable_ifft]) " "\n\t" "lh %[tmp2], 14(%[pcoefTable_ifft]) " "\n\t" "lh %[tmp_re], 12(%[pefw]) " "\n\t" "lh %[tmp_im], 14(%[pefw]) " "\n\t" "addu %[pfft], %[fft], %[tmp2] " "\n\t" "sh %[tmp_re], 0(%[pfft]) " "\n\t" "sh %[tmp_im], 2(%[pfft]) " "\n\t" "addu %[pfft], %[fft], %[tmp1] " "\n\t" "sh %[tmp_re], 0(%[pfft]) " "\n\t" "subu %[tmp_im], $zero, %[tmp_im] " "\n\t" "sh %[tmp_im], 2(%[pfft]) " "\n\t" "addiu %[pcoefTable_ifft], %[pcoefTable_ifft], 16 " "\n\t" "addiu %[i], %[i], -4 " "\n\t" "bgtz %[i], 1b " "\n\t" " addiu %[pefw], %[pefw], 16 " "\n\t" ".set pop " "\n\t" : [tmp1] "=&r"(tmp1), [tmp2] "=&r"(tmp2), [pfft] "+r"(pfft), [i] "=&r"(i), [tmp_re] "=&r"(tmp_re), [tmp_im] "=&r"(tmp_im), [pefw] "+r"(pefw), [pcoefTable_ifft] "+r"(pcoefTable_ifft), [fft] "+r"(fft) : : "memory"); fft[2] = efw[PART_LEN].real; fft[3] = -efw[PART_LEN].imag; outCFFT = WebRtcSpl_ComplexIFFT(fft, PART_LEN_SHIFT, 1); pfft = fft; __asm __volatile( ".set push \n\t" ".set noreorder \n\t" "addiu %[i], $zero, 128 \n\t" "1: \n\t" "lh %[tmp1], 0(%[ppfft]) \n\t" "lh %[tmp2], 4(%[ppfft]) \n\t" "lh %[tmp3], 8(%[ppfft]) \n\t" "lh %[tmp4], 12(%[ppfft]) \n\t" "addiu %[i], %[i], -4 \n\t" "sh %[tmp1], 0(%[pfft]) \n\t" "sh %[tmp2], 2(%[pfft]) \n\t" "sh %[tmp3], 4(%[pfft]) \n\t" "sh %[tmp4], 6(%[pfft]) \n\t" "addiu %[ppfft], %[ppfft], 16 \n\t" "bgtz %[i], 1b \n\t" " addiu %[pfft], %[pfft], 8 \n\t" ".set pop \n\t" : [tmp1] "=&r"(tmp1), [tmp2] "=&r"(tmp2), [pfft] "+r"(pfft), [i] "=&r"(i), [tmp3] "=&r"(tmp3), [tmp4] "=&r"(tmp4), [ppfft] "+r"(ppfft) : : "memory"); pfft = fft; out_aecm = (int32_t)(outCFFT - aecm->dfaCleanQDomain); __asm __volatile( ".set push " "\n\t" ".set noreorder " "\n\t" "addiu %[i], $zero, 64 " "\n\t" "11: " "\n\t" "lh %[tmp1], 0(%[pfft]) " "\n\t" "lh %[tmp2], 0(%[p_kSqrtHanning]) " "\n\t" "addiu %[i], %[i], -2 " "\n\t" "mul %[tmp1], %[tmp1], %[tmp2] " "\n\t" "lh %[tmp3], 2(%[pfft]) " "\n\t" "lh %[tmp4], 2(%[p_kSqrtHanning]) " "\n\t" "mul %[tmp3], %[tmp3], %[tmp4] " "\n\t" "addiu %[tmp1], %[tmp1], 8192 " "\n\t" "sra %[tmp1], %[tmp1], 14 " "\n\t" "addiu %[tmp3], %[tmp3], 8192 " "\n\t" "sra %[tmp3], %[tmp3], 14 " "\n\t" "bgez %[out_aecm], 1f " "\n\t" " negu %[tmp2], %[out_aecm] " "\n\t" "srav %[tmp1], %[tmp1], %[tmp2] " "\n\t" "b 2f " "\n\t" " srav %[tmp3], %[tmp3], %[tmp2] " "\n\t" "1: " "\n\t" "sllv %[tmp1], %[tmp1], %[out_aecm] " "\n\t" "sllv %[tmp3], %[tmp3], %[out_aecm] " "\n\t" "2: " "\n\t" "lh %[tmp4], 0(%[paecm_buf]) " "\n\t" "lh %[tmp2], 2(%[paecm_buf]) " "\n\t" "addu %[tmp3], %[tmp3], %[tmp2] " "\n\t" "addu %[tmp1], %[tmp1], %[tmp4] " "\n\t" #if defined(MIPS_DSP_R1_LE) "shll_s.w %[tmp1], %[tmp1], 16 " "\n\t" "sra %[tmp1], %[tmp1], 16 " "\n\t" "shll_s.w %[tmp3], %[tmp3], 16 " "\n\t" "sra %[tmp3], %[tmp3], 16 " "\n\t" #else // #if defined(MIPS_DSP_R1_LE) "sra %[tmp4], %[tmp1], 31 " "\n\t" "sra %[tmp2], %[tmp1], 15 " "\n\t" "beq %[tmp4], %[tmp2], 3f " "\n\t" " ori %[tmp2], $zero, 0x7fff " "\n\t" "xor %[tmp1], %[tmp2], %[tmp4] " "\n\t" "3: " "\n\t" "sra %[tmp2], %[tmp3], 31 " "\n\t" "sra %[tmp4], %[tmp3], 15 " "\n\t" "beq %[tmp2], %[tmp4], 4f " "\n\t" " ori %[tmp4], $zero, 0x7fff " "\n\t" "xor %[tmp3], %[tmp4], %[tmp2] " "\n\t" "4: " "\n\t" #endif // #if defined(MIPS_DSP_R1_LE) "sh %[tmp1], 0(%[pfft]) " "\n\t" "sh %[tmp1], 0(%[output1]) " "\n\t" "sh %[tmp3], 2(%[pfft]) " "\n\t" "sh %[tmp3], 2(%[output1]) " "\n\t" "lh %[tmp1], 128(%[pfft]) " "\n\t" "lh %[tmp2], 0(%[pp_kSqrtHanning]) " "\n\t" "mul %[tmp1], %[tmp1], %[tmp2] " "\n\t" "lh %[tmp3], 130(%[pfft]) " "\n\t" "lh %[tmp4], -2(%[pp_kSqrtHanning]) " "\n\t" "mul %[tmp3], %[tmp3], %[tmp4] " "\n\t" "sra %[tmp1], %[tmp1], 14 " "\n\t" "sra %[tmp3], %[tmp3], 14 " "\n\t" "bgez %[out_aecm], 5f " "\n\t" " negu %[tmp2], %[out_aecm] " "\n\t" "srav %[tmp3], %[tmp3], %[tmp2] " "\n\t" "b 6f " "\n\t" " srav %[tmp1], %[tmp1], %[tmp2] " "\n\t" "5: " "\n\t" "sllv %[tmp1], %[tmp1], %[out_aecm] " "\n\t" "sllv %[tmp3], %[tmp3], %[out_aecm] " "\n\t" "6: " "\n\t" #if defined(MIPS_DSP_R1_LE) "shll_s.w %[tmp1], %[tmp1], 16 " "\n\t" "sra %[tmp1], %[tmp1], 16 " "\n\t" "shll_s.w %[tmp3], %[tmp3], 16 " "\n\t" "sra %[tmp3], %[tmp3], 16 " "\n\t" #else // #if defined(MIPS_DSP_R1_LE) "sra %[tmp4], %[tmp1], 31 " "\n\t" "sra %[tmp2], %[tmp1], 15 " "\n\t" "beq %[tmp4], %[tmp2], 7f " "\n\t" " ori %[tmp2], $zero, 0x7fff " "\n\t" "xor %[tmp1], %[tmp2], %[tmp4] " "\n\t" "7: " "\n\t" "sra %[tmp2], %[tmp3], 31 " "\n\t" "sra %[tmp4], %[tmp3], 15 " "\n\t" "beq %[tmp2], %[tmp4], 8f " "\n\t" " ori %[tmp4], $zero, 0x7fff " "\n\t" "xor %[tmp3], %[tmp4], %[tmp2] " "\n\t" "8: " "\n\t" #endif // #if defined(MIPS_DSP_R1_LE) "sh %[tmp1], 0(%[paecm_buf]) " "\n\t" "sh %[tmp3], 2(%[paecm_buf]) " "\n\t" "addiu %[output1], %[output1], 4 " "\n\t" "addiu %[paecm_buf], %[paecm_buf], 4 " "\n\t" "addiu %[pfft], %[pfft], 4 " "\n\t" "addiu %[p_kSqrtHanning], %[p_kSqrtHanning], 4 " "\n\t" "bgtz %[i], 11b " "\n\t" " addiu %[pp_kSqrtHanning], %[pp_kSqrtHanning], -4 " "\n\t" ".set pop " "\n\t" : [tmp1] "=&r"(tmp1), [tmp2] "=&r"(tmp2), [pfft] "+r"(pfft), [output1] "+r"(output1), [tmp3] "=&r"(tmp3), [tmp4] "=&r"(tmp4), [paecm_buf] "+r"(paecm_buf), [i] "=&r"(i), [pp_kSqrtHanning] "+r"(pp_kSqrtHanning), [p_kSqrtHanning] "+r"(p_kSqrtHanning) : [out_aecm] "r"(out_aecm), [WebRtcAecm_kSqrtHanning] "r"(WebRtcAecm_kSqrtHanning) : "hi", "lo", "memory"); // Copy the current block to the old position // (aecm->outBuf is shifted elsewhere) memcpy(aecm->xBuf, aecm->xBuf + PART_LEN, sizeof(int16_t) * PART_LEN); memcpy(aecm->dBufNoisy, aecm->dBufNoisy + PART_LEN, sizeof(int16_t) * PART_LEN); if (nearendClean != NULL) { memcpy(aecm->dBufClean, aecm->dBufClean + PART_LEN, sizeof(int16_t) * PART_LEN); } } void WebRtcAecm_CalcLinearEnergies_mips(AecmCore* aecm, const uint16_t* far_spectrum, int32_t* echo_est, uint32_t* far_energy, uint32_t* echo_energy_adapt, uint32_t* echo_energy_stored) { int i; uint32_t par1 = (*far_energy); uint32_t par2 = (*echo_energy_adapt); uint32_t par3 = (*echo_energy_stored); int16_t* ch_stored_p = &(aecm->channelStored[0]); int16_t* ch_adapt_p = &(aecm->channelAdapt16[0]); uint16_t* spectrum_p = (uint16_t*)(&(far_spectrum[0])); int32_t* echo_p = &(echo_est[0]); int32_t temp0, stored0, echo0, adept0, spectrum0; int32_t stored1, adept1, spectrum1, echo1, temp1; // Get energy for the delayed far end signal and estimated // echo using both stored and adapted channels. for (i = 0; i < PART_LEN; i += 4) { __asm __volatile( ".set push \n\t" ".set noreorder \n\t" "lh %[stored0], 0(%[ch_stored_p]) \n\t" "lhu %[adept0], 0(%[ch_adapt_p]) \n\t" "lhu %[spectrum0], 0(%[spectrum_p]) \n\t" "lh %[stored1], 2(%[ch_stored_p]) \n\t" "lhu %[adept1], 2(%[ch_adapt_p]) \n\t" "lhu %[spectrum1], 2(%[spectrum_p]) \n\t" "mul %[echo0], %[stored0], %[spectrum0] \n\t" "mul %[temp0], %[adept0], %[spectrum0] \n\t" "mul %[echo1], %[stored1], %[spectrum1] \n\t" "mul %[temp1], %[adept1], %[spectrum1] \n\t" "addu %[par1], %[par1], %[spectrum0] \n\t" "addu %[par1], %[par1], %[spectrum1] \n\t" "addiu %[echo_p], %[echo_p], 16 \n\t" "addu %[par3], %[par3], %[echo0] \n\t" "addu %[par2], %[par2], %[temp0] \n\t" "addu %[par3], %[par3], %[echo1] \n\t" "addu %[par2], %[par2], %[temp1] \n\t" "usw %[echo0], -16(%[echo_p]) \n\t" "usw %[echo1], -12(%[echo_p]) \n\t" "lh %[stored0], 4(%[ch_stored_p]) \n\t" "lhu %[adept0], 4(%[ch_adapt_p]) \n\t" "lhu %[spectrum0], 4(%[spectrum_p]) \n\t" "lh %[stored1], 6(%[ch_stored_p]) \n\t" "lhu %[adept1], 6(%[ch_adapt_p]) \n\t" "lhu %[spectrum1], 6(%[spectrum_p]) \n\t" "mul %[echo0], %[stored0], %[spectrum0] \n\t" "mul %[temp0], %[adept0], %[spectrum0] \n\t" "mul %[echo1], %[stored1], %[spectrum1] \n\t" "mul %[temp1], %[adept1], %[spectrum1] \n\t" "addu %[par1], %[par1], %[spectrum0] \n\t" "addu %[par1], %[par1], %[spectrum1] \n\t" "addiu %[ch_stored_p], %[ch_stored_p], 8 \n\t" "addiu %[ch_adapt_p], %[ch_adapt_p], 8 \n\t" "addiu %[spectrum_p], %[spectrum_p], 8 \n\t" "addu %[par3], %[par3], %[echo0] \n\t" "addu %[par2], %[par2], %[temp0] \n\t" "addu %[par3], %[par3], %[echo1] \n\t" "addu %[par2], %[par2], %[temp1] \n\t" "usw %[echo0], -8(%[echo_p]) \n\t" "usw %[echo1], -4(%[echo_p]) \n\t" ".set pop \n\t" : [temp0] "=&r"(temp0), [stored0] "=&r"(stored0), [adept0] "=&r"(adept0), [spectrum0] "=&r"(spectrum0), [echo0] "=&r"(echo0), [echo_p] "+r"(echo_p), [par3] "+r"(par3), [par1] "+r"(par1), [par2] "+r"(par2), [stored1] "=&r"(stored1), [adept1] "=&r"(adept1), [echo1] "=&r"(echo1), [spectrum1] "=&r"(spectrum1), [temp1] "=&r"(temp1), [ch_stored_p] "+r"(ch_stored_p), [ch_adapt_p] "+r"(ch_adapt_p), [spectrum_p] "+r"(spectrum_p) : : "hi", "lo", "memory"); } echo_est[PART_LEN] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[PART_LEN], far_spectrum[PART_LEN]); par1 += (uint32_t)(far_spectrum[PART_LEN]); par2 += aecm->channelAdapt16[PART_LEN] * far_spectrum[PART_LEN]; par3 += (uint32_t)echo_est[PART_LEN]; (*far_energy) = par1; (*echo_energy_adapt) = par2; (*echo_energy_stored) = par3; } #if defined(MIPS_DSP_R1_LE) void WebRtcAecm_StoreAdaptiveChannel_mips(AecmCore* aecm, const uint16_t* far_spectrum, int32_t* echo_est) { int i; int16_t* temp1; uint16_t* temp8; int32_t temp0, temp2, temp3, temp4, temp5, temp6; int32_t* temp7 = &(echo_est[0]); temp1 = &(aecm->channelStored[0]); temp8 = (uint16_t*)(&far_spectrum[0]); // During startup we store the channel every block. memcpy(aecm->channelStored, aecm->channelAdapt16, sizeof(int16_t) * PART_LEN1); // Recalculate echo estimate for (i = 0; i < PART_LEN; i += 4) { __asm __volatile( "ulw %[temp0], 0(%[temp8]) \n\t" "ulw %[temp2], 0(%[temp1]) \n\t" "ulw %[temp4], 4(%[temp8]) \n\t" "ulw %[temp5], 4(%[temp1]) \n\t" "muleq_s.w.phl %[temp3], %[temp2], %[temp0] \n\t" "muleq_s.w.phr %[temp0], %[temp2], %[temp0] \n\t" "muleq_s.w.phl %[temp6], %[temp5], %[temp4] \n\t" "muleq_s.w.phr %[temp4], %[temp5], %[temp4] \n\t" "addiu %[temp7], %[temp7], 16 \n\t" "addiu %[temp1], %[temp1], 8 \n\t" "addiu %[temp8], %[temp8], 8 \n\t" "sra %[temp3], %[temp3], 1 \n\t" "sra %[temp0], %[temp0], 1 \n\t" "sra %[temp6], %[temp6], 1 \n\t" "sra %[temp4], %[temp4], 1 \n\t" "usw %[temp3], -12(%[temp7]) \n\t" "usw %[temp0], -16(%[temp7]) \n\t" "usw %[temp6], -4(%[temp7]) \n\t" "usw %[temp4], -8(%[temp7]) \n\t" : [temp0] "=&r"(temp0), [temp2] "=&r"(temp2), [temp3] "=&r"(temp3), [temp4] "=&r"(temp4), [temp5] "=&r"(temp5), [temp6] "=&r"(temp6), [temp1] "+r"(temp1), [temp8] "+r"(temp8), [temp7] "+r"(temp7) : : "hi", "lo", "memory"); } echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]); } void WebRtcAecm_ResetAdaptiveChannel_mips(AecmCore* aecm) { int i; int32_t* temp3; int16_t* temp0; int32_t temp1, temp2, temp4, temp5; temp0 = &(aecm->channelStored[0]); temp3 = &(aecm->channelAdapt32[0]); // The stored channel has a significantly lower MSE than the adaptive one for // two consecutive calculations. Reset the adaptive channel. memcpy(aecm->channelAdapt16, aecm->channelStored, sizeof(int16_t) * PART_LEN1); // Restore the W32 channel for (i = 0; i < PART_LEN; i += 4) { __asm __volatile( "ulw %[temp1], 0(%[temp0]) \n\t" "ulw %[temp4], 4(%[temp0]) \n\t" "preceq.w.phl %[temp2], %[temp1] \n\t" "preceq.w.phr %[temp1], %[temp1] \n\t" "preceq.w.phl %[temp5], %[temp4] \n\t" "preceq.w.phr %[temp4], %[temp4] \n\t" "addiu %[temp0], %[temp0], 8 \n\t" "usw %[temp2], 4(%[temp3]) \n\t" "usw %[temp1], 0(%[temp3]) \n\t" "usw %[temp5], 12(%[temp3]) \n\t" "usw %[temp4], 8(%[temp3]) \n\t" "addiu %[temp3], %[temp3], 16 \n\t" : [temp1] "=&r"(temp1), [temp2] "=&r"(temp2), [temp4] "=&r"(temp4), [temp5] "=&r"(temp5), [temp3] "+r"(temp3), [temp0] "+r"(temp0) : : "memory"); } aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16; } #endif // #if defined(MIPS_DSP_R1_LE) // Transforms a time domain signal into the frequency domain, outputting the // complex valued signal, absolute value and sum of absolute values. // // time_signal [in] Pointer to time domain signal // freq_signal_real [out] Pointer to real part of frequency domain array // freq_signal_imag [out] Pointer to imaginary part of frequency domain // array // freq_signal_abs [out] Pointer to absolute value of frequency domain // array // freq_signal_sum_abs [out] Pointer to the sum of all absolute values in // the frequency domain array // return value The Q-domain of current frequency values // static int TimeToFrequencyDomain(AecmCore* aecm, const int16_t* time_signal, ComplexInt16* freq_signal, uint16_t* freq_signal_abs, uint32_t* freq_signal_sum_abs) { int i = 0; int time_signal_scaling = 0; // In fft_buf, +16 for 32-byte alignment. int16_t fft_buf[PART_LEN4 + 16]; int16_t* fft = (int16_t*)(((uintptr_t)fft_buf + 31) & ~31); int16_t tmp16no1; #if !defined(MIPS_DSP_R2_LE) int32_t tmp32no1; int32_t tmp32no2; int16_t tmp16no2; #else int32_t tmp32no10, tmp32no11, tmp32no12, tmp32no13; int32_t tmp32no20, tmp32no21, tmp32no22, tmp32no23; int16_t* freqp; uint16_t* freqabsp; uint32_t freqt0, freqt1, freqt2, freqt3; uint32_t freqs; #endif #ifdef AECM_DYNAMIC_Q tmp16no1 = WebRtcSpl_MaxAbsValueW16(time_signal, PART_LEN2); time_signal_scaling = WebRtcSpl_NormW16(tmp16no1); #endif WindowAndFFT(aecm, fft, time_signal, freq_signal, time_signal_scaling); // Extract imaginary and real part, // calculate the magnitude for all frequency bins freq_signal[0].imag = 0; freq_signal[PART_LEN].imag = 0; freq_signal[PART_LEN].real = fft[PART_LEN2]; freq_signal_abs[0] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[0].real); freq_signal_abs[PART_LEN] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[PART_LEN].real); (*freq_signal_sum_abs) = (uint32_t)(freq_signal_abs[0]) + (uint32_t)(freq_signal_abs[PART_LEN]); #if !defined(MIPS_DSP_R2_LE) for (i = 1; i < PART_LEN; i++) { if (freq_signal[i].real == 0) { freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[i].imag); } else if (freq_signal[i].imag == 0) { freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[i].real); } else { // Approximation for magnitude of complex fft output // magn = sqrt(real^2 + imag^2) // magn ~= alpha * max(|imag|,|real|) + beta * min(|imag|,|real|) // // The parameters alpha and beta are stored in Q15 tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real); tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag); tmp32no1 = tmp16no1 * tmp16no1; tmp32no2 = tmp16no2 * tmp16no2; tmp32no2 = WebRtcSpl_AddSatW32(tmp32no1, tmp32no2); tmp32no1 = WebRtcSpl_SqrtFloor(tmp32no2); freq_signal_abs[i] = (uint16_t)tmp32no1; } (*freq_signal_sum_abs) += (uint32_t)freq_signal_abs[i]; } #else // #if !defined(MIPS_DSP_R2_LE) freqs = (uint32_t)(freq_signal_abs[0]) + (uint32_t)(freq_signal_abs[PART_LEN]); freqp = &(freq_signal[1].real); __asm __volatile( "lw %[freqt0], 0(%[freqp]) \n\t" "lw %[freqt1], 4(%[freqp]) \n\t" "lw %[freqt2], 8(%[freqp]) \n\t" "mult $ac0, $zero, $zero \n\t" "mult $ac1, $zero, $zero \n\t" "mult $ac2, $zero, $zero \n\t" "dpaq_s.w.ph $ac0, %[freqt0], %[freqt0] \n\t" "dpaq_s.w.ph $ac1, %[freqt1], %[freqt1] \n\t" "dpaq_s.w.ph $ac2, %[freqt2], %[freqt2] \n\t" "addiu %[freqp], %[freqp], 12 \n\t" "extr.w %[tmp32no20], $ac0, 1 \n\t" "extr.w %[tmp32no21], $ac1, 1 \n\t" "extr.w %[tmp32no22], $ac2, 1 \n\t" : [freqt0] "=&r"(freqt0), [freqt1] "=&r"(freqt1), [freqt2] "=&r"(freqt2), [freqp] "+r"(freqp), [tmp32no20] "=r"(tmp32no20), [tmp32no21] "=r"(tmp32no21), [tmp32no22] "=r"(tmp32no22) : : "memory", "hi", "lo", "$ac1hi", "$ac1lo", "$ac2hi", "$ac2lo"); tmp32no10 = WebRtcSpl_SqrtFloor(tmp32no20); tmp32no11 = WebRtcSpl_SqrtFloor(tmp32no21); tmp32no12 = WebRtcSpl_SqrtFloor(tmp32no22); freq_signal_abs[1] = (uint16_t)tmp32no10; freq_signal_abs[2] = (uint16_t)tmp32no11; freq_signal_abs[3] = (uint16_t)tmp32no12; freqs += (uint32_t)tmp32no10; freqs += (uint32_t)tmp32no11; freqs += (uint32_t)tmp32no12; freqabsp = &(freq_signal_abs[4]); for (i = 4; i < PART_LEN; i += 4) { __asm __volatile( "ulw %[freqt0], 0(%[freqp]) \n\t" "ulw %[freqt1], 4(%[freqp]) \n\t" "ulw %[freqt2], 8(%[freqp]) \n\t" "ulw %[freqt3], 12(%[freqp]) \n\t" "mult $ac0, $zero, $zero \n\t" "mult $ac1, $zero, $zero \n\t" "mult $ac2, $zero, $zero \n\t" "mult $ac3, $zero, $zero \n\t" "dpaq_s.w.ph $ac0, %[freqt0], %[freqt0] \n\t" "dpaq_s.w.ph $ac1, %[freqt1], %[freqt1] \n\t" "dpaq_s.w.ph $ac2, %[freqt2], %[freqt2] \n\t" "dpaq_s.w.ph $ac3, %[freqt3], %[freqt3] \n\t" "addiu %[freqp], %[freqp], 16 \n\t" "addiu %[freqabsp], %[freqabsp], 8 \n\t" "extr.w %[tmp32no20], $ac0, 1 \n\t" "extr.w %[tmp32no21], $ac1, 1 \n\t" "extr.w %[tmp32no22], $ac2, 1 \n\t" "extr.w %[tmp32no23], $ac3, 1 \n\t" : [freqt0] "=&r"(freqt0), [freqt1] "=&r"(freqt1), [freqt2] "=&r"(freqt2), [freqt3] "=&r"(freqt3), [tmp32no20] "=r"(tmp32no20), [tmp32no21] "=r"(tmp32no21), [tmp32no22] "=r"(tmp32no22), [tmp32no23] "=r"(tmp32no23), [freqabsp] "+r"(freqabsp), [freqp] "+r"(freqp) : : "memory", "hi", "lo", "$ac1hi", "$ac1lo", "$ac2hi", "$ac2lo", "$ac3hi", "$ac3lo"); tmp32no10 = WebRtcSpl_SqrtFloor(tmp32no20); tmp32no11 = WebRtcSpl_SqrtFloor(tmp32no21); tmp32no12 = WebRtcSpl_SqrtFloor(tmp32no22); tmp32no13 = WebRtcSpl_SqrtFloor(tmp32no23); __asm __volatile( "sh %[tmp32no10], -8(%[freqabsp]) \n\t" "sh %[tmp32no11], -6(%[freqabsp]) \n\t" "sh %[tmp32no12], -4(%[freqabsp]) \n\t" "sh %[tmp32no13], -2(%[freqabsp]) \n\t" "addu %[freqs], %[freqs], %[tmp32no10] \n\t" "addu %[freqs], %[freqs], %[tmp32no11] \n\t" "addu %[freqs], %[freqs], %[tmp32no12] \n\t" "addu %[freqs], %[freqs], %[tmp32no13] \n\t" : [freqs] "+r"(freqs) : [tmp32no10] "r"(tmp32no10), [tmp32no11] "r"(tmp32no11), [tmp32no12] "r"(tmp32no12), [tmp32no13] "r"(tmp32no13), [freqabsp] "r"(freqabsp) : "memory"); } (*freq_signal_sum_abs) = freqs; #endif return time_signal_scaling; } int WebRtcAecm_ProcessBlock(AecmCore* aecm, const int16_t* farend, const int16_t* nearendNoisy, const int16_t* nearendClean, int16_t* output) { int i; uint32_t xfaSum; uint32_t dfaNoisySum; uint32_t dfaCleanSum; uint32_t echoEst32Gained; uint32_t tmpU32; int32_t tmp32no1; uint16_t xfa[PART_LEN1]; uint16_t dfaNoisy[PART_LEN1]; uint16_t dfaClean[PART_LEN1]; uint16_t* ptrDfaClean = dfaClean; const uint16_t* far_spectrum_ptr = NULL; // 32 byte aligned buffers (with +8 or +16). int16_t fft_buf[PART_LEN4 + 2 + 16]; // +2 to make a loop safe. int32_t echoEst32_buf[PART_LEN1 + 8]; int32_t dfw_buf[PART_LEN2 + 8]; int32_t efw_buf[PART_LEN2 + 8]; int16_t* fft = (int16_t*)(((uint32_t)fft_buf + 31) & ~31); int32_t* echoEst32 = (int32_t*)(((uint32_t)echoEst32_buf + 31) & ~31); ComplexInt16* dfw = (ComplexInt16*)(((uint32_t)dfw_buf + 31) & ~31); ComplexInt16* efw = (ComplexInt16*)(((uint32_t)efw_buf + 31) & ~31); int16_t hnl[PART_LEN1]; int16_t numPosCoef = 0; int delay; int16_t tmp16no1; int16_t tmp16no2; int16_t mu; int16_t supGain; int16_t zeros32, zeros16; int16_t zerosDBufNoisy, zerosDBufClean, zerosXBuf; int far_q; int16_t resolutionDiff, qDomainDiff, dfa_clean_q_domain_diff; const int kMinPrefBand = 4; const int kMaxPrefBand = 24; int32_t avgHnl32 = 0; int32_t temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8; int16_t* ptr; int16_t* ptr1; int16_t* er_ptr; int16_t* dr_ptr; ptr = &hnl[0]; ptr1 = &hnl[0]; er_ptr = &efw[0].real; dr_ptr = &dfw[0].real; // Determine startup state. There are three states: // (0) the first CONV_LEN blocks // (1) another CONV_LEN blocks // (2) the rest if (aecm->startupState < 2) { aecm->startupState = (aecm->totCount >= CONV_LEN) + (aecm->totCount >= CONV_LEN2); } // END: Determine startup state // Buffer near and far end signals memcpy(aecm->xBuf + PART_LEN, farend, sizeof(int16_t) * PART_LEN); memcpy(aecm->dBufNoisy + PART_LEN, nearendNoisy, sizeof(int16_t) * PART_LEN); if (nearendClean != NULL) { memcpy(aecm->dBufClean + PART_LEN, nearendClean, sizeof(int16_t) * PART_LEN); } // Transform far end signal from time domain to frequency domain. far_q = TimeToFrequencyDomain(aecm, aecm->xBuf, dfw, xfa, &xfaSum); // Transform noisy near end signal from time domain to frequency domain. zerosDBufNoisy = TimeToFrequencyDomain(aecm, aecm->dBufNoisy, dfw, dfaNoisy, &dfaNoisySum); aecm->dfaNoisyQDomainOld = aecm->dfaNoisyQDomain; aecm->dfaNoisyQDomain = (int16_t)zerosDBufNoisy; if (nearendClean == NULL) { ptrDfaClean = dfaNoisy; aecm->dfaCleanQDomainOld = aecm->dfaNoisyQDomainOld; aecm->dfaCleanQDomain = aecm->dfaNoisyQDomain; dfaCleanSum = dfaNoisySum; } else { // Transform clean near end signal from time domain to frequency domain. zerosDBufClean = TimeToFrequencyDomain(aecm, aecm->dBufClean, dfw, dfaClean, &dfaCleanSum); aecm->dfaCleanQDomainOld = aecm->dfaCleanQDomain; aecm->dfaCleanQDomain = (int16_t)zerosDBufClean; } // Get the delay // Save far-end history and estimate delay WebRtcAecm_UpdateFarHistory(aecm, xfa, far_q); if (WebRtc_AddFarSpectrumFix(aecm->delay_estimator_farend, xfa, PART_LEN1, far_q) == -1) { return -1; } delay = WebRtc_DelayEstimatorProcessFix(aecm->delay_estimator, dfaNoisy, PART_LEN1, zerosDBufNoisy); if (delay == -1) { return -1; } else if (delay == -2) { // If the delay is unknown, we assume zero. // NOTE: this will have to be adjusted if we ever add lookahead. delay = 0; } if (aecm->fixedDelay >= 0) { // Use fixed delay delay = aecm->fixedDelay; } // Get aligned far end spectrum far_spectrum_ptr = WebRtcAecm_AlignedFarend(aecm, &far_q, delay); zerosXBuf = (int16_t)far_q; if (far_spectrum_ptr == NULL) { return -1; } // Calculate log(energy) and update energy threshold levels WebRtcAecm_CalcEnergies(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisySum, echoEst32); // Calculate stepsize mu = WebRtcAecm_CalcStepSize(aecm); // Update counters aecm->totCount++; // This is the channel estimation algorithm. // It is base on NLMS but has a variable step length, // which was calculated above. WebRtcAecm_UpdateChannel(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisy, mu, echoEst32); supGain = WebRtcAecm_CalcSuppressionGain(aecm); // Calculate Wiener filter hnl[] for (i = 0; i < PART_LEN1; i++) { // Far end signal through channel estimate in Q8 // How much can we shift right to preserve resolution tmp32no1 = echoEst32[i] - aecm->echoFilt[i]; aecm->echoFilt[i] += rtc::dchecked_cast((int64_t{tmp32no1} * 50) >> 8); zeros32 = WebRtcSpl_NormW32(aecm->echoFilt[i]) + 1; zeros16 = WebRtcSpl_NormW16(supGain) + 1; if (zeros32 + zeros16 > 16) { // Multiplication is safe // Result in // Q(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN+aecm->xfaQDomainBuf[diff]) echoEst32Gained = WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i], (uint16_t)supGain); resolutionDiff = 14 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN; resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf); } else { tmp16no1 = 17 - zeros32 - zeros16; resolutionDiff = 14 + tmp16no1 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN; resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf); if (zeros32 > tmp16no1) { echoEst32Gained = WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i], supGain >> tmp16no1); } else { // Result in Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16) echoEst32Gained = (aecm->echoFilt[i] >> tmp16no1) * supGain; } } zeros16 = WebRtcSpl_NormW16(aecm->nearFilt[i]); RTC_DCHECK_GE(zeros16, 0); // |zeros16| is a norm, hence non-negative. dfa_clean_q_domain_diff = aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld; if (zeros16 < dfa_clean_q_domain_diff && aecm->nearFilt[i]) { tmp16no1 = aecm->nearFilt[i] << zeros16; qDomainDiff = zeros16 - dfa_clean_q_domain_diff; tmp16no2 = ptrDfaClean[i] >> -qDomainDiff; } else { tmp16no1 = dfa_clean_q_domain_diff < 0 ? aecm->nearFilt[i] >> -dfa_clean_q_domain_diff : aecm->nearFilt[i] << dfa_clean_q_domain_diff; qDomainDiff = 0; tmp16no2 = ptrDfaClean[i]; } tmp32no1 = (int32_t)(tmp16no2 - tmp16no1); tmp16no2 = (int16_t)(tmp32no1 >> 4); tmp16no2 += tmp16no1; zeros16 = WebRtcSpl_NormW16(tmp16no2); if ((tmp16no2) & (-qDomainDiff > zeros16)) { aecm->nearFilt[i] = WEBRTC_SPL_WORD16_MAX; } else { aecm->nearFilt[i] = qDomainDiff < 0 ? tmp16no2 << -qDomainDiff : tmp16no2 >> qDomainDiff; } // Wiener filter coefficients, resulting hnl in Q14 if (echoEst32Gained == 0) { hnl[i] = ONE_Q14; numPosCoef++; } else if (aecm->nearFilt[i] == 0) { hnl[i] = 0; } else { // Multiply the suppression gain // Rounding echoEst32Gained += (uint32_t)(aecm->nearFilt[i] >> 1); tmpU32 = WebRtcSpl_DivU32U16(echoEst32Gained, (uint16_t)aecm->nearFilt[i]); // Current resolution is // Q-(RESOLUTION_CHANNEL + RESOLUTION_SUPGAIN // - max(0, 17 - zeros16 - zeros32)) // Make sure we are in Q14 tmp32no1 = (int32_t)WEBRTC_SPL_SHIFT_W32(tmpU32, resolutionDiff); if (tmp32no1 > ONE_Q14) { hnl[i] = 0; } else if (tmp32no1 < 0) { hnl[i] = ONE_Q14; numPosCoef++; } else { // 1-echoEst/dfa hnl[i] = ONE_Q14 - (int16_t)tmp32no1; if (hnl[i] <= 0) { hnl[i] = 0; } else { numPosCoef++; } } } } // Only in wideband. Prevent the gain in upper band from being larger than // in lower band. if (aecm->mult == 2) { // TODO(bjornv): Investigate if the scaling of hnl[i] below can cause // speech distortion in double-talk. for (i = 0; i < (PART_LEN1 >> 3); i++) { __asm __volatile( "lh %[temp1], 0(%[ptr1]) \n\t" "lh %[temp2], 2(%[ptr1]) \n\t" "lh %[temp3], 4(%[ptr1]) \n\t" "lh %[temp4], 6(%[ptr1]) \n\t" "lh %[temp5], 8(%[ptr1]) \n\t" "lh %[temp6], 10(%[ptr1]) \n\t" "lh %[temp7], 12(%[ptr1]) \n\t" "lh %[temp8], 14(%[ptr1]) \n\t" "mul %[temp1], %[temp1], %[temp1] \n\t" "mul %[temp2], %[temp2], %[temp2] \n\t" "mul %[temp3], %[temp3], %[temp3] \n\t" "mul %[temp4], %[temp4], %[temp4] \n\t" "mul %[temp5], %[temp5], %[temp5] \n\t" "mul %[temp6], %[temp6], %[temp6] \n\t" "mul %[temp7], %[temp7], %[temp7] \n\t" "mul %[temp8], %[temp8], %[temp8] \n\t" "sra %[temp1], %[temp1], 14 \n\t" "sra %[temp2], %[temp2], 14 \n\t" "sra %[temp3], %[temp3], 14 \n\t" "sra %[temp4], %[temp4], 14 \n\t" "sra %[temp5], %[temp5], 14 \n\t" "sra %[temp6], %[temp6], 14 \n\t" "sra %[temp7], %[temp7], 14 \n\t" "sra %[temp8], %[temp8], 14 \n\t" "sh %[temp1], 0(%[ptr1]) \n\t" "sh %[temp2], 2(%[ptr1]) \n\t" "sh %[temp3], 4(%[ptr1]) \n\t" "sh %[temp4], 6(%[ptr1]) \n\t" "sh %[temp5], 8(%[ptr1]) \n\t" "sh %[temp6], 10(%[ptr1]) \n\t" "sh %[temp7], 12(%[ptr1]) \n\t" "sh %[temp8], 14(%[ptr1]) \n\t" "addiu %[ptr1], %[ptr1], 16 \n\t" : [temp1] "=&r"(temp1), [temp2] "=&r"(temp2), [temp3] "=&r"(temp3), [temp4] "=&r"(temp4), [temp5] "=&r"(temp5), [temp6] "=&r"(temp6), [temp7] "=&r"(temp7), [temp8] "=&r"(temp8), [ptr1] "+r"(ptr1) : : "memory", "hi", "lo"); } for (i = 0; i < (PART_LEN1 & 7); i++) { __asm __volatile( "lh %[temp1], 0(%[ptr1]) \n\t" "mul %[temp1], %[temp1], %[temp1] \n\t" "sra %[temp1], %[temp1], 14 \n\t" "sh %[temp1], 0(%[ptr1]) \n\t" "addiu %[ptr1], %[ptr1], 2 \n\t" : [temp1] "=&r"(temp1), [ptr1] "+r"(ptr1) : : "memory", "hi", "lo"); } for (i = kMinPrefBand; i <= kMaxPrefBand; i++) { avgHnl32 += (int32_t)hnl[i]; } RTC_DCHECK_GT(kMaxPrefBand - kMinPrefBand + 1, 0); avgHnl32 /= (kMaxPrefBand - kMinPrefBand + 1); for (i = kMaxPrefBand; i < PART_LEN1; i++) { if (hnl[i] > (int16_t)avgHnl32) { hnl[i] = (int16_t)avgHnl32; } } } // Calculate NLP gain, result is in Q14 if (aecm->nlpFlag) { if (numPosCoef < 3) { for (i = 0; i < PART_LEN1; i++) { efw[i].real = 0; efw[i].imag = 0; hnl[i] = 0; } } else { for (i = 0; i < PART_LEN1; i++) { #if defined(MIPS_DSP_R1_LE) __asm __volatile( ".set push \n\t" ".set noreorder \n\t" "lh %[temp1], 0(%[ptr]) \n\t" "lh %[temp2], 0(%[dr_ptr]) \n\t" "slti %[temp4], %[temp1], 0x4001 \n\t" "beqz %[temp4], 3f \n\t" " lh %[temp3], 2(%[dr_ptr]) \n\t" "slti %[temp5], %[temp1], 3277 \n\t" "bnez %[temp5], 2f \n\t" " addiu %[dr_ptr], %[dr_ptr], 4 \n\t" "mul %[temp2], %[temp2], %[temp1] \n\t" "mul %[temp3], %[temp3], %[temp1] \n\t" "shra_r.w %[temp2], %[temp2], 14 \n\t" "shra_r.w %[temp3], %[temp3], 14 \n\t" "b 4f \n\t" " nop \n\t" "2: \n\t" "addu %[temp1], $zero, $zero \n\t" "addu %[temp2], $zero, $zero \n\t" "addu %[temp3], $zero, $zero \n\t" "b 1f \n\t" " nop \n\t" "3: \n\t" "addiu %[temp1], $0, 0x4000 \n\t" "1: \n\t" "sh %[temp1], 0(%[ptr]) \n\t" "4: \n\t" "sh %[temp2], 0(%[er_ptr]) \n\t" "sh %[temp3], 2(%[er_ptr]) \n\t" "addiu %[ptr], %[ptr], 2 \n\t" "addiu %[er_ptr], %[er_ptr], 4 \n\t" ".set pop \n\t" : [temp1] "=&r"(temp1), [temp2] "=&r"(temp2), [temp3] "=&r"(temp3), [temp4] "=&r"(temp4), [temp5] "=&r"(temp5), [ptr] "+r"(ptr), [er_ptr] "+r"(er_ptr), [dr_ptr] "+r"(dr_ptr) : : "memory", "hi", "lo"); #else __asm __volatile( ".set push \n\t" ".set noreorder \n\t" "lh %[temp1], 0(%[ptr]) \n\t" "lh %[temp2], 0(%[dr_ptr]) \n\t" "slti %[temp4], %[temp1], 0x4001 \n\t" "beqz %[temp4], 3f \n\t" " lh %[temp3], 2(%[dr_ptr]) \n\t" "slti %[temp5], %[temp1], 3277 \n\t" "bnez %[temp5], 2f \n\t" " addiu %[dr_ptr], %[dr_ptr], 4 \n\t" "mul %[temp2], %[temp2], %[temp1] \n\t" "mul %[temp3], %[temp3], %[temp1] \n\t" "addiu %[temp2], %[temp2], 0x2000 \n\t" "addiu %[temp3], %[temp3], 0x2000 \n\t" "sra %[temp2], %[temp2], 14 \n\t" "sra %[temp3], %[temp3], 14 \n\t" "b 4f \n\t" " nop \n\t" "2: \n\t" "addu %[temp1], $zero, $zero \n\t" "addu %[temp2], $zero, $zero \n\t" "addu %[temp3], $zero, $zero \n\t" "b 1f \n\t" " nop \n\t" "3: \n\t" "addiu %[temp1], $0, 0x4000 \n\t" "1: \n\t" "sh %[temp1], 0(%[ptr]) \n\t" "4: \n\t" "sh %[temp2], 0(%[er_ptr]) \n\t" "sh %[temp3], 2(%[er_ptr]) \n\t" "addiu %[ptr], %[ptr], 2 \n\t" "addiu %[er_ptr], %[er_ptr], 4 \n\t" ".set pop \n\t" : [temp1] "=&r"(temp1), [temp2] "=&r"(temp2), [temp3] "=&r"(temp3), [temp4] "=&r"(temp4), [temp5] "=&r"(temp5), [ptr] "+r"(ptr), [er_ptr] "+r"(er_ptr), [dr_ptr] "+r"(dr_ptr) : : "memory", "hi", "lo"); #endif } } } else { // multiply with Wiener coefficients for (i = 0; i < PART_LEN1; i++) { efw[i].real = (int16_t)( WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real, hnl[i], 14)); efw[i].imag = (int16_t)( WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag, hnl[i], 14)); } } if (aecm->cngMode == AecmTrue) { ComfortNoise(aecm, ptrDfaClean, efw, hnl); } InverseFFTAndWindow(aecm, fft, efw, output, nearendClean); return 0; } // Generate comfort noise and add to output signal. static void ComfortNoise(AecmCore* aecm, const uint16_t* dfa, ComplexInt16* out, const int16_t* lambda) { int16_t i; int16_t tmp16, tmp161, tmp162, tmp163, nrsh1, nrsh2; int32_t tmp32, tmp321, tnoise, tnoise1; int32_t tmp322, tmp323, *tmp1; int16_t* dfap; int16_t* lambdap; const int32_t c2049 = 2049; const int32_t c359 = 359; const int32_t c114 = ONE_Q14; int16_t randW16[PART_LEN]; int16_t uReal[PART_LEN1]; int16_t uImag[PART_LEN1]; int32_t outLShift32; int16_t shiftFromNearToNoise = kNoiseEstQDomain - aecm->dfaCleanQDomain; int16_t minTrackShift = 9; RTC_DCHECK_GE(shiftFromNearToNoise, 0); RTC_DCHECK_LT(shiftFromNearToNoise, 16); if (aecm->noiseEstCtr < 100) { // Track the minimum more quickly initially. aecm->noiseEstCtr++; minTrackShift = 6; } // Generate a uniform random array on [0 2^15-1]. WebRtcSpl_RandUArray(randW16, PART_LEN, &aecm->seed); int16_t* randW16p = (int16_t*)randW16; #if defined(MIPS_DSP_R1_LE) int16_t* kCosTablep = (int16_t*)WebRtcAecm_kCosTable; int16_t* kSinTablep = (int16_t*)WebRtcAecm_kSinTable; #endif // #if defined(MIPS_DSP_R1_LE) tmp1 = (int32_t*)aecm->noiseEst + 1; dfap = (int16_t*)dfa + 1; lambdap = (int16_t*)lambda + 1; // Estimate noise power. for (i = 1; i < PART_LEN1; i += 2) { // Shift to the noise domain. __asm __volatile( "lh %[tmp32], 0(%[dfap]) \n\t" "lw %[tnoise], 0(%[tmp1]) \n\t" "sllv %[outLShift32], %[tmp32], %[shiftFromNearToNoise] \n\t" : [tmp32] "=&r"(tmp32), [outLShift32] "=r"(outLShift32), [tnoise] "=&r"(tnoise) : [tmp1] "r"(tmp1), [dfap] "r"(dfap), [shiftFromNearToNoise] "r"(shiftFromNearToNoise) : "memory"); if (outLShift32 < tnoise) { // Reset "too low" counter aecm->noiseEstTooLowCtr[i] = 0; // Track the minimum. if (tnoise < (1 << minTrackShift)) { // For small values, decrease noiseEst[i] every // |kNoiseEstIncCount| block. The regular approach below can not // go further down due to truncation. aecm->noiseEstTooHighCtr[i]++; if (aecm->noiseEstTooHighCtr[i] >= kNoiseEstIncCount) { tnoise--; aecm->noiseEstTooHighCtr[i] = 0; // Reset the counter } } else { __asm __volatile( "subu %[tmp32], %[tnoise], %[outLShift32] \n\t" "srav %[tmp32], %[tmp32], %[minTrackShift] \n\t" "subu %[tnoise], %[tnoise], %[tmp32] \n\t" : [tmp32] "=&r"(tmp32), [tnoise] "+r"(tnoise) : [outLShift32] "r"(outLShift32), [minTrackShift] "r"(minTrackShift)); } } else { // Reset "too high" counter aecm->noiseEstTooHighCtr[i] = 0; // Ramp slowly upwards until we hit the minimum again. if ((tnoise >> 19) <= 0) { if ((tnoise >> 11) > 0) { // Large enough for relative increase __asm __volatile( "mul %[tnoise], %[tnoise], %[c2049] \n\t" "sra %[tnoise], %[tnoise], 11 \n\t" : [tnoise] "+r"(tnoise) : [c2049] "r"(c2049) : "hi", "lo"); } else { // Make incremental increases based on size every // |kNoiseEstIncCount| block aecm->noiseEstTooLowCtr[i]++; if (aecm->noiseEstTooLowCtr[i] >= kNoiseEstIncCount) { __asm __volatile( "sra %[tmp32], %[tnoise], 9 \n\t" "addi %[tnoise], %[tnoise], 1 \n\t" "addu %[tnoise], %[tnoise], %[tmp32] \n\t" : [tnoise] "+r"(tnoise), [tmp32] "=&r"(tmp32) :); aecm->noiseEstTooLowCtr[i] = 0; // Reset counter } } } else { // Avoid overflow. // Multiplication with 2049 will cause wrap around. Scale // down first and then multiply __asm __volatile( "sra %[tnoise], %[tnoise], 11 \n\t" "mul %[tnoise], %[tnoise], %[c2049] \n\t" : [tnoise] "+r"(tnoise) : [c2049] "r"(c2049) : "hi", "lo"); } } // Shift to the noise domain. __asm __volatile( "lh %[tmp32], 2(%[dfap]) \n\t" "lw %[tnoise1], 4(%[tmp1]) \n\t" "addiu %[dfap], %[dfap], 4 \n\t" "sllv %[outLShift32], %[tmp32], %[shiftFromNearToNoise] \n\t" : [tmp32] "=&r"(tmp32), [dfap] "+r"(dfap), [outLShift32] "=r"(outLShift32), [tnoise1] "=&r"(tnoise1) : [tmp1] "r"(tmp1), [shiftFromNearToNoise] "r"(shiftFromNearToNoise) : "memory"); if (outLShift32 < tnoise1) { // Reset "too low" counter aecm->noiseEstTooLowCtr[i + 1] = 0; // Track the minimum. if (tnoise1 < (1 << minTrackShift)) { // For small values, decrease noiseEst[i] every // |kNoiseEstIncCount| block. The regular approach below can not // go further down due to truncation. aecm->noiseEstTooHighCtr[i + 1]++; if (aecm->noiseEstTooHighCtr[i + 1] >= kNoiseEstIncCount) { tnoise1--; aecm->noiseEstTooHighCtr[i + 1] = 0; // Reset the counter } } else { __asm __volatile( "subu %[tmp32], %[tnoise1], %[outLShift32] \n\t" "srav %[tmp32], %[tmp32], %[minTrackShift] \n\t" "subu %[tnoise1], %[tnoise1], %[tmp32] \n\t" : [tmp32] "=&r"(tmp32), [tnoise1] "+r"(tnoise1) : [outLShift32] "r"(outLShift32), [minTrackShift] "r"(minTrackShift)); } } else { // Reset "too high" counter aecm->noiseEstTooHighCtr[i + 1] = 0; // Ramp slowly upwards until we hit the minimum again. if ((tnoise1 >> 19) <= 0) { if ((tnoise1 >> 11) > 0) { // Large enough for relative increase __asm __volatile( "mul %[tnoise1], %[tnoise1], %[c2049] \n\t" "sra %[tnoise1], %[tnoise1], 11 \n\t" : [tnoise1] "+r"(tnoise1) : [c2049] "r"(c2049) : "hi", "lo"); } else { // Make incremental increases based on size every // |kNoiseEstIncCount| block aecm->noiseEstTooLowCtr[i + 1]++; if (aecm->noiseEstTooLowCtr[i + 1] >= kNoiseEstIncCount) { __asm __volatile( "sra %[tmp32], %[tnoise1], 9 \n\t" "addi %[tnoise1], %[tnoise1], 1 \n\t" "addu %[tnoise1], %[tnoise1], %[tmp32] \n\t" : [tnoise1] "+r"(tnoise1), [tmp32] "=&r"(tmp32) :); aecm->noiseEstTooLowCtr[i + 1] = 0; // Reset counter } } } else { // Avoid overflow. // Multiplication with 2049 will cause wrap around. Scale // down first and then multiply __asm __volatile( "sra %[tnoise1], %[tnoise1], 11 \n\t" "mul %[tnoise1], %[tnoise1], %[c2049] \n\t" : [tnoise1] "+r"(tnoise1) : [c2049] "r"(c2049) : "hi", "lo"); } } __asm __volatile( "lh %[tmp16], 0(%[lambdap]) \n\t" "lh %[tmp161], 2(%[lambdap]) \n\t" "sw %[tnoise], 0(%[tmp1]) \n\t" "sw %[tnoise1], 4(%[tmp1]) \n\t" "subu %[tmp16], %[c114], %[tmp16] \n\t" "subu %[tmp161], %[c114], %[tmp161] \n\t" "srav %[tmp32], %[tnoise], %[shiftFromNearToNoise] \n\t" "srav %[tmp321], %[tnoise1], %[shiftFromNearToNoise] \n\t" "addiu %[lambdap], %[lambdap], 4 \n\t" "addiu %[tmp1], %[tmp1], 8 \n\t" : [tmp16] "=&r"(tmp16), [tmp161] "=&r"(tmp161), [tmp1] "+r"(tmp1), [tmp32] "=&r"(tmp32), [tmp321] "=&r"(tmp321), [lambdap] "+r"(lambdap) : [tnoise] "r"(tnoise), [tnoise1] "r"(tnoise1), [c114] "r"(c114), [shiftFromNearToNoise] "r"(shiftFromNearToNoise) : "memory"); if (tmp32 > 32767) { tmp32 = 32767; aecm->noiseEst[i] = tmp32 << shiftFromNearToNoise; } if (tmp321 > 32767) { tmp321 = 32767; aecm->noiseEst[i + 1] = tmp321 << shiftFromNearToNoise; } __asm __volatile( "mul %[tmp32], %[tmp32], %[tmp16] \n\t" "mul %[tmp321], %[tmp321], %[tmp161] \n\t" "sra %[nrsh1], %[tmp32], 14 \n\t" "sra %[nrsh2], %[tmp321], 14 \n\t" : [nrsh1] "=&r"(nrsh1), [nrsh2] "=r"(nrsh2) : [tmp16] "r"(tmp16), [tmp161] "r"(tmp161), [tmp32] "r"(tmp32), [tmp321] "r"(tmp321) : "memory", "hi", "lo"); __asm __volatile( "lh %[tmp32], 0(%[randW16p]) \n\t" "lh %[tmp321], 2(%[randW16p]) \n\t" "addiu %[randW16p], %[randW16p], 4 \n\t" "mul %[tmp32], %[tmp32], %[c359] \n\t" "mul %[tmp321], %[tmp321], %[c359] \n\t" "sra %[tmp16], %[tmp32], 15 \n\t" "sra %[tmp161], %[tmp321], 15 \n\t" : [randW16p] "+r"(randW16p), [tmp32] "=&r"(tmp32), [tmp16] "=r"(tmp16), [tmp161] "=r"(tmp161), [tmp321] "=&r"(tmp321) : [c359] "r"(c359) : "memory", "hi", "lo"); #if !defined(MIPS_DSP_R1_LE) tmp32 = WebRtcAecm_kCosTable[tmp16]; tmp321 = WebRtcAecm_kSinTable[tmp16]; tmp322 = WebRtcAecm_kCosTable[tmp161]; tmp323 = WebRtcAecm_kSinTable[tmp161]; #else __asm __volatile( "sll %[tmp16], %[tmp16], 1 \n\t" "sll %[tmp161], %[tmp161], 1 \n\t" "lhx %[tmp32], %[tmp16](%[kCosTablep]) \n\t" "lhx %[tmp321], %[tmp16](%[kSinTablep]) \n\t" "lhx %[tmp322], %[tmp161](%[kCosTablep]) \n\t" "lhx %[tmp323], %[tmp161](%[kSinTablep]) \n\t" : [tmp32] "=&r"(tmp32), [tmp321] "=&r"(tmp321), [tmp322] "=&r"(tmp322), [tmp323] "=&r"(tmp323) : [kCosTablep] "r"(kCosTablep), [tmp16] "r"(tmp16), [tmp161] "r"(tmp161), [kSinTablep] "r"(kSinTablep) : "memory"); #endif __asm __volatile( "mul %[tmp32], %[tmp32], %[nrsh1] \n\t" "negu %[tmp162], %[nrsh1] \n\t" "mul %[tmp322], %[tmp322], %[nrsh2] \n\t" "negu %[tmp163], %[nrsh2] \n\t" "sra %[tmp32], %[tmp32], 13 \n\t" "mul %[tmp321], %[tmp321], %[tmp162] \n\t" "sra %[tmp322], %[tmp322], 13 \n\t" "mul %[tmp323], %[tmp323], %[tmp163] \n\t" "sra %[tmp321], %[tmp321], 13 \n\t" "sra %[tmp323], %[tmp323], 13 \n\t" : [tmp32] "+r"(tmp32), [tmp321] "+r"(tmp321), [tmp162] "=&r"(tmp162), [tmp322] "+r"(tmp322), [tmp323] "+r"(tmp323), [tmp163] "=&r"(tmp163) : [nrsh1] "r"(nrsh1), [nrsh2] "r"(nrsh2) : "hi", "lo"); // Tables are in Q13. uReal[i] = (int16_t)tmp32; uImag[i] = (int16_t)tmp321; uReal[i + 1] = (int16_t)tmp322; uImag[i + 1] = (int16_t)tmp323; } int32_t tt, sgn; tt = out[0].real; sgn = ((int)tt) >> 31; out[0].real = sgn == (int16_t)(tt >> 15) ? (int16_t)tt : (16384 ^ sgn); tt = out[0].imag; sgn = ((int)tt) >> 31; out[0].imag = sgn == (int16_t)(tt >> 15) ? (int16_t)tt : (16384 ^ sgn); for (i = 1; i < PART_LEN; i++) { tt = out[i].real + uReal[i]; sgn = ((int)tt) >> 31; out[i].real = sgn == (int16_t)(tt >> 15) ? (int16_t)tt : (16384 ^ sgn); tt = out[i].imag + uImag[i]; sgn = ((int)tt) >> 31; out[i].imag = sgn == (int16_t)(tt >> 15) ? (int16_t)tt : (16384 ^ sgn); } tt = out[PART_LEN].real + uReal[PART_LEN]; sgn = ((int)tt) >> 31; out[PART_LEN].real = sgn == (int16_t)(tt >> 15) ? (int16_t)tt : (16384 ^ sgn); tt = out[PART_LEN].imag; sgn = ((int)tt) >> 31; out[PART_LEN].imag = sgn == (int16_t)(tt >> 15) ? (int16_t)tt : (16384 ^ sgn); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aecm/aecm_core_neon.cc0000664000175000017500000001763414475643423027344 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include #include "common_audio/signal_processing/include/real_fft.h" #include "modules/audio_processing/aecm/aecm_core.h" #include "rtc_base/checks.h" namespace webrtc { namespace { // TODO(kma): Re-write the corresponding assembly file, the offset // generating script and makefile, to replace these C functions. static inline void AddLanes(uint32_t* ptr, uint32x4_t v) { #if defined(WEBRTC_ARCH_ARM64) *(ptr) = vaddvq_u32(v); #else uint32x2_t tmp_v; tmp_v = vadd_u32(vget_low_u32(v), vget_high_u32(v)); tmp_v = vpadd_u32(tmp_v, tmp_v); *(ptr) = vget_lane_u32(tmp_v, 0); #endif } } // namespace void WebRtcAecm_CalcLinearEnergiesNeon(AecmCore* aecm, const uint16_t* far_spectrum, int32_t* echo_est, uint32_t* far_energy, uint32_t* echo_energy_adapt, uint32_t* echo_energy_stored) { int16_t* start_stored_p = aecm->channelStored; int16_t* start_adapt_p = aecm->channelAdapt16; int32_t* echo_est_p = echo_est; const int16_t* end_stored_p = aecm->channelStored + PART_LEN; const uint16_t* far_spectrum_p = far_spectrum; int16x8_t store_v, adapt_v; uint16x8_t spectrum_v; uint32x4_t echo_est_v_low, echo_est_v_high; uint32x4_t far_energy_v, echo_stored_v, echo_adapt_v; far_energy_v = vdupq_n_u32(0); echo_adapt_v = vdupq_n_u32(0); echo_stored_v = vdupq_n_u32(0); // Get energy for the delayed far end signal and estimated // echo using both stored and adapted channels. // The C code: // for (i = 0; i < PART_LEN1; i++) { // echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], // far_spectrum[i]); // (*far_energy) += (uint32_t)(far_spectrum[i]); // *echo_energy_adapt += aecm->channelAdapt16[i] * far_spectrum[i]; // (*echo_energy_stored) += (uint32_t)echo_est[i]; // } while (start_stored_p < end_stored_p) { spectrum_v = vld1q_u16(far_spectrum_p); adapt_v = vld1q_s16(start_adapt_p); store_v = vld1q_s16(start_stored_p); far_energy_v = vaddw_u16(far_energy_v, vget_low_u16(spectrum_v)); far_energy_v = vaddw_u16(far_energy_v, vget_high_u16(spectrum_v)); echo_est_v_low = vmull_u16(vreinterpret_u16_s16(vget_low_s16(store_v)), vget_low_u16(spectrum_v)); echo_est_v_high = vmull_u16(vreinterpret_u16_s16(vget_high_s16(store_v)), vget_high_u16(spectrum_v)); vst1q_s32(echo_est_p, vreinterpretq_s32_u32(echo_est_v_low)); vst1q_s32(echo_est_p + 4, vreinterpretq_s32_u32(echo_est_v_high)); echo_stored_v = vaddq_u32(echo_est_v_low, echo_stored_v); echo_stored_v = vaddq_u32(echo_est_v_high, echo_stored_v); echo_adapt_v = vmlal_u16(echo_adapt_v, vreinterpret_u16_s16(vget_low_s16(adapt_v)), vget_low_u16(spectrum_v)); echo_adapt_v = vmlal_u16(echo_adapt_v, vreinterpret_u16_s16(vget_high_s16(adapt_v)), vget_high_u16(spectrum_v)); start_stored_p += 8; start_adapt_p += 8; far_spectrum_p += 8; echo_est_p += 8; } AddLanes(far_energy, far_energy_v); AddLanes(echo_energy_stored, echo_stored_v); AddLanes(echo_energy_adapt, echo_adapt_v); echo_est[PART_LEN] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[PART_LEN], far_spectrum[PART_LEN]); *echo_energy_stored += (uint32_t)echo_est[PART_LEN]; *far_energy += (uint32_t)far_spectrum[PART_LEN]; *echo_energy_adapt += aecm->channelAdapt16[PART_LEN] * far_spectrum[PART_LEN]; } void WebRtcAecm_StoreAdaptiveChannelNeon(AecmCore* aecm, const uint16_t* far_spectrum, int32_t* echo_est) { RTC_DCHECK_EQ(0, (uintptr_t)echo_est % 32); RTC_DCHECK_EQ(0, (uintptr_t)aecm->channelStored % 16); RTC_DCHECK_EQ(0, (uintptr_t)aecm->channelAdapt16 % 16); // This is C code of following optimized code. // During startup we store the channel every block. // memcpy(aecm->channelStored, // aecm->channelAdapt16, // sizeof(int16_t) * PART_LEN1); // Recalculate echo estimate // for (i = 0; i < PART_LEN; i += 4) { // echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], // far_spectrum[i]); // echo_est[i + 1] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1], // far_spectrum[i + 1]); // echo_est[i + 2] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2], // far_spectrum[i + 2]); // echo_est[i + 3] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3], // far_spectrum[i + 3]); // } // echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], // far_spectrum[i]); const uint16_t* far_spectrum_p = far_spectrum; int16_t* start_adapt_p = aecm->channelAdapt16; int16_t* start_stored_p = aecm->channelStored; const int16_t* end_stored_p = aecm->channelStored + PART_LEN; int32_t* echo_est_p = echo_est; uint16x8_t far_spectrum_v; int16x8_t adapt_v; uint32x4_t echo_est_v_low, echo_est_v_high; while (start_stored_p < end_stored_p) { far_spectrum_v = vld1q_u16(far_spectrum_p); adapt_v = vld1q_s16(start_adapt_p); vst1q_s16(start_stored_p, adapt_v); echo_est_v_low = vmull_u16(vget_low_u16(far_spectrum_v), vget_low_u16(vreinterpretq_u16_s16(adapt_v))); echo_est_v_high = vmull_u16(vget_high_u16(far_spectrum_v), vget_high_u16(vreinterpretq_u16_s16(adapt_v))); vst1q_s32(echo_est_p, vreinterpretq_s32_u32(echo_est_v_low)); vst1q_s32(echo_est_p + 4, vreinterpretq_s32_u32(echo_est_v_high)); far_spectrum_p += 8; start_adapt_p += 8; start_stored_p += 8; echo_est_p += 8; } aecm->channelStored[PART_LEN] = aecm->channelAdapt16[PART_LEN]; echo_est[PART_LEN] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[PART_LEN], far_spectrum[PART_LEN]); } void WebRtcAecm_ResetAdaptiveChannelNeon(AecmCore* aecm) { RTC_DCHECK_EQ(0, (uintptr_t)aecm->channelStored % 16); RTC_DCHECK_EQ(0, (uintptr_t)aecm->channelAdapt16 % 16); RTC_DCHECK_EQ(0, (uintptr_t)aecm->channelAdapt32 % 32); // The C code of following optimized code. // for (i = 0; i < PART_LEN1; i++) { // aecm->channelAdapt16[i] = aecm->channelStored[i]; // aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32( // (int32_t)aecm->channelStored[i], 16); // } int16_t* start_stored_p = aecm->channelStored; int16_t* start_adapt16_p = aecm->channelAdapt16; int32_t* start_adapt32_p = aecm->channelAdapt32; const int16_t* end_stored_p = start_stored_p + PART_LEN; int16x8_t stored_v; int32x4_t adapt32_v_low, adapt32_v_high; while (start_stored_p < end_stored_p) { stored_v = vld1q_s16(start_stored_p); vst1q_s16(start_adapt16_p, stored_v); adapt32_v_low = vshll_n_s16(vget_low_s16(stored_v), 16); adapt32_v_high = vshll_n_s16(vget_high_s16(stored_v), 16); vst1q_s32(start_adapt32_p, adapt32_v_low); vst1q_s32(start_adapt32_p + 4, adapt32_v_high); start_stored_p += 8; start_adapt16_p += 8; start_adapt32_p += 8; } aecm->channelAdapt16[PART_LEN] = aecm->channelStored[PART_LEN]; aecm->channelAdapt32[PART_LEN] = (int32_t)aecm->channelStored[PART_LEN] << 16; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aecm/aecm_defines.h0000664000175000017500000000755614475643423026656 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AECM_AECM_DEFINES_H_ #define MODULES_AUDIO_PROCESSING_AECM_AECM_DEFINES_H_ #define AECM_DYNAMIC_Q /* Turn on/off dynamic Q-domain. */ /* Algorithm parameters */ #define FRAME_LEN 80 /* Total frame length, 10 ms. */ #define PART_LEN 64 /* Length of partition. */ #define PART_LEN_SHIFT 7 /* Length of (PART_LEN * 2) in base 2. */ #define PART_LEN1 (PART_LEN + 1) /* Unique fft coefficients. */ #define PART_LEN2 (PART_LEN << 1) /* Length of partition * 2. */ #define PART_LEN4 (PART_LEN << 2) /* Length of partition * 4. */ #define FAR_BUF_LEN PART_LEN4 /* Length of buffers. */ #define MAX_DELAY 100 /* Counter parameters */ #define CONV_LEN 512 /* Convergence length used at startup. */ #define CONV_LEN2 (CONV_LEN << 1) /* Used at startup. */ /* Energy parameters */ #define MAX_BUF_LEN 64 /* History length of energy signals. */ #define FAR_ENERGY_MIN 1025 /* Lowest Far energy level: At least 2 */ /* in energy. */ #define FAR_ENERGY_DIFF 929 /* Allowed difference between max */ /* and min. */ #define ENERGY_DEV_OFFSET 0 /* The energy error offset in Q8. */ #define ENERGY_DEV_TOL 400 /* The energy estimation tolerance (Q8). */ #define FAR_ENERGY_VAD_REGION 230 /* Far VAD tolerance region. */ /* Stepsize parameters */ #define MU_MIN 10 /* Min stepsize 2^-MU_MIN (far end energy */ /* dependent). */ #define MU_MAX 1 /* Max stepsize 2^-MU_MAX (far end energy */ /* dependent). */ #define MU_DIFF 9 /* MU_MIN - MU_MAX */ /* Channel parameters */ #define MIN_MSE_COUNT 20 /* Min number of consecutive blocks with enough */ /* far end energy to compare channel estimates. */ #define MIN_MSE_DIFF 29 /* The ratio between adapted and stored channel to */ /* accept a new storage (0.8 in Q-MSE_RESOLUTION). */ #define MSE_RESOLUTION 5 /* MSE parameter resolution. */ #define RESOLUTION_CHANNEL16 12 /* W16 Channel in Q-RESOLUTION_CHANNEL16. */ #define RESOLUTION_CHANNEL32 28 /* W32 Channel in Q-RESOLUTION_CHANNEL. */ #define CHANNEL_VAD 16 /* Minimum energy in frequency band */ /* to update channel. */ /* Suppression gain parameters: SUPGAIN parameters in Q-(RESOLUTION_SUPGAIN). */ #define RESOLUTION_SUPGAIN 8 /* Channel in Q-(RESOLUTION_SUPGAIN). */ #define SUPGAIN_DEFAULT (1 << RESOLUTION_SUPGAIN) /* Default. */ #define SUPGAIN_ERROR_PARAM_A 3072 /* Estimation error parameter */ /* (Maximum gain) (8 in Q8). */ #define SUPGAIN_ERROR_PARAM_B 1536 /* Estimation error parameter */ /* (Gain before going down). */ #define SUPGAIN_ERROR_PARAM_D SUPGAIN_DEFAULT /* Estimation error parameter */ /* (Should be the same as Default) (1 in Q8). */ #define SUPGAIN_EPC_DT 200 /* SUPGAIN_ERROR_PARAM_C * ENERGY_DEV_TOL */ /* Defines for "check delay estimation" */ #define CORR_WIDTH 31 /* Number of samples to correlate over. */ #define CORR_MAX 16 /* Maximum correlation offset. */ #define CORR_MAX_BUF 63 #define CORR_DEV 4 #define CORR_MAX_LEVEL 20 #define CORR_MAX_LOW 4 #define CORR_BUF_LEN (CORR_MAX << 1) + 1 /* Note that CORR_WIDTH + 2*CORR_MAX <= MAX_BUF_LEN. */ #define ONE_Q14 (1 << 14) /* NLP defines */ #define NLP_COMP_LOW 3277 /* 0.2 in Q14 */ #define NLP_COMP_HIGH ONE_Q14 /* 1 in Q14 */ #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aecm/echo_control_mobile.cc0000664000175000017500000004362014475643423030407 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aecm/echo_control_mobile.h" #ifdef AEC_DEBUG #include #endif #include #include extern "C" { #include "common_audio/ring_buffer.h" #include "common_audio/signal_processing/include/signal_processing_library.h" #include "modules/audio_processing/aecm/aecm_defines.h" } #include "modules/audio_processing/aecm/aecm_core.h" namespace webrtc { namespace { #define BUF_SIZE_FRAMES 50 // buffer size (frames) // Maximum length of resampled signal. Must be an integer multiple of frames // (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN // The factor of 2 handles wb, and the + 1 is as a safety margin #define MAX_RESAMP_LEN (5 * FRAME_LEN) static const size_t kBufSizeSamp = BUF_SIZE_FRAMES * FRAME_LEN; // buffer size (samples) static const int kSampMsNb = 8; // samples per ms in nb // Target suppression levels for nlp modes // log{0.001, 0.00001, 0.00000001} static const int kInitCheck = 42; typedef struct { int sampFreq; int scSampFreq; short bufSizeStart; int knownDelay; // Stores the last frame added to the farend buffer short farendOld[2][FRAME_LEN]; short initFlag; // indicates if AEC has been initialized // Variables used for averaging far end buffer size short counter; short sum; short firstVal; short checkBufSizeCtr; // Variables used for delay shifts short msInSndCardBuf; short filtDelay; int timeForDelayChange; int ECstartup; int checkBuffSize; int delayChange; short lastDelayDiff; int16_t echoMode; #ifdef AEC_DEBUG FILE* bufFile; FILE* delayFile; FILE* preCompFile; FILE* postCompFile; #endif // AEC_DEBUG // Structures RingBuffer* farendBuf; AecmCore* aecmCore; } AecMobile; } // namespace // Estimates delay to set the position of the farend buffer read pointer // (controlled by knownDelay) static int WebRtcAecm_EstBufDelay(AecMobile* aecm, short msInSndCardBuf); // Stuffs the farend buffer if the estimated delay is too large static int WebRtcAecm_DelayComp(AecMobile* aecm); void* WebRtcAecm_Create() { // Allocate zero-filled memory. AecMobile* aecm = static_cast(calloc(1, sizeof(AecMobile))); aecm->aecmCore = WebRtcAecm_CreateCore(); if (!aecm->aecmCore) { WebRtcAecm_Free(aecm); return NULL; } aecm->farendBuf = WebRtc_CreateBuffer(kBufSizeSamp, sizeof(int16_t)); if (!aecm->farendBuf) { WebRtcAecm_Free(aecm); return NULL; } #ifdef AEC_DEBUG aecm->aecmCore->farFile = fopen("aecFar.pcm", "wb"); aecm->aecmCore->nearFile = fopen("aecNear.pcm", "wb"); aecm->aecmCore->outFile = fopen("aecOut.pcm", "wb"); // aecm->aecmCore->outLpFile = fopen("aecOutLp.pcm","wb"); aecm->bufFile = fopen("aecBuf.dat", "wb"); aecm->delayFile = fopen("aecDelay.dat", "wb"); aecm->preCompFile = fopen("preComp.pcm", "wb"); aecm->postCompFile = fopen("postComp.pcm", "wb"); #endif // AEC_DEBUG return aecm; } void WebRtcAecm_Free(void* aecmInst) { AecMobile* aecm = static_cast(aecmInst); if (aecm == NULL) { return; } #ifdef AEC_DEBUG fclose(aecm->aecmCore->farFile); fclose(aecm->aecmCore->nearFile); fclose(aecm->aecmCore->outFile); // fclose(aecm->aecmCore->outLpFile); fclose(aecm->bufFile); fclose(aecm->delayFile); fclose(aecm->preCompFile); fclose(aecm->postCompFile); #endif // AEC_DEBUG WebRtcAecm_FreeCore(aecm->aecmCore); WebRtc_FreeBuffer(aecm->farendBuf); free(aecm); } int32_t WebRtcAecm_Init(void* aecmInst, int32_t sampFreq) { AecMobile* aecm = static_cast(aecmInst); AecmConfig aecConfig; if (aecm == NULL) { return -1; } if (sampFreq != 8000 && sampFreq != 16000) { return AECM_BAD_PARAMETER_ERROR; } aecm->sampFreq = sampFreq; // Initialize AECM core if (WebRtcAecm_InitCore(aecm->aecmCore, aecm->sampFreq) == -1) { return AECM_UNSPECIFIED_ERROR; } // Initialize farend buffer WebRtc_InitBuffer(aecm->farendBuf); aecm->initFlag = kInitCheck; // indicates that initialization has been done aecm->delayChange = 1; aecm->sum = 0; aecm->counter = 0; aecm->checkBuffSize = 1; aecm->firstVal = 0; aecm->ECstartup = 1; aecm->bufSizeStart = 0; aecm->checkBufSizeCtr = 0; aecm->filtDelay = 0; aecm->timeForDelayChange = 0; aecm->knownDelay = 0; aecm->lastDelayDiff = 0; memset(&aecm->farendOld, 0, sizeof(aecm->farendOld)); // Default settings. aecConfig.cngMode = AecmTrue; aecConfig.echoMode = 3; if (WebRtcAecm_set_config(aecm, aecConfig) == -1) { return AECM_UNSPECIFIED_ERROR; } return 0; } // Returns any error that is caused when buffering the // farend signal. int32_t WebRtcAecm_GetBufferFarendError(void* aecmInst, const int16_t* farend, size_t nrOfSamples) { AecMobile* aecm = static_cast(aecmInst); if (aecm == NULL) return -1; if (farend == NULL) return AECM_NULL_POINTER_ERROR; if (aecm->initFlag != kInitCheck) return AECM_UNINITIALIZED_ERROR; if (nrOfSamples != 80 && nrOfSamples != 160) return AECM_BAD_PARAMETER_ERROR; return 0; } int32_t WebRtcAecm_BufferFarend(void* aecmInst, const int16_t* farend, size_t nrOfSamples) { AecMobile* aecm = static_cast(aecmInst); const int32_t err = WebRtcAecm_GetBufferFarendError(aecmInst, farend, nrOfSamples); if (err != 0) return err; // TODO(unknown): Is this really a good idea? if (!aecm->ECstartup) { WebRtcAecm_DelayComp(aecm); } WebRtc_WriteBuffer(aecm->farendBuf, farend, nrOfSamples); return 0; } int32_t WebRtcAecm_Process(void* aecmInst, const int16_t* nearendNoisy, const int16_t* nearendClean, int16_t* out, size_t nrOfSamples, int16_t msInSndCardBuf) { AecMobile* aecm = static_cast(aecmInst); int32_t retVal = 0; size_t i; short nmbrOfFilledBuffers; size_t nBlocks10ms; size_t nFrames; #ifdef AEC_DEBUG short msInAECBuf; #endif if (aecm == NULL) { return -1; } if (nearendNoisy == NULL) { return AECM_NULL_POINTER_ERROR; } if (out == NULL) { return AECM_NULL_POINTER_ERROR; } if (aecm->initFlag != kInitCheck) { return AECM_UNINITIALIZED_ERROR; } if (nrOfSamples != 80 && nrOfSamples != 160) { return AECM_BAD_PARAMETER_ERROR; } if (msInSndCardBuf < 0) { msInSndCardBuf = 0; retVal = AECM_BAD_PARAMETER_WARNING; } else if (msInSndCardBuf > 500) { msInSndCardBuf = 500; retVal = AECM_BAD_PARAMETER_WARNING; } msInSndCardBuf += 10; aecm->msInSndCardBuf = msInSndCardBuf; nFrames = nrOfSamples / FRAME_LEN; nBlocks10ms = nFrames / aecm->aecmCore->mult; if (aecm->ECstartup) { if (nearendClean == NULL) { if (out != nearendNoisy) { memcpy(out, nearendNoisy, sizeof(short) * nrOfSamples); } } else if (out != nearendClean) { memcpy(out, nearendClean, sizeof(short) * nrOfSamples); } nmbrOfFilledBuffers = (short)WebRtc_available_read(aecm->farendBuf) / FRAME_LEN; // The AECM is in the start up mode // AECM is disabled until the soundcard buffer and farend buffers are OK // Mechanism to ensure that the soundcard buffer is reasonably stable. if (aecm->checkBuffSize) { aecm->checkBufSizeCtr++; // Before we fill up the far end buffer we require the amount of data on // the sound card to be stable (+/-8 ms) compared to the first value. This // comparison is made during the following 4 consecutive frames. If it // seems to be stable then we start to fill up the far end buffer. if (aecm->counter == 0) { aecm->firstVal = aecm->msInSndCardBuf; aecm->sum = 0; } if (abs(aecm->firstVal - aecm->msInSndCardBuf) < WEBRTC_SPL_MAX(0.2 * aecm->msInSndCardBuf, kSampMsNb)) { aecm->sum += aecm->msInSndCardBuf; aecm->counter++; } else { aecm->counter = 0; } if (aecm->counter * nBlocks10ms >= 6) { // The farend buffer size is determined in blocks of 80 samples // Use 75% of the average value of the soundcard buffer aecm->bufSizeStart = WEBRTC_SPL_MIN( (3 * aecm->sum * aecm->aecmCore->mult) / (aecm->counter * 40), BUF_SIZE_FRAMES); // buffersize has now been determined aecm->checkBuffSize = 0; } if (aecm->checkBufSizeCtr * nBlocks10ms > 50) { // for really bad sound cards, don't disable echocanceller for more than // 0.5 sec aecm->bufSizeStart = WEBRTC_SPL_MIN( (3 * aecm->msInSndCardBuf * aecm->aecmCore->mult) / 40, BUF_SIZE_FRAMES); aecm->checkBuffSize = 0; } } // if checkBuffSize changed in the if-statement above if (!aecm->checkBuffSize) { // soundcard buffer is now reasonably stable // When the far end buffer is filled with approximately the same amount of // data as the amount on the sound card we end the start up phase and // start to cancel echoes. if (nmbrOfFilledBuffers == aecm->bufSizeStart) { aecm->ECstartup = 0; // Enable the AECM } else if (nmbrOfFilledBuffers > aecm->bufSizeStart) { WebRtc_MoveReadPtr(aecm->farendBuf, (int)WebRtc_available_read(aecm->farendBuf) - (int)aecm->bufSizeStart * FRAME_LEN); aecm->ECstartup = 0; } } } else { // AECM is enabled // Note only 1 block supported for nb and 2 blocks for wb for (i = 0; i < nFrames; i++) { int16_t farend[FRAME_LEN]; const int16_t* farend_ptr = NULL; nmbrOfFilledBuffers = (short)WebRtc_available_read(aecm->farendBuf) / FRAME_LEN; // Check that there is data in the far end buffer if (nmbrOfFilledBuffers > 0) { // Get the next 80 samples from the farend buffer WebRtc_ReadBuffer(aecm->farendBuf, (void**)&farend_ptr, farend, FRAME_LEN); // Always store the last frame for use when we run out of data memcpy(&(aecm->farendOld[i][0]), farend_ptr, FRAME_LEN * sizeof(short)); } else { // We have no data so we use the last played frame memcpy(farend, &(aecm->farendOld[i][0]), FRAME_LEN * sizeof(short)); farend_ptr = farend; } // Call buffer delay estimator when all data is extracted, // i,e. i = 0 for NB and i = 1 for WB if ((i == 0 && aecm->sampFreq == 8000) || (i == 1 && aecm->sampFreq == 16000)) { WebRtcAecm_EstBufDelay(aecm, aecm->msInSndCardBuf); } // Call the AECM /*WebRtcAecm_ProcessFrame(aecm->aecmCore, farend, &nearend[FRAME_LEN * i], &out[FRAME_LEN * i], aecm->knownDelay);*/ if (WebRtcAecm_ProcessFrame( aecm->aecmCore, farend_ptr, &nearendNoisy[FRAME_LEN * i], (nearendClean ? &nearendClean[FRAME_LEN * i] : NULL), &out[FRAME_LEN * i]) == -1) return -1; } } #ifdef AEC_DEBUG msInAECBuf = (short)WebRtc_available_read(aecm->farendBuf) / (kSampMsNb * aecm->aecmCore->mult); fwrite(&msInAECBuf, 2, 1, aecm->bufFile); fwrite(&(aecm->knownDelay), sizeof(aecm->knownDelay), 1, aecm->delayFile); #endif return retVal; } int32_t WebRtcAecm_set_config(void* aecmInst, AecmConfig config) { AecMobile* aecm = static_cast(aecmInst); if (aecm == NULL) { return -1; } if (aecm->initFlag != kInitCheck) { return AECM_UNINITIALIZED_ERROR; } if (config.cngMode != AecmFalse && config.cngMode != AecmTrue) { return AECM_BAD_PARAMETER_ERROR; } aecm->aecmCore->cngMode = config.cngMode; if (config.echoMode < 0 || config.echoMode > 4) { return AECM_BAD_PARAMETER_ERROR; } aecm->echoMode = config.echoMode; if (aecm->echoMode == 0) { aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 3; aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 3; aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 3; aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 3; aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 3) - (SUPGAIN_ERROR_PARAM_B >> 3); aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 3) - (SUPGAIN_ERROR_PARAM_D >> 3); } else if (aecm->echoMode == 1) { aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 2; aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 2; aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 2; aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 2; aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 2) - (SUPGAIN_ERROR_PARAM_B >> 2); aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 2) - (SUPGAIN_ERROR_PARAM_D >> 2); } else if (aecm->echoMode == 2) { aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 1; aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 1; aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 1; aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 1; aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 1) - (SUPGAIN_ERROR_PARAM_B >> 1); aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 1) - (SUPGAIN_ERROR_PARAM_D >> 1); } else if (aecm->echoMode == 3) { aecm->aecmCore->supGain = SUPGAIN_DEFAULT; aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT; aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A; aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D; aecm->aecmCore->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B; aecm->aecmCore->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D; } else if (aecm->echoMode == 4) { aecm->aecmCore->supGain = SUPGAIN_DEFAULT << 1; aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT << 1; aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A << 1; aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D << 1; aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A << 1) - (SUPGAIN_ERROR_PARAM_B << 1); aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B << 1) - (SUPGAIN_ERROR_PARAM_D << 1); } return 0; } int32_t WebRtcAecm_InitEchoPath(void* aecmInst, const void* echo_path, size_t size_bytes) { AecMobile* aecm = static_cast(aecmInst); const int16_t* echo_path_ptr = static_cast(echo_path); if (aecmInst == NULL) { return -1; } if (echo_path == NULL) { return AECM_NULL_POINTER_ERROR; } if (size_bytes != WebRtcAecm_echo_path_size_bytes()) { // Input channel size does not match the size of AECM return AECM_BAD_PARAMETER_ERROR; } if (aecm->initFlag != kInitCheck) { return AECM_UNINITIALIZED_ERROR; } WebRtcAecm_InitEchoPathCore(aecm->aecmCore, echo_path_ptr); return 0; } int32_t WebRtcAecm_GetEchoPath(void* aecmInst, void* echo_path, size_t size_bytes) { AecMobile* aecm = static_cast(aecmInst); int16_t* echo_path_ptr = static_cast(echo_path); if (aecmInst == NULL) { return -1; } if (echo_path == NULL) { return AECM_NULL_POINTER_ERROR; } if (size_bytes != WebRtcAecm_echo_path_size_bytes()) { // Input channel size does not match the size of AECM return AECM_BAD_PARAMETER_ERROR; } if (aecm->initFlag != kInitCheck) { return AECM_UNINITIALIZED_ERROR; } memcpy(echo_path_ptr, aecm->aecmCore->channelStored, size_bytes); return 0; } size_t WebRtcAecm_echo_path_size_bytes() { return (PART_LEN1 * sizeof(int16_t)); } static int WebRtcAecm_EstBufDelay(AecMobile* aecm, short msInSndCardBuf) { short delayNew, nSampSndCard; short nSampFar = (short)WebRtc_available_read(aecm->farendBuf); short diff; nSampSndCard = msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult; delayNew = nSampSndCard - nSampFar; if (delayNew < FRAME_LEN) { WebRtc_MoveReadPtr(aecm->farendBuf, FRAME_LEN); delayNew += FRAME_LEN; } aecm->filtDelay = WEBRTC_SPL_MAX(0, (8 * aecm->filtDelay + 2 * delayNew) / 10); diff = aecm->filtDelay - aecm->knownDelay; if (diff > 224) { if (aecm->lastDelayDiff < 96) { aecm->timeForDelayChange = 0; } else { aecm->timeForDelayChange++; } } else if (diff < 96 && aecm->knownDelay > 0) { if (aecm->lastDelayDiff > 224) { aecm->timeForDelayChange = 0; } else { aecm->timeForDelayChange++; } } else { aecm->timeForDelayChange = 0; } aecm->lastDelayDiff = diff; if (aecm->timeForDelayChange > 25) { aecm->knownDelay = WEBRTC_SPL_MAX((int)aecm->filtDelay - 160, 0); } return 0; } static int WebRtcAecm_DelayComp(AecMobile* aecm) { int nSampFar = (int)WebRtc_available_read(aecm->farendBuf); int nSampSndCard, delayNew, nSampAdd; const int maxStuffSamp = 10 * FRAME_LEN; nSampSndCard = aecm->msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult; delayNew = nSampSndCard - nSampFar; if (delayNew > FAR_BUF_LEN - FRAME_LEN * aecm->aecmCore->mult) { // The difference of the buffer sizes is larger than the maximum // allowed known delay. Compensate by stuffing the buffer. nSampAdd = (int)(WEBRTC_SPL_MAX(((nSampSndCard >> 1) - nSampFar), FRAME_LEN)); nSampAdd = WEBRTC_SPL_MIN(nSampAdd, maxStuffSamp); WebRtc_MoveReadPtr(aecm->farendBuf, -nSampAdd); aecm->delayChange = 1; // the delay needs to be updated } return 0; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/aecm/echo_control_mobile.h0000664000175000017500000001744314475643423030255 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AECM_ECHO_CONTROL_MOBILE_H_ #define MODULES_AUDIO_PROCESSING_AECM_ECHO_CONTROL_MOBILE_H_ #include #include namespace webrtc { enum { AecmFalse = 0, AecmTrue }; // Errors #define AECM_UNSPECIFIED_ERROR 12000 #define AECM_UNSUPPORTED_FUNCTION_ERROR 12001 #define AECM_UNINITIALIZED_ERROR 12002 #define AECM_NULL_POINTER_ERROR 12003 #define AECM_BAD_PARAMETER_ERROR 12004 // Warnings #define AECM_BAD_PARAMETER_WARNING 12100 typedef struct { int16_t cngMode; // AECM_FALSE, AECM_TRUE (default) int16_t echoMode; // 0, 1, 2, 3 (default), 4 } AecmConfig; #ifdef __cplusplus extern "C" { #endif /* * Allocates the memory needed by the AECM. The memory needs to be * initialized separately using the WebRtcAecm_Init() function. * Returns a pointer to the instance and a nullptr at failure. */ void* WebRtcAecm_Create(); /* * This function releases the memory allocated by WebRtcAecm_Create() * * Inputs Description * ------------------------------------------------------------------- * void* aecmInst Pointer to the AECM instance */ void WebRtcAecm_Free(void* aecmInst); /* * Initializes an AECM instance. * * Inputs Description * ------------------------------------------------------------------- * void* aecmInst Pointer to the AECM instance * int32_t sampFreq Sampling frequency of data * * Outputs Description * ------------------------------------------------------------------- * int32_t return 0: OK * 1200-12004,12100: error/warning */ int32_t WebRtcAecm_Init(void* aecmInst, int32_t sampFreq); /* * Inserts an 80 or 160 sample block of data into the farend buffer. * * Inputs Description * ------------------------------------------------------------------- * void* aecmInst Pointer to the AECM instance * int16_t* farend In buffer containing one frame of * farend signal * int16_t nrOfSamples Number of samples in farend buffer * * Outputs Description * ------------------------------------------------------------------- * int32_t return 0: OK * 1200-12004,12100: error/warning */ int32_t WebRtcAecm_BufferFarend(void* aecmInst, const int16_t* farend, size_t nrOfSamples); /* * Reports any errors that would arise when buffering a farend buffer. * * Inputs Description * ------------------------------------------------------------------- * void* aecmInst Pointer to the AECM instance * int16_t* farend In buffer containing one frame of * farend signal * int16_t nrOfSamples Number of samples in farend buffer * * Outputs Description * ------------------------------------------------------------------- * int32_t return 0: OK * 1200-12004,12100: error/warning */ int32_t WebRtcAecm_GetBufferFarendError(void* aecmInst, const int16_t* farend, size_t nrOfSamples); /* * Runs the AECM on an 80 or 160 sample blocks of data. * * Inputs Description * ------------------------------------------------------------------- * void* aecmInst Pointer to the AECM instance * int16_t* nearendNoisy In buffer containing one frame of * reference nearend+echo signal. If * noise reduction is active, provide * the noisy signal here. * int16_t* nearendClean In buffer containing one frame of * nearend+echo signal. If noise * reduction is active, provide the * clean signal here. Otherwise pass a * NULL pointer. * int16_t nrOfSamples Number of samples in nearend buffer * int16_t msInSndCardBuf Delay estimate for sound card and * system buffers * * Outputs Description * ------------------------------------------------------------------- * int16_t* out Out buffer, one frame of processed nearend * int32_t return 0: OK * 1200-12004,12100: error/warning */ int32_t WebRtcAecm_Process(void* aecmInst, const int16_t* nearendNoisy, const int16_t* nearendClean, int16_t* out, size_t nrOfSamples, int16_t msInSndCardBuf); /* * This function enables the user to set certain parameters on-the-fly * * Inputs Description * ------------------------------------------------------------------- * void* aecmInst Pointer to the AECM instance * AecmConfig config Config instance that contains all * properties to be set * * Outputs Description * ------------------------------------------------------------------- * int32_t return 0: OK * 1200-12004,12100: error/warning */ int32_t WebRtcAecm_set_config(void* aecmInst, AecmConfig config); /* * This function enables the user to set the echo path on-the-fly. * * Inputs Description * ------------------------------------------------------------------- * void* aecmInst Pointer to the AECM instance * void* echo_path Pointer to the echo path to be set * size_t size_bytes Size in bytes of the echo path * * Outputs Description * ------------------------------------------------------------------- * int32_t return 0: OK * 1200-12004,12100: error/warning */ int32_t WebRtcAecm_InitEchoPath(void* aecmInst, const void* echo_path, size_t size_bytes); /* * This function enables the user to get the currently used echo path * on-the-fly * * Inputs Description * ------------------------------------------------------------------- * void* aecmInst Pointer to the AECM instance * void* echo_path Pointer to echo path * size_t size_bytes Size in bytes of the echo path * * Outputs Description * ------------------------------------------------------------------- * int32_t return 0: OK * 1200-12004,12100: error/warning */ int32_t WebRtcAecm_GetEchoPath(void* aecmInst, void* echo_path, size_t size_bytes); /* * This function enables the user to get the echo path size in bytes * * Outputs Description * ------------------------------------------------------------------- * size_t return Size in bytes */ size_t WebRtcAecm_echo_path_size_bytes(); #ifdef __cplusplus } #endif } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AECM_ECHO_CONTROL_MOBILE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc/0000775000175000017500000000000014475643423023713 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc/BUILD.gn0000664000175000017500000000542014475643423025101 0ustar00arunarun# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../../../webrtc.gni") rtc_source_set("gain_control_interface") { sources = [ "gain_control.h" ] } rtc_library("agc") { sources = [ "agc_manager_direct.cc", "agc_manager_direct.h", ] configs += [ "..:apm_debug_dump" ] deps = [ ":gain_control_interface", ":gain_map", ":level_estimation", "..:apm_logging", "..:audio_buffer", "../../../common_audio", "../../../common_audio:common_audio_c", "../../../rtc_base:checks", "../../../rtc_base:gtest_prod", "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", "../../../rtc_base:safe_minmax", "../../../system_wrappers:field_trial", "../../../system_wrappers:metrics", "../agc2:level_estimation_agc", "../vad", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("level_estimation") { sources = [ "agc.cc", "agc.h", "loudness_histogram.cc", "loudness_histogram.h", "utility.cc", "utility.h", ] deps = [ "../../../rtc_base:checks", "../vad", ] } rtc_library("legacy_agc") { visibility = [ ":*", "..:*", ] # Only targets in this file and in # audio_processing can depend on # this. sources = [ "legacy/analog_agc.cc", "legacy/analog_agc.h", "legacy/digital_agc.cc", "legacy/digital_agc.h", "legacy/gain_control.h", ] deps = [ "../../../common_audio", "../../../common_audio:common_audio_c", "../../../common_audio/third_party/ooura:fft_size_256", "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", "../../../system_wrappers", ] if (rtc_build_with_neon) { if (current_cpu != "arm64") { # Enable compilation for the NEON instruction set. suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ] cflags = [ "-mfpu=neon" ] } } } rtc_source_set("gain_map") { sources = [ "gain_map_internal.h" ] } if (rtc_include_tests) { rtc_library("agc_unittests") { testonly = true sources = [ "agc_manager_direct_unittest.cc", "loudness_histogram_unittest.cc", "mock_agc.h", ] configs += [ "..:apm_debug_dump" ] deps = [ ":agc", ":gain_control_interface", ":level_estimation", "..:mocks", "../../../test:field_trial", "../../../test:fileutils", "../../../test:test_support", "//testing/gtest", ] } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc/agc.cc0000664000175000017500000000521214475643423024754 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc/agc.h" #include #include #include #include "modules/audio_processing/agc/loudness_histogram.h" #include "modules/audio_processing/agc/utility.h" #include "rtc_base/checks.h" namespace webrtc { namespace { const int kDefaultLevelDbfs = -18; const int kNumAnalysisFrames = 100; const double kActivityThreshold = 0.3; } // namespace Agc::Agc() : target_level_loudness_(Dbfs2Loudness(kDefaultLevelDbfs)), target_level_dbfs_(kDefaultLevelDbfs), histogram_(LoudnessHistogram::Create(kNumAnalysisFrames)), inactive_histogram_(LoudnessHistogram::Create()) {} Agc::~Agc() = default; void Agc::Process(const int16_t* audio, size_t length, int sample_rate_hz) { vad_.ProcessChunk(audio, length, sample_rate_hz); const std::vector& rms = vad_.chunkwise_rms(); const std::vector& probabilities = vad_.chunkwise_voice_probabilities(); RTC_DCHECK_EQ(rms.size(), probabilities.size()); for (size_t i = 0; i < rms.size(); ++i) { histogram_->Update(rms[i], probabilities[i]); } } bool Agc::GetRmsErrorDb(int* error) { if (!error) { RTC_NOTREACHED(); return false; } if (histogram_->num_updates() < kNumAnalysisFrames) { // We haven't yet received enough frames. return false; } if (histogram_->AudioContent() < kNumAnalysisFrames * kActivityThreshold) { // We are likely in an inactive segment. return false; } double loudness = Linear2Loudness(histogram_->CurrentRms()); *error = std::floor(Loudness2Db(target_level_loudness_ - loudness) + 0.5); histogram_->Reset(); return true; } void Agc::Reset() { histogram_->Reset(); } int Agc::set_target_level_dbfs(int level) { // TODO(turajs): just some arbitrary sanity check. We can come up with better // limits. The upper limit should be chosen such that the risk of clipping is // low. The lower limit should not result in a too quiet signal. if (level >= 0 || level <= -100) return -1; target_level_dbfs_ = level; target_level_loudness_ = Dbfs2Loudness(level); return 0; } int Agc::target_level_dbfs() const { return target_level_dbfs_; } float Agc::voice_probability() const { return vad_.last_voice_probability(); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc/agc.h0000664000175000017500000000305214475643423024616 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC_AGC_H_ #define MODULES_AUDIO_PROCESSING_AGC_AGC_H_ #include #include "modules/audio_processing/vad/voice_activity_detector.h" namespace webrtc { class LoudnessHistogram; class Agc { public: Agc(); virtual ~Agc(); // |audio| must be mono; in a multi-channel stream, provide the first (usually // left) channel. virtual void Process(const int16_t* audio, size_t length, int sample_rate_hz); // Retrieves the difference between the target RMS level and the current // signal RMS level in dB. Returns true if an update is available and false // otherwise, in which case |error| should be ignored and no action taken. virtual bool GetRmsErrorDb(int* error); virtual void Reset(); virtual int set_target_level_dbfs(int level); virtual int target_level_dbfs() const; virtual float voice_probability() const; private: double target_level_loudness_; int target_level_dbfs_; std::unique_ptr histogram_; std::unique_ptr inactive_histogram_; VoiceActivityDetector vad_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC_AGC_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc/agc_manager_direct.cc0000664000175000017500000005246214475643423030011 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc/agc_manager_direct.h" #include #include #include "common_audio/include/audio_util.h" #include "modules/audio_processing/agc/gain_control.h" #include "modules/audio_processing/agc/gain_map_internal.h" #include "modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.h" #include "rtc_base/atomic_ops.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_minmax.h" #include "system_wrappers/include/field_trial.h" #include "system_wrappers/include/metrics.h" namespace webrtc { namespace { // Amount the microphone level is lowered with every clipping event. const int kClippedLevelStep = 15; // Proportion of clipped samples required to declare a clipping event. const float kClippedRatioThreshold = 0.1f; // Time in frames to wait after a clipping event before checking again. const int kClippedWaitFrames = 300; // Amount of error we tolerate in the microphone level (presumably due to OS // quantization) before we assume the user has manually adjusted the microphone. const int kLevelQuantizationSlack = 25; const int kDefaultCompressionGain = 7; const int kMaxCompressionGain = 12; const int kMinCompressionGain = 2; // Controls the rate of compression changes towards the target. const float kCompressionGainStep = 0.05f; const int kMaxMicLevel = 255; static_assert(kGainMapSize > kMaxMicLevel, "gain map too small"); const int kMinMicLevel = 12; // Prevent very large microphone level changes. const int kMaxResidualGainChange = 15; // Maximum additional gain allowed to compensate for microphone level // restrictions from clipping events. const int kSurplusCompressionGain = 6; // Returns whether a fall-back solution to choose the maximum level should be // chosen. bool UseMaxAnalogChannelLevel() { return field_trial::IsEnabled("WebRTC-UseMaxAnalogAgcChannelLevel"); } // Returns kMinMicLevel if no field trial exists or if it has been disabled. // Returns a value between 0 and 255 depending on the field-trial string. // Example: 'WebRTC-Audio-AgcMinMicLevelExperiment/Enabled-80' => returns 80. int GetMinMicLevel() { RTC_LOG(LS_INFO) << "[agc] GetMinMicLevel"; constexpr char kMinMicLevelFieldTrial[] = "WebRTC-Audio-AgcMinMicLevelExperiment"; if (!webrtc::field_trial::IsEnabled(kMinMicLevelFieldTrial)) { RTC_LOG(LS_INFO) << "[agc] Using default min mic level: " << kMinMicLevel; return kMinMicLevel; } const auto field_trial_string = webrtc::field_trial::FindFullName(kMinMicLevelFieldTrial); int min_mic_level = -1; sscanf(field_trial_string.c_str(), "Enabled-%d", &min_mic_level); if (min_mic_level >= 0 && min_mic_level <= 255) { RTC_LOG(LS_INFO) << "[agc] Experimental min mic level: " << min_mic_level; return min_mic_level; } else { RTC_LOG(LS_WARNING) << "[agc] Invalid parameter for " << kMinMicLevelFieldTrial << ", ignored."; return kMinMicLevel; } } int ClampLevel(int mic_level, int min_mic_level) { return rtc::SafeClamp(mic_level, min_mic_level, kMaxMicLevel); } int LevelFromGainError(int gain_error, int level, int min_mic_level) { RTC_DCHECK_GE(level, 0); RTC_DCHECK_LE(level, kMaxMicLevel); if (gain_error == 0) { return level; } int new_level = level; if (gain_error > 0) { while (kGainMap[new_level] - kGainMap[level] < gain_error && new_level < kMaxMicLevel) { ++new_level; } } else { while (kGainMap[new_level] - kGainMap[level] > gain_error && new_level > min_mic_level) { --new_level; } } return new_level; } // Returns the proportion of samples in the buffer which are at full-scale // (and presumably clipped). float ComputeClippedRatio(const float* const* audio, size_t num_channels, size_t samples_per_channel) { RTC_DCHECK_GT(samples_per_channel, 0); int num_clipped = 0; for (size_t ch = 0; ch < num_channels; ++ch) { int num_clipped_in_ch = 0; for (size_t i = 0; i < samples_per_channel; ++i) { RTC_DCHECK(audio[ch]); if (audio[ch][i] >= 32767.f || audio[ch][i] <= -32768.f) { ++num_clipped_in_ch; } } num_clipped = std::max(num_clipped, num_clipped_in_ch); } return static_cast(num_clipped) / (samples_per_channel); } } // namespace MonoAgc::MonoAgc(ApmDataDumper* data_dumper, int startup_min_level, int clipped_level_min, bool use_agc2_level_estimation, bool disable_digital_adaptive, int min_mic_level) : min_mic_level_(min_mic_level), disable_digital_adaptive_(disable_digital_adaptive), max_level_(kMaxMicLevel), max_compression_gain_(kMaxCompressionGain), target_compression_(kDefaultCompressionGain), compression_(target_compression_), compression_accumulator_(compression_), startup_min_level_(ClampLevel(startup_min_level, min_mic_level_)), clipped_level_min_(clipped_level_min) { if (use_agc2_level_estimation) { agc_ = std::make_unique(data_dumper); } else { agc_ = std::make_unique(); } } MonoAgc::~MonoAgc() = default; void MonoAgc::Initialize() { max_level_ = kMaxMicLevel; max_compression_gain_ = kMaxCompressionGain; target_compression_ = disable_digital_adaptive_ ? 0 : kDefaultCompressionGain; compression_ = disable_digital_adaptive_ ? 0 : target_compression_; compression_accumulator_ = compression_; capture_muted_ = false; check_volume_on_next_process_ = true; } void MonoAgc::Process(const int16_t* audio, size_t samples_per_channel, int sample_rate_hz) { new_compression_to_set_ = absl::nullopt; if (check_volume_on_next_process_) { check_volume_on_next_process_ = false; // We have to wait until the first process call to check the volume, // because Chromium doesn't guarantee it to be valid any earlier. CheckVolumeAndReset(); } agc_->Process(audio, samples_per_channel, sample_rate_hz); UpdateGain(); if (!disable_digital_adaptive_) { UpdateCompressor(); } } void MonoAgc::HandleClipping() { // Always decrease the maximum level, even if the current level is below // threshold. SetMaxLevel(std::max(clipped_level_min_, max_level_ - kClippedLevelStep)); if (log_to_histograms_) { RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.AgcClippingAdjustmentAllowed", level_ - kClippedLevelStep >= clipped_level_min_); } if (level_ > clipped_level_min_) { // Don't try to adjust the level if we're already below the limit. As // a consequence, if the user has brought the level above the limit, we // will still not react until the postproc updates the level. SetLevel(std::max(clipped_level_min_, level_ - kClippedLevelStep)); // Reset the AGCs for all channels since the level has changed. agc_->Reset(); } } void MonoAgc::SetLevel(int new_level) { int voe_level = stream_analog_level_; if (voe_level == 0) { RTC_DLOG(LS_INFO) << "[agc] VolumeCallbacks returned level=0, taking no action."; return; } if (voe_level < 0 || voe_level > kMaxMicLevel) { RTC_LOG(LS_ERROR) << "VolumeCallbacks returned an invalid level=" << voe_level; return; } if (voe_level > level_ + kLevelQuantizationSlack || voe_level < level_ - kLevelQuantizationSlack) { RTC_DLOG(LS_INFO) << "[agc] Mic volume was manually adjusted. Updating " "stored level from " << level_ << " to " << voe_level; level_ = voe_level; // Always allow the user to increase the volume. if (level_ > max_level_) { SetMaxLevel(level_); } // Take no action in this case, since we can't be sure when the volume // was manually adjusted. The compressor will still provide some of the // desired gain change. agc_->Reset(); return; } new_level = std::min(new_level, max_level_); if (new_level == level_) { return; } stream_analog_level_ = new_level; RTC_DLOG(LS_INFO) << "[agc] voe_level=" << voe_level << ", level_=" << level_ << ", new_level=" << new_level; level_ = new_level; } void MonoAgc::SetMaxLevel(int level) { RTC_DCHECK_GE(level, clipped_level_min_); max_level_ = level; // Scale the |kSurplusCompressionGain| linearly across the restricted // level range. max_compression_gain_ = kMaxCompressionGain + std::floor((1.f * kMaxMicLevel - max_level_) / (kMaxMicLevel - clipped_level_min_) * kSurplusCompressionGain + 0.5f); RTC_DLOG(LS_INFO) << "[agc] max_level_=" << max_level_ << ", max_compression_gain_=" << max_compression_gain_; } void MonoAgc::SetCaptureMuted(bool muted) { if (capture_muted_ == muted) { return; } capture_muted_ = muted; if (!muted) { // When we unmute, we should reset things to be safe. check_volume_on_next_process_ = true; } } int MonoAgc::CheckVolumeAndReset() { int level = stream_analog_level_; // Reasons for taking action at startup: // 1) A person starting a call is expected to be heard. // 2) Independent of interpretation of |level| == 0 we should raise it so the // AGC can do its job properly. if (level == 0 && !startup_) { RTC_DLOG(LS_INFO) << "[agc] VolumeCallbacks returned level=0, taking no action."; return 0; } if (level < 0 || level > kMaxMicLevel) { RTC_LOG(LS_ERROR) << "[agc] VolumeCallbacks returned an invalid level=" << level; return -1; } RTC_DLOG(LS_INFO) << "[agc] Initial GetMicVolume()=" << level; int minLevel = startup_ ? startup_min_level_ : min_mic_level_; if (level < minLevel) { level = minLevel; RTC_DLOG(LS_INFO) << "[agc] Initial volume too low, raising to " << level; stream_analog_level_ = level; } agc_->Reset(); level_ = level; startup_ = false; return 0; } // Requests the RMS error from AGC and distributes the required gain change // between the digital compression stage and volume slider. We use the // compressor first, providing a slack region around the current slider // position to reduce movement. // // If the slider needs to be moved, we check first if the user has adjusted // it, in which case we take no action and cache the updated level. void MonoAgc::UpdateGain() { int rms_error = 0; if (!agc_->GetRmsErrorDb(&rms_error)) { // No error update ready. return; } // The compressor will always add at least kMinCompressionGain. In effect, // this adjusts our target gain upward by the same amount and rms_error // needs to reflect that. rms_error += kMinCompressionGain; // Handle as much error as possible with the compressor first. int raw_compression = rtc::SafeClamp(rms_error, kMinCompressionGain, max_compression_gain_); // Deemphasize the compression gain error. Move halfway between the current // target and the newly received target. This serves to soften perceptible // intra-talkspurt adjustments, at the cost of some adaptation speed. if ((raw_compression == max_compression_gain_ && target_compression_ == max_compression_gain_ - 1) || (raw_compression == kMinCompressionGain && target_compression_ == kMinCompressionGain + 1)) { // Special case to allow the target to reach the endpoints of the // compression range. The deemphasis would otherwise halt it at 1 dB shy. target_compression_ = raw_compression; } else { target_compression_ = (raw_compression - target_compression_) / 2 + target_compression_; } // Residual error will be handled by adjusting the volume slider. Use the // raw rather than deemphasized compression here as we would otherwise // shrink the amount of slack the compressor provides. const int residual_gain = rtc::SafeClamp(rms_error - raw_compression, -kMaxResidualGainChange, kMaxResidualGainChange); RTC_DLOG(LS_INFO) << "[agc] rms_error=" << rms_error << ", target_compression=" << target_compression_ << ", residual_gain=" << residual_gain; if (residual_gain == 0) return; int old_level = level_; SetLevel(LevelFromGainError(residual_gain, level_, min_mic_level_)); if (old_level != level_) { // level_ was updated by SetLevel; log the new value. RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.AgcSetLevel", level_, 1, kMaxMicLevel, 50); // Reset the AGC since the level has changed. agc_->Reset(); } } void MonoAgc::UpdateCompressor() { calls_since_last_gain_log_++; if (calls_since_last_gain_log_ == 100) { calls_since_last_gain_log_ = 0; RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.Agc.DigitalGainApplied", compression_, 0, kMaxCompressionGain, kMaxCompressionGain + 1); } if (compression_ == target_compression_) { return; } // Adapt the compression gain slowly towards the target, in order to avoid // highly perceptible changes. if (target_compression_ > compression_) { compression_accumulator_ += kCompressionGainStep; } else { compression_accumulator_ -= kCompressionGainStep; } // The compressor accepts integer gains in dB. Adjust the gain when // we've come within half a stepsize of the nearest integer. (We don't // check for equality due to potential floating point imprecision). int new_compression = compression_; int nearest_neighbor = std::floor(compression_accumulator_ + 0.5); if (std::fabs(compression_accumulator_ - nearest_neighbor) < kCompressionGainStep / 2) { new_compression = nearest_neighbor; } // Set the new compression gain. if (new_compression != compression_) { RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.Agc.DigitalGainUpdated", new_compression, 0, kMaxCompressionGain, kMaxCompressionGain + 1); compression_ = new_compression; compression_accumulator_ = new_compression; new_compression_to_set_ = compression_; } } int AgcManagerDirect::instance_counter_ = 0; AgcManagerDirect::AgcManagerDirect(Agc* agc, int startup_min_level, int clipped_level_min, int sample_rate_hz) : AgcManagerDirect(/*num_capture_channels*/ 1, startup_min_level, clipped_level_min, /*use_agc2_level_estimation*/ false, /*disable_digital_adaptive*/ false, sample_rate_hz) { RTC_DCHECK(channel_agcs_[0]); RTC_DCHECK(agc); channel_agcs_[0]->set_agc(agc); } AgcManagerDirect::AgcManagerDirect(int num_capture_channels, int startup_min_level, int clipped_level_min, bool use_agc2_level_estimation, bool disable_digital_adaptive, int sample_rate_hz) : data_dumper_( new ApmDataDumper(rtc::AtomicOps::Increment(&instance_counter_))), use_min_channel_level_(!UseMaxAnalogChannelLevel()), sample_rate_hz_(sample_rate_hz), num_capture_channels_(num_capture_channels), disable_digital_adaptive_(disable_digital_adaptive), frames_since_clipped_(kClippedWaitFrames), capture_muted_(false), channel_agcs_(num_capture_channels), new_compressions_to_set_(num_capture_channels) { const int min_mic_level = GetMinMicLevel(); for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) { ApmDataDumper* data_dumper_ch = ch == 0 ? data_dumper_.get() : nullptr; channel_agcs_[ch] = std::make_unique( data_dumper_ch, startup_min_level, clipped_level_min, use_agc2_level_estimation, disable_digital_adaptive_, min_mic_level); } RTC_DCHECK_LT(0, channel_agcs_.size()); channel_agcs_[0]->ActivateLogging(); } AgcManagerDirect::~AgcManagerDirect() {} void AgcManagerDirect::Initialize() { RTC_DLOG(LS_INFO) << "AgcManagerDirect::Initialize"; data_dumper_->InitiateNewSetOfRecordings(); for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) { channel_agcs_[ch]->Initialize(); } capture_muted_ = false; AggregateChannelLevels(); } void AgcManagerDirect::SetupDigitalGainControl( GainControl* gain_control) const { RTC_DCHECK(gain_control); if (gain_control->set_mode(GainControl::kFixedDigital) != 0) { RTC_LOG(LS_ERROR) << "set_mode(GainControl::kFixedDigital) failed."; } const int target_level_dbfs = disable_digital_adaptive_ ? 0 : 2; if (gain_control->set_target_level_dbfs(target_level_dbfs) != 0) { RTC_LOG(LS_ERROR) << "set_target_level_dbfs() failed."; } const int compression_gain_db = disable_digital_adaptive_ ? 0 : kDefaultCompressionGain; if (gain_control->set_compression_gain_db(compression_gain_db) != 0) { RTC_LOG(LS_ERROR) << "set_compression_gain_db() failed."; } const bool enable_limiter = !disable_digital_adaptive_; if (gain_control->enable_limiter(enable_limiter) != 0) { RTC_LOG(LS_ERROR) << "enable_limiter() failed."; } } void AgcManagerDirect::AnalyzePreProcess(const AudioBuffer* audio) { RTC_DCHECK(audio); AnalyzePreProcess(audio->channels_const(), audio->num_frames()); } void AgcManagerDirect::AnalyzePreProcess(const float* const* audio, size_t samples_per_channel) { RTC_DCHECK(audio); AggregateChannelLevels(); if (capture_muted_) { return; } if (frames_since_clipped_ < kClippedWaitFrames) { ++frames_since_clipped_; return; } // Check for clipped samples, as the AGC has difficulty detecting pitch // under clipping distortion. We do this in the preprocessing phase in order // to catch clipped echo as well. // // If we find a sufficiently clipped frame, drop the current microphone level // and enforce a new maximum level, dropped the same amount from the current // maximum. This harsh treatment is an effort to avoid repeated clipped echo // events. As compensation for this restriction, the maximum compression // gain is increased, through SetMaxLevel(). float clipped_ratio = ComputeClippedRatio(audio, num_capture_channels_, samples_per_channel); if (clipped_ratio > kClippedRatioThreshold) { RTC_DLOG(LS_INFO) << "[agc] Clipping detected. clipped_ratio=" << clipped_ratio; for (auto& state_ch : channel_agcs_) { state_ch->HandleClipping(); } frames_since_clipped_ = 0; } AggregateChannelLevels(); } void AgcManagerDirect::Process(const AudioBuffer* audio) { AggregateChannelLevels(); if (capture_muted_) { return; } for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) { int16_t* audio_use = nullptr; std::array audio_data; int num_frames_per_band; if (audio) { FloatS16ToS16(audio->split_bands_const_f(ch)[0], audio->num_frames_per_band(), audio_data.data()); audio_use = audio_data.data(); num_frames_per_band = audio->num_frames_per_band(); } else { // Only used for testing. // TODO(peah): Change unittests to only allow on non-null audio input. num_frames_per_band = 320; } channel_agcs_[ch]->Process(audio_use, num_frames_per_band, sample_rate_hz_); new_compressions_to_set_[ch] = channel_agcs_[ch]->new_compression(); } AggregateChannelLevels(); } absl::optional AgcManagerDirect::GetDigitalComressionGain() { return new_compressions_to_set_[channel_controlling_gain_]; } void AgcManagerDirect::SetCaptureMuted(bool muted) { for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) { channel_agcs_[ch]->SetCaptureMuted(muted); } capture_muted_ = muted; } float AgcManagerDirect::voice_probability() const { float max_prob = 0.f; for (const auto& state_ch : channel_agcs_) { max_prob = std::max(max_prob, state_ch->voice_probability()); } return max_prob; } void AgcManagerDirect::set_stream_analog_level(int level) { for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) { channel_agcs_[ch]->set_stream_analog_level(level); } AggregateChannelLevels(); } void AgcManagerDirect::AggregateChannelLevels() { stream_analog_level_ = channel_agcs_[0]->stream_analog_level(); channel_controlling_gain_ = 0; if (use_min_channel_level_) { for (size_t ch = 1; ch < channel_agcs_.size(); ++ch) { int level = channel_agcs_[ch]->stream_analog_level(); if (level < stream_analog_level_) { stream_analog_level_ = level; channel_controlling_gain_ = static_cast(ch); } } } else { for (size_t ch = 1; ch < channel_agcs_.size(); ++ch) { int level = channel_agcs_[ch]->stream_analog_level(); if (level > stream_analog_level_) { stream_analog_level_ = level; channel_controlling_gain_ = static_cast(ch); } } } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc/agc_manager_direct.h0000664000175000017500000001337214475643423027650 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC_AGC_MANAGER_DIRECT_H_ #define MODULES_AUDIO_PROCESSING_AGC_AGC_MANAGER_DIRECT_H_ #include #include "absl/types/optional.h" #include "modules/audio_processing/agc/agc.h" #include "modules/audio_processing/audio_buffer.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/gtest_prod_util.h" namespace webrtc { class MonoAgc; class GainControl; // Direct interface to use AGC to set volume and compression values. // AudioProcessing uses this interface directly to integrate the callback-less // AGC. // // This class is not thread-safe. class AgcManagerDirect final { public: // AgcManagerDirect will configure GainControl internally. The user is // responsible for processing the audio using it after the call to Process. // The operating range of startup_min_level is [12, 255] and any input value // outside that range will be clamped. AgcManagerDirect(int num_capture_channels, int startup_min_level, int clipped_level_min, bool use_agc2_level_estimation, bool disable_digital_adaptive, int sample_rate_hz); ~AgcManagerDirect(); AgcManagerDirect(const AgcManagerDirect&) = delete; AgcManagerDirect& operator=(const AgcManagerDirect&) = delete; void Initialize(); void SetupDigitalGainControl(GainControl* gain_control) const; void AnalyzePreProcess(const AudioBuffer* audio); void Process(const AudioBuffer* audio); // Call when the capture stream has been muted/unmuted. This causes the // manager to disregard all incoming audio; chances are good it's background // noise to which we'd like to avoid adapting. void SetCaptureMuted(bool muted); float voice_probability() const; int stream_analog_level() const { return stream_analog_level_; } void set_stream_analog_level(int level); int num_channels() const { return num_capture_channels_; } int sample_rate_hz() const { return sample_rate_hz_; } // If available, returns a new compression gain for the digital gain control. absl::optional GetDigitalComressionGain(); private: friend class AgcManagerDirectTest; FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectStandaloneTest, DisableDigitalDisablesDigital); FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectStandaloneTest, AgcMinMicLevelExperiment); // Dependency injection for testing. Don't delete |agc| as the memory is owned // by the manager. AgcManagerDirect(Agc* agc, int startup_min_level, int clipped_level_min, int sample_rate_hz); void AnalyzePreProcess(const float* const* audio, size_t samples_per_channel); void AggregateChannelLevels(); std::unique_ptr data_dumper_; static int instance_counter_; const bool use_min_channel_level_; const int sample_rate_hz_; const int num_capture_channels_; const bool disable_digital_adaptive_; int frames_since_clipped_; int stream_analog_level_ = 0; bool capture_muted_; int channel_controlling_gain_ = 0; std::vector> channel_agcs_; std::vector> new_compressions_to_set_; }; class MonoAgc { public: MonoAgc(ApmDataDumper* data_dumper, int startup_min_level, int clipped_level_min, bool use_agc2_level_estimation, bool disable_digital_adaptive, int min_mic_level); ~MonoAgc(); MonoAgc(const MonoAgc&) = delete; MonoAgc& operator=(const MonoAgc&) = delete; void Initialize(); void SetCaptureMuted(bool muted); void HandleClipping(); void Process(const int16_t* audio, size_t samples_per_channel, int sample_rate_hz); void set_stream_analog_level(int level) { stream_analog_level_ = level; } int stream_analog_level() const { return stream_analog_level_; } float voice_probability() const { return agc_->voice_probability(); } void ActivateLogging() { log_to_histograms_ = true; } absl::optional new_compression() const { return new_compression_to_set_; } // Only used for testing. void set_agc(Agc* agc) { agc_.reset(agc); } int min_mic_level() const { return min_mic_level_; } int startup_min_level() const { return startup_min_level_; } private: // Sets a new microphone level, after first checking that it hasn't been // updated by the user, in which case no action is taken. void SetLevel(int new_level); // Set the maximum level the AGC is allowed to apply. Also updates the // maximum compression gain to compensate. The level must be at least // |kClippedLevelMin|. void SetMaxLevel(int level); int CheckVolumeAndReset(); void UpdateGain(); void UpdateCompressor(); const int min_mic_level_; const bool disable_digital_adaptive_; std::unique_ptr agc_; int level_ = 0; int max_level_; int max_compression_gain_; int target_compression_; int compression_; float compression_accumulator_; bool capture_muted_ = false; bool check_volume_on_next_process_ = true; bool startup_ = true; int startup_min_level_; int calls_since_last_gain_log_ = 0; int stream_analog_level_ = 0; absl::optional new_compression_to_set_; bool log_to_histograms_ = false; const int clipped_level_min_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC_AGC_MANAGER_DIRECT_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc/gain_control.h0000664000175000017500000001103114475643423026536 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC_GAIN_CONTROL_H_ #define MODULES_AUDIO_PROCESSING_AGC_GAIN_CONTROL_H_ namespace webrtc { // The automatic gain control (AGC) component brings the signal to an // appropriate range. This is done by applying a digital gain directly and, in // the analog mode, prescribing an analog gain to be applied at the audio HAL. // // Recommended to be enabled on the client-side. class GainControl { public: // When an analog mode is set, this must be called prior to |ProcessStream()| // to pass the current analog level from the audio HAL. Must be within the // range provided to |set_analog_level_limits()|. virtual int set_stream_analog_level(int level) = 0; // When an analog mode is set, this should be called after |ProcessStream()| // to obtain the recommended new analog level for the audio HAL. It is the // users responsibility to apply this level. virtual int stream_analog_level() const = 0; enum Mode { // Adaptive mode intended for use if an analog volume control is available // on the capture device. It will require the user to provide coupling // between the OS mixer controls and AGC through the |stream_analog_level()| // functions. // // It consists of an analog gain prescription for the audio device and a // digital compression stage. kAdaptiveAnalog, // Adaptive mode intended for situations in which an analog volume control // is unavailable. It operates in a similar fashion to the adaptive analog // mode, but with scaling instead applied in the digital domain. As with // the analog mode, it additionally uses a digital compression stage. kAdaptiveDigital, // Fixed mode which enables only the digital compression stage also used by // the two adaptive modes. // // It is distinguished from the adaptive modes by considering only a // short time-window of the input signal. It applies a fixed gain through // most of the input level range, and compresses (gradually reduces gain // with increasing level) the input signal at higher levels. This mode is // preferred on embedded devices where the capture signal level is // predictable, so that a known gain can be applied. kFixedDigital }; virtual int set_mode(Mode mode) = 0; virtual Mode mode() const = 0; // Sets the target peak |level| (or envelope) of the AGC in dBFs (decibels // from digital full-scale). The convention is to use positive values. For // instance, passing in a value of 3 corresponds to -3 dBFs, or a target // level 3 dB below full-scale. Limited to [0, 31]. // // TODO(ajm): use a negative value here instead, if/when VoE will similarly // update its interface. virtual int set_target_level_dbfs(int level) = 0; virtual int target_level_dbfs() const = 0; // Sets the maximum |gain| the digital compression stage may apply, in dB. A // higher number corresponds to greater compression, while a value of 0 will // leave the signal uncompressed. Limited to [0, 90]. virtual int set_compression_gain_db(int gain) = 0; virtual int compression_gain_db() const = 0; // When enabled, the compression stage will hard limit the signal to the // target level. Otherwise, the signal will be compressed but not limited // above the target level. virtual int enable_limiter(bool enable) = 0; virtual bool is_limiter_enabled() const = 0; // Sets the |minimum| and |maximum| analog levels of the audio capture device. // Must be set if and only if an analog mode is used. Limited to [0, 65535]. virtual int set_analog_level_limits(int minimum, int maximum) = 0; virtual int analog_level_minimum() const = 0; virtual int analog_level_maximum() const = 0; // Returns true if the AGC has detected a saturation event (period where the // signal reaches digital full-scale) in the current frame and the analog // level cannot be reduced. // // This could be used as an indicator to reduce or disable analog mic gain at // the audio HAL. virtual bool stream_is_saturated() const = 0; protected: virtual ~GainControl() {} }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC_GAIN_CONTROL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc/gain_map_internal.h0000664000175000017500000000406714475643423027542 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC_GAIN_MAP_INTERNAL_H_ #define MODULES_AUDIO_PROCESSING_AGC_GAIN_MAP_INTERNAL_H_ namespace webrtc { static const int kGainMapSize = 256; // Uses parameters: si = 2, sf = 0.25, D = 8/256 static const int kGainMap[kGainMapSize] = { -56, -54, -52, -50, -48, -47, -45, -43, -42, -40, -38, -37, -35, -34, -33, -31, -30, -29, -27, -26, -25, -24, -23, -22, -20, -19, -18, -17, -16, -15, -14, -14, -13, -12, -11, -10, -9, -8, -8, -7, -6, -5, -5, -4, -3, -2, -2, -1, 0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20, 20, 21, 21, 21, 22, 22, 22, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 26, 26, 26, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 64}; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC_GAIN_MAP_INTERNAL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc/legacy/0000775000175000017500000000000014475643423025157 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc/legacy/analog_agc.cc0000664000175000017500000011257614475643423027555 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * * Using a feedback system, determines an appropriate analog volume level * given an input signal and current volume level. Targets a conservative * signal level and is intended for use with a digital AGC to apply * additional gain. * */ #include "modules/audio_processing/agc/legacy/analog_agc.h" #include #include "rtc_base/checks.h" namespace webrtc { namespace { // Errors #define AGC_UNSPECIFIED_ERROR 18000 #define AGC_UNINITIALIZED_ERROR 18002 #define AGC_NULL_POINTER_ERROR 18003 #define AGC_BAD_PARAMETER_ERROR 18004 /* The slope of in Q13*/ static const int16_t kSlope1[8] = {21793, 12517, 7189, 4129, 2372, 1362, 472, 78}; /* The offset in Q14 */ static const int16_t kOffset1[8] = {25395, 23911, 22206, 20737, 19612, 18805, 17951, 17367}; /* The slope of in Q13*/ static const int16_t kSlope2[8] = {2063, 1731, 1452, 1218, 1021, 857, 597, 337}; /* The offset in Q14 */ static const int16_t kOffset2[8] = {18432, 18379, 18290, 18177, 18052, 17920, 17670, 17286}; static const int16_t kMuteGuardTimeMs = 8000; static const int16_t kInitCheck = 42; static const size_t kNumSubframes = 10; /* Default settings if config is not used */ #define AGC_DEFAULT_TARGET_LEVEL 3 #define AGC_DEFAULT_COMP_GAIN 9 /* This is the target level for the analog part in ENV scale. To convert to RMS * scale you * have to add OFFSET_ENV_TO_RMS. */ #define ANALOG_TARGET_LEVEL 11 #define ANALOG_TARGET_LEVEL_2 5 // ANALOG_TARGET_LEVEL / 2 /* Offset between RMS scale (analog part) and ENV scale (digital part). This * value actually * varies with the FIXED_ANALOG_TARGET_LEVEL, hence we should in the future * replace it with * a table. */ #define OFFSET_ENV_TO_RMS 9 /* The reference input level at which the digital part gives an output of * targetLevelDbfs * (desired level) if we have no compression gain. This level should be set high * enough not * to compress the peaks due to the dynamics. */ #define DIGITAL_REF_AT_0_COMP_GAIN 4 /* Speed of reference level decrease. */ #define DIFF_REF_TO_ANALOG 5 /* Size of analog gain table */ #define GAIN_TBL_LEN 32 /* Matlab code: * fprintf(1, '\t%i, %i, %i, %i,\n', round(10.^(linspace(0,10,32)/20) * 2^12)); */ /* Q12 */ static const uint16_t kGainTableAnalog[GAIN_TBL_LEN] = { 4096, 4251, 4412, 4579, 4752, 4932, 5118, 5312, 5513, 5722, 5938, 6163, 6396, 6638, 6889, 7150, 7420, 7701, 7992, 8295, 8609, 8934, 9273, 9623, 9987, 10365, 10758, 11165, 11587, 12025, 12480, 12953}; /* Gain/Suppression tables for virtual Mic (in Q10) */ static const uint16_t kGainTableVirtualMic[128] = { 1052, 1081, 1110, 1141, 1172, 1204, 1237, 1271, 1305, 1341, 1378, 1416, 1454, 1494, 1535, 1577, 1620, 1664, 1710, 1757, 1805, 1854, 1905, 1957, 2010, 2065, 2122, 2180, 2239, 2301, 2364, 2428, 2495, 2563, 2633, 2705, 2779, 2855, 2933, 3013, 3096, 3180, 3267, 3357, 3449, 3543, 3640, 3739, 3842, 3947, 4055, 4166, 4280, 4397, 4517, 4640, 4767, 4898, 5032, 5169, 5311, 5456, 5605, 5758, 5916, 6078, 6244, 6415, 6590, 6770, 6956, 7146, 7341, 7542, 7748, 7960, 8178, 8402, 8631, 8867, 9110, 9359, 9615, 9878, 10148, 10426, 10711, 11004, 11305, 11614, 11932, 12258, 12593, 12938, 13292, 13655, 14029, 14412, 14807, 15212, 15628, 16055, 16494, 16945, 17409, 17885, 18374, 18877, 19393, 19923, 20468, 21028, 21603, 22194, 22801, 23425, 24065, 24724, 25400, 26095, 26808, 27541, 28295, 29069, 29864, 30681, 31520, 32382}; static const uint16_t kSuppressionTableVirtualMic[128] = { 1024, 1006, 988, 970, 952, 935, 918, 902, 886, 870, 854, 839, 824, 809, 794, 780, 766, 752, 739, 726, 713, 700, 687, 675, 663, 651, 639, 628, 616, 605, 594, 584, 573, 563, 553, 543, 533, 524, 514, 505, 496, 487, 478, 470, 461, 453, 445, 437, 429, 421, 414, 406, 399, 392, 385, 378, 371, 364, 358, 351, 345, 339, 333, 327, 321, 315, 309, 304, 298, 293, 288, 283, 278, 273, 268, 263, 258, 254, 249, 244, 240, 236, 232, 227, 223, 219, 215, 211, 208, 204, 200, 197, 193, 190, 186, 183, 180, 176, 173, 170, 167, 164, 161, 158, 155, 153, 150, 147, 145, 142, 139, 137, 134, 132, 130, 127, 125, 123, 121, 118, 116, 114, 112, 110, 108, 106, 104, 102}; /* Table for target energy levels. Values in Q(-7) * Matlab code * targetLevelTable = fprintf('%d,\t%d,\t%d,\t%d,\n', * round((32767*10.^(-(0:63)'/20)).^2*16/2^7) */ static const int32_t kTargetLevelTable[64] = { 134209536, 106606424, 84680493, 67264106, 53429779, 42440782, 33711911, 26778323, 21270778, 16895980, 13420954, 10660642, 8468049, 6726411, 5342978, 4244078, 3371191, 2677832, 2127078, 1689598, 1342095, 1066064, 846805, 672641, 534298, 424408, 337119, 267783, 212708, 168960, 134210, 106606, 84680, 67264, 53430, 42441, 33712, 26778, 21271, 16896, 13421, 10661, 8468, 6726, 5343, 4244, 3371, 2678, 2127, 1690, 1342, 1066, 847, 673, 534, 424, 337, 268, 213, 169, 134, 107, 85, 67}; } // namespace int WebRtcAgc_AddMic(void* state, int16_t* const* in_mic, size_t num_bands, size_t samples) { int32_t nrg, max_nrg, sample, tmp32; int32_t* ptr; uint16_t targetGainIdx, gain; size_t i; int16_t n, L, tmp16, tmp_speech[16]; LegacyAgc* stt; stt = reinterpret_cast(state); if (stt->fs == 8000) { L = 8; if (samples != 80) { return -1; } } else { L = 16; if (samples != 160) { return -1; } } /* apply slowly varying digital gain */ if (stt->micVol > stt->maxAnalog) { /* |maxLevel| is strictly >= |micVol|, so this condition should be * satisfied here, ensuring there is no divide-by-zero. */ RTC_DCHECK_GT(stt->maxLevel, stt->maxAnalog); /* Q1 */ tmp16 = (int16_t)(stt->micVol - stt->maxAnalog); tmp32 = (GAIN_TBL_LEN - 1) * tmp16; tmp16 = (int16_t)(stt->maxLevel - stt->maxAnalog); targetGainIdx = tmp32 / tmp16; RTC_DCHECK_LT(targetGainIdx, GAIN_TBL_LEN); /* Increment through the table towards the target gain. * If micVol drops below maxAnalog, we allow the gain * to be dropped immediately. */ if (stt->gainTableIdx < targetGainIdx) { stt->gainTableIdx++; } else if (stt->gainTableIdx > targetGainIdx) { stt->gainTableIdx--; } /* Q12 */ gain = kGainTableAnalog[stt->gainTableIdx]; for (i = 0; i < samples; i++) { size_t j; for (j = 0; j < num_bands; ++j) { sample = (in_mic[j][i] * gain) >> 12; if (sample > 32767) { in_mic[j][i] = 32767; } else if (sample < -32768) { in_mic[j][i] = -32768; } else { in_mic[j][i] = (int16_t)sample; } } } } else { stt->gainTableIdx = 0; } /* compute envelope */ if (stt->inQueue > 0) { ptr = stt->env[1]; } else { ptr = stt->env[0]; } for (i = 0; i < kNumSubframes; i++) { /* iterate over samples */ max_nrg = 0; for (n = 0; n < L; n++) { nrg = in_mic[0][i * L + n] * in_mic[0][i * L + n]; if (nrg > max_nrg) { max_nrg = nrg; } } ptr[i] = max_nrg; } /* compute energy */ if (stt->inQueue > 0) { ptr = stt->Rxx16w32_array[1]; } else { ptr = stt->Rxx16w32_array[0]; } for (i = 0; i < kNumSubframes / 2; i++) { if (stt->fs == 16000) { WebRtcSpl_DownsampleBy2(&in_mic[0][i * 32], 32, tmp_speech, stt->filterState); } else { memcpy(tmp_speech, &in_mic[0][i * 16], 16 * sizeof(int16_t)); } /* Compute energy in blocks of 16 samples */ ptr[i] = WebRtcSpl_DotProductWithScale(tmp_speech, tmp_speech, 16, 4); } /* update queue information */ if (stt->inQueue == 0) { stt->inQueue = 1; } else { stt->inQueue = 2; } /* call VAD (use low band only) */ WebRtcAgc_ProcessVad(&stt->vadMic, in_mic[0], samples); return 0; } int WebRtcAgc_AddFarend(void* state, const int16_t* in_far, size_t samples) { LegacyAgc* stt = reinterpret_cast(state); int err = WebRtcAgc_GetAddFarendError(state, samples); if (err != 0) return err; return WebRtcAgc_AddFarendToDigital(&stt->digitalAgc, in_far, samples); } int WebRtcAgc_GetAddFarendError(void* state, size_t samples) { LegacyAgc* stt; stt = reinterpret_cast(state); if (stt == NULL) return -1; if (stt->fs == 8000) { if (samples != 80) return -1; } else if (stt->fs == 16000 || stt->fs == 32000 || stt->fs == 48000) { if (samples != 160) return -1; } else { return -1; } return 0; } int WebRtcAgc_VirtualMic(void* agcInst, int16_t* const* in_near, size_t num_bands, size_t samples, int32_t micLevelIn, int32_t* micLevelOut) { int32_t tmpFlt, micLevelTmp, gainIdx; uint16_t gain; size_t ii, j; LegacyAgc* stt; uint32_t nrg; size_t sampleCntr; uint32_t frameNrg = 0; uint32_t frameNrgLimit = 5500; int16_t numZeroCrossing = 0; const int16_t kZeroCrossingLowLim = 15; const int16_t kZeroCrossingHighLim = 20; stt = reinterpret_cast(agcInst); /* * Before applying gain decide if this is a low-level signal. * The idea is that digital AGC will not adapt to low-level * signals. */ if (stt->fs != 8000) { frameNrgLimit = frameNrgLimit << 1; } frameNrg = (uint32_t)(in_near[0][0] * in_near[0][0]); for (sampleCntr = 1; sampleCntr < samples; sampleCntr++) { // increment frame energy if it is less than the limit // the correct value of the energy is not important if (frameNrg < frameNrgLimit) { nrg = (uint32_t)(in_near[0][sampleCntr] * in_near[0][sampleCntr]); frameNrg += nrg; } // Count the zero crossings numZeroCrossing += ((in_near[0][sampleCntr] ^ in_near[0][sampleCntr - 1]) < 0); } if ((frameNrg < 500) || (numZeroCrossing <= 5)) { stt->lowLevelSignal = 1; } else if (numZeroCrossing <= kZeroCrossingLowLim) { stt->lowLevelSignal = 0; } else if (frameNrg <= frameNrgLimit) { stt->lowLevelSignal = 1; } else if (numZeroCrossing >= kZeroCrossingHighLim) { stt->lowLevelSignal = 1; } else { stt->lowLevelSignal = 0; } micLevelTmp = micLevelIn << stt->scale; /* Set desired level */ gainIdx = stt->micVol; if (stt->micVol > stt->maxAnalog) { gainIdx = stt->maxAnalog; } if (micLevelTmp != stt->micRef) { /* Something has happened with the physical level, restart. */ stt->micRef = micLevelTmp; stt->micVol = 127; *micLevelOut = 127; stt->micGainIdx = 127; gainIdx = 127; } /* Pre-process the signal to emulate the microphone level. */ /* Take one step at a time in the gain table. */ if (gainIdx > 127) { gain = kGainTableVirtualMic[gainIdx - 128]; } else { gain = kSuppressionTableVirtualMic[127 - gainIdx]; } for (ii = 0; ii < samples; ii++) { tmpFlt = (in_near[0][ii] * gain) >> 10; if (tmpFlt > 32767) { tmpFlt = 32767; gainIdx--; if (gainIdx >= 127) { gain = kGainTableVirtualMic[gainIdx - 127]; } else { gain = kSuppressionTableVirtualMic[127 - gainIdx]; } } if (tmpFlt < -32768) { tmpFlt = -32768; gainIdx--; if (gainIdx >= 127) { gain = kGainTableVirtualMic[gainIdx - 127]; } else { gain = kSuppressionTableVirtualMic[127 - gainIdx]; } } in_near[0][ii] = (int16_t)tmpFlt; for (j = 1; j < num_bands; ++j) { tmpFlt = (in_near[j][ii] * gain) >> 10; if (tmpFlt > 32767) { tmpFlt = 32767; } if (tmpFlt < -32768) { tmpFlt = -32768; } in_near[j][ii] = (int16_t)tmpFlt; } } /* Set the level we (finally) used */ stt->micGainIdx = gainIdx; // *micLevelOut = stt->micGainIdx; *micLevelOut = stt->micGainIdx >> stt->scale; /* Add to Mic as if it was the output from a true microphone */ if (WebRtcAgc_AddMic(agcInst, in_near, num_bands, samples) != 0) { return -1; } return 0; } void WebRtcAgc_UpdateAgcThresholds(LegacyAgc* stt) { int16_t tmp16; /* Set analog target level in envelope dBOv scale */ tmp16 = (DIFF_REF_TO_ANALOG * stt->compressionGaindB) + ANALOG_TARGET_LEVEL_2; tmp16 = WebRtcSpl_DivW32W16ResW16((int32_t)tmp16, ANALOG_TARGET_LEVEL); stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN + tmp16; if (stt->analogTarget < DIGITAL_REF_AT_0_COMP_GAIN) { stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN; } if (stt->agcMode == kAgcModeFixedDigital) { /* Adjust for different parameter interpretation in FixedDigital mode */ stt->analogTarget = stt->compressionGaindB; } /* Since the offset between RMS and ENV is not constant, we should make this * into a * table, but for now, we'll stick with a constant, tuned for the chosen * analog * target level. */ stt->targetIdx = ANALOG_TARGET_LEVEL + OFFSET_ENV_TO_RMS; /* Analog adaptation limits */ /* analogTargetLevel = round((32767*10^(-targetIdx/20))^2*16/2^7) */ stt->analogTargetLevel = kRxxBufferLen * kTargetLevelTable[stt->targetIdx]; /* ex. -20 dBov */ stt->startUpperLimit = kRxxBufferLen * kTargetLevelTable[stt->targetIdx - 1]; /* -19 dBov */ stt->startLowerLimit = kRxxBufferLen * kTargetLevelTable[stt->targetIdx + 1]; /* -21 dBov */ stt->upperPrimaryLimit = kRxxBufferLen * kTargetLevelTable[stt->targetIdx - 2]; /* -18 dBov */ stt->lowerPrimaryLimit = kRxxBufferLen * kTargetLevelTable[stt->targetIdx + 2]; /* -22 dBov */ stt->upperSecondaryLimit = kRxxBufferLen * kTargetLevelTable[stt->targetIdx - 5]; /* -15 dBov */ stt->lowerSecondaryLimit = kRxxBufferLen * kTargetLevelTable[stt->targetIdx + 5]; /* -25 dBov */ stt->upperLimit = stt->startUpperLimit; stt->lowerLimit = stt->startLowerLimit; } void WebRtcAgc_SaturationCtrl(LegacyAgc* stt, uint8_t* saturated, int32_t* env) { int16_t i, tmpW16; /* Check if the signal is saturated */ for (i = 0; i < 10; i++) { tmpW16 = (int16_t)(env[i] >> 20); if (tmpW16 > 875) { stt->envSum += tmpW16; } } if (stt->envSum > 25000) { *saturated = 1; stt->envSum = 0; } /* stt->envSum *= 0.99; */ stt->envSum = (int16_t)((stt->envSum * 32440) >> 15); } void WebRtcAgc_ZeroCtrl(LegacyAgc* stt, int32_t* inMicLevel, int32_t* env) { int16_t i; int64_t tmp = 0; int32_t midVal; /* Is the input signal zero? */ for (i = 0; i < 10; i++) { tmp += env[i]; } /* Each block is allowed to have a few non-zero * samples. */ if (tmp < 500) { stt->msZero += 10; } else { stt->msZero = 0; } if (stt->muteGuardMs > 0) { stt->muteGuardMs -= 10; } if (stt->msZero > 500) { stt->msZero = 0; /* Increase microphone level only if it's less than 50% */ midVal = (stt->maxAnalog + stt->minLevel + 1) / 2; if (*inMicLevel < midVal) { /* *inMicLevel *= 1.1; */ *inMicLevel = (1126 * *inMicLevel) >> 10; /* Reduces risk of a muted mic repeatedly triggering excessive levels due * to zero signal detection. */ *inMicLevel = WEBRTC_SPL_MIN(*inMicLevel, stt->zeroCtrlMax); stt->micVol = *inMicLevel; } stt->activeSpeech = 0; stt->Rxx16_LPw32Max = 0; /* The AGC has a tendency (due to problems with the VAD parameters), to * vastly increase the volume after a muting event. This timer prevents * upwards adaptation for a short period. */ stt->muteGuardMs = kMuteGuardTimeMs; } } void WebRtcAgc_SpeakerInactiveCtrl(LegacyAgc* stt) { /* Check if the near end speaker is inactive. * If that is the case the VAD threshold is * increased since the VAD speech model gets * more sensitive to any sound after a long * silence. */ int32_t tmp32; int16_t vadThresh; if (stt->vadMic.stdLongTerm < 2500) { stt->vadThreshold = 1500; } else { vadThresh = kNormalVadThreshold; if (stt->vadMic.stdLongTerm < 4500) { /* Scale between min and max threshold */ vadThresh += (4500 - stt->vadMic.stdLongTerm) / 2; } /* stt->vadThreshold = (31 * stt->vadThreshold + vadThresh) / 32; */ tmp32 = vadThresh + 31 * stt->vadThreshold; stt->vadThreshold = (int16_t)(tmp32 >> 5); } } void WebRtcAgc_ExpCurve(int16_t volume, int16_t* index) { // volume in Q14 // index in [0-7] /* 8 different curves */ if (volume > 5243) { if (volume > 7864) { if (volume > 12124) { *index = 7; } else { *index = 6; } } else { if (volume > 6554) { *index = 5; } else { *index = 4; } } } else { if (volume > 2621) { if (volume > 3932) { *index = 3; } else { *index = 2; } } else { if (volume > 1311) { *index = 1; } else { *index = 0; } } } } int32_t WebRtcAgc_ProcessAnalog(void* state, int32_t inMicLevel, int32_t* outMicLevel, int16_t vadLogRatio, int16_t echo, uint8_t* saturationWarning) { uint32_t tmpU32; int32_t Rxx16w32, tmp32; int32_t inMicLevelTmp, lastMicVol; int16_t i; uint8_t saturated = 0; LegacyAgc* stt; stt = reinterpret_cast(state); inMicLevelTmp = inMicLevel << stt->scale; if (inMicLevelTmp > stt->maxAnalog) { return -1; } else if (inMicLevelTmp < stt->minLevel) { return -1; } if (stt->firstCall == 0) { int32_t tmpVol; stt->firstCall = 1; tmp32 = ((stt->maxLevel - stt->minLevel) * 51) >> 9; tmpVol = (stt->minLevel + tmp32); /* If the mic level is very low at start, increase it! */ if ((inMicLevelTmp < tmpVol) && (stt->agcMode == kAgcModeAdaptiveAnalog)) { inMicLevelTmp = tmpVol; } stt->micVol = inMicLevelTmp; } /* Set the mic level to the previous output value if there is digital input * gain */ if ((inMicLevelTmp == stt->maxAnalog) && (stt->micVol > stt->maxAnalog)) { inMicLevelTmp = stt->micVol; } /* If the mic level was manually changed to a very low value raise it! */ if ((inMicLevelTmp != stt->micVol) && (inMicLevelTmp < stt->minOutput)) { tmp32 = ((stt->maxLevel - stt->minLevel) * 51) >> 9; inMicLevelTmp = (stt->minLevel + tmp32); stt->micVol = inMicLevelTmp; } if (inMicLevelTmp != stt->micVol) { if (inMicLevel == stt->lastInMicLevel) { // We requested a volume adjustment, but it didn't occur. This is // probably due to a coarse quantization of the volume slider. // Restore the requested value to prevent getting stuck. inMicLevelTmp = stt->micVol; } else { // As long as the value changed, update to match. stt->micVol = inMicLevelTmp; } } if (inMicLevelTmp > stt->maxLevel) { // Always allow the user to raise the volume above the maxLevel. stt->maxLevel = inMicLevelTmp; } // Store last value here, after we've taken care of manual updates etc. stt->lastInMicLevel = inMicLevel; lastMicVol = stt->micVol; /* Checks if the signal is saturated. Also a check if individual samples * are larger than 12000 is done. If they are the counter for increasing * the volume level is set to -100ms */ WebRtcAgc_SaturationCtrl(stt, &saturated, stt->env[0]); /* The AGC is always allowed to lower the level if the signal is saturated */ if (saturated == 1) { /* Lower the recording level * Rxx160_LP is adjusted down because it is so slow it could * cause the AGC to make wrong decisions. */ /* stt->Rxx160_LPw32 *= 0.875; */ stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 8) * 7; stt->zeroCtrlMax = stt->micVol; /* stt->micVol *= 0.903; */ tmp32 = inMicLevelTmp - stt->minLevel; tmpU32 = WEBRTC_SPL_UMUL(29591, (uint32_t)(tmp32)); stt->micVol = (tmpU32 >> 15) + stt->minLevel; if (stt->micVol > lastMicVol - 2) { stt->micVol = lastMicVol - 2; } inMicLevelTmp = stt->micVol; if (stt->micVol < stt->minOutput) { *saturationWarning = 1; } /* Reset counter for decrease of volume level to avoid * decreasing too much. The saturation control can still * lower the level if needed. */ stt->msTooHigh = -100; /* Enable the control mechanism to ensure that our measure, * Rxx160_LP, is in the correct range. This must be done since * the measure is very slow. */ stt->activeSpeech = 0; stt->Rxx16_LPw32Max = 0; /* Reset to initial values */ stt->msecSpeechInnerChange = kMsecSpeechInner; stt->msecSpeechOuterChange = kMsecSpeechOuter; stt->changeToSlowMode = 0; stt->muteGuardMs = 0; stt->upperLimit = stt->startUpperLimit; stt->lowerLimit = stt->startLowerLimit; } /* Check if the input speech is zero. If so the mic volume * is increased. On some computers the input is zero up as high * level as 17% */ WebRtcAgc_ZeroCtrl(stt, &inMicLevelTmp, stt->env[0]); /* Check if the near end speaker is inactive. * If that is the case the VAD threshold is * increased since the VAD speech model gets * more sensitive to any sound after a long * silence. */ WebRtcAgc_SpeakerInactiveCtrl(stt); for (i = 0; i < 5; i++) { /* Computed on blocks of 16 samples */ Rxx16w32 = stt->Rxx16w32_array[0][i]; /* Rxx160w32 in Q(-7) */ tmp32 = (Rxx16w32 - stt->Rxx16_vectorw32[stt->Rxx16pos]) >> 3; stt->Rxx160w32 = stt->Rxx160w32 + tmp32; stt->Rxx16_vectorw32[stt->Rxx16pos] = Rxx16w32; /* Circular buffer */ stt->Rxx16pos++; if (stt->Rxx16pos == kRxxBufferLen) { stt->Rxx16pos = 0; } /* Rxx16_LPw32 in Q(-4) */ tmp32 = (Rxx16w32 - stt->Rxx16_LPw32) >> kAlphaShortTerm; stt->Rxx16_LPw32 = (stt->Rxx16_LPw32) + tmp32; if (vadLogRatio > stt->vadThreshold) { /* Speech detected! */ /* Check if Rxx160_LP is in the correct range. If * it is too high/low then we set it to the maximum of * Rxx16_LPw32 during the first 200ms of speech. */ if (stt->activeSpeech < 250) { stt->activeSpeech += 2; if (stt->Rxx16_LPw32 > stt->Rxx16_LPw32Max) { stt->Rxx16_LPw32Max = stt->Rxx16_LPw32; } } else if (stt->activeSpeech == 250) { stt->activeSpeech += 2; tmp32 = stt->Rxx16_LPw32Max >> 3; stt->Rxx160_LPw32 = tmp32 * kRxxBufferLen; } tmp32 = (stt->Rxx160w32 - stt->Rxx160_LPw32) >> kAlphaLongTerm; stt->Rxx160_LPw32 = stt->Rxx160_LPw32 + tmp32; if (stt->Rxx160_LPw32 > stt->upperSecondaryLimit) { stt->msTooHigh += 2; stt->msTooLow = 0; stt->changeToSlowMode = 0; if (stt->msTooHigh > stt->msecSpeechOuterChange) { stt->msTooHigh = 0; /* Lower the recording level */ /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */ tmp32 = stt->Rxx160_LPw32 >> 6; stt->Rxx160_LPw32 = tmp32 * 53; /* Reduce the max gain to avoid excessive oscillation * (but never drop below the maximum analog level). */ stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16; stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog); stt->zeroCtrlMax = stt->micVol; /* 0.95 in Q15 */ tmp32 = inMicLevelTmp - stt->minLevel; tmpU32 = WEBRTC_SPL_UMUL(31130, (uint32_t)(tmp32)); stt->micVol = (tmpU32 >> 15) + stt->minLevel; if (stt->micVol > lastMicVol - 1) { stt->micVol = lastMicVol - 1; } inMicLevelTmp = stt->micVol; /* Enable the control mechanism to ensure that our measure, * Rxx160_LP, is in the correct range. */ stt->activeSpeech = 0; stt->Rxx16_LPw32Max = 0; } } else if (stt->Rxx160_LPw32 > stt->upperLimit) { stt->msTooHigh += 2; stt->msTooLow = 0; stt->changeToSlowMode = 0; if (stt->msTooHigh > stt->msecSpeechInnerChange) { /* Lower the recording level */ stt->msTooHigh = 0; /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */ stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 53; /* Reduce the max gain to avoid excessive oscillation * (but never drop below the maximum analog level). */ stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16; stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog); stt->zeroCtrlMax = stt->micVol; /* 0.965 in Q15 */ tmp32 = inMicLevelTmp - stt->minLevel; tmpU32 = WEBRTC_SPL_UMUL(31621, (uint32_t)(inMicLevelTmp - stt->minLevel)); stt->micVol = (tmpU32 >> 15) + stt->minLevel; if (stt->micVol > lastMicVol - 1) { stt->micVol = lastMicVol - 1; } inMicLevelTmp = stt->micVol; } } else if (stt->Rxx160_LPw32 < stt->lowerSecondaryLimit) { stt->msTooHigh = 0; stt->changeToSlowMode = 0; stt->msTooLow += 2; if (stt->msTooLow > stt->msecSpeechOuterChange) { /* Raise the recording level */ int16_t index, weightFIX; int16_t volNormFIX = 16384; // =1 in Q14. stt->msTooLow = 0; /* Normalize the volume level */ tmp32 = (inMicLevelTmp - stt->minLevel) << 14; if (stt->maxInit != stt->minLevel) { volNormFIX = tmp32 / (stt->maxInit - stt->minLevel); } /* Find correct curve */ WebRtcAgc_ExpCurve(volNormFIX, &index); /* Compute weighting factor for the volume increase, 32^(-2*X)/2+1.05 */ weightFIX = kOffset1[index] - (int16_t)((kSlope1[index] * volNormFIX) >> 13); /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */ stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 67; tmp32 = inMicLevelTmp - stt->minLevel; tmpU32 = ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel)); stt->micVol = (tmpU32 >> 14) + stt->minLevel; if (stt->micVol < lastMicVol + 2) { stt->micVol = lastMicVol + 2; } inMicLevelTmp = stt->micVol; } } else if (stt->Rxx160_LPw32 < stt->lowerLimit) { stt->msTooHigh = 0; stt->changeToSlowMode = 0; stt->msTooLow += 2; if (stt->msTooLow > stt->msecSpeechInnerChange) { /* Raise the recording level */ int16_t index, weightFIX; int16_t volNormFIX = 16384; // =1 in Q14. stt->msTooLow = 0; /* Normalize the volume level */ tmp32 = (inMicLevelTmp - stt->minLevel) << 14; if (stt->maxInit != stt->minLevel) { volNormFIX = tmp32 / (stt->maxInit - stt->minLevel); } /* Find correct curve */ WebRtcAgc_ExpCurve(volNormFIX, &index); /* Compute weighting factor for the volume increase, (3.^(-2.*X))/8+1 */ weightFIX = kOffset2[index] - (int16_t)((kSlope2[index] * volNormFIX) >> 13); /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */ stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 67; tmp32 = inMicLevelTmp - stt->minLevel; tmpU32 = ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel)); stt->micVol = (tmpU32 >> 14) + stt->minLevel; if (stt->micVol < lastMicVol + 1) { stt->micVol = lastMicVol + 1; } inMicLevelTmp = stt->micVol; } } else { /* The signal is inside the desired range which is: * lowerLimit < Rxx160_LP/640 < upperLimit */ if (stt->changeToSlowMode > 4000) { stt->msecSpeechInnerChange = 1000; stt->msecSpeechOuterChange = 500; stt->upperLimit = stt->upperPrimaryLimit; stt->lowerLimit = stt->lowerPrimaryLimit; } else { stt->changeToSlowMode += 2; // in milliseconds } stt->msTooLow = 0; stt->msTooHigh = 0; stt->micVol = inMicLevelTmp; } } } /* Ensure gain is not increased in presence of echo or after a mute event * (but allow the zeroCtrl() increase on the frame of a mute detection). */ if (echo == 1 || (stt->muteGuardMs > 0 && stt->muteGuardMs < kMuteGuardTimeMs)) { if (stt->micVol > lastMicVol) { stt->micVol = lastMicVol; } } /* limit the gain */ if (stt->micVol > stt->maxLevel) { stt->micVol = stt->maxLevel; } else if (stt->micVol < stt->minOutput) { stt->micVol = stt->minOutput; } *outMicLevel = WEBRTC_SPL_MIN(stt->micVol, stt->maxAnalog) >> stt->scale; return 0; } int WebRtcAgc_Analyze(void* agcInst, const int16_t* const* in_near, size_t num_bands, size_t samples, int32_t inMicLevel, int32_t* outMicLevel, int16_t echo, uint8_t* saturationWarning, int32_t gains[11]) { LegacyAgc* stt = reinterpret_cast(agcInst); if (stt == NULL) { return -1; } if (stt->fs == 8000) { if (samples != 80) { return -1; } } else if (stt->fs == 16000 || stt->fs == 32000 || stt->fs == 48000) { if (samples != 160) { return -1; } } else { return -1; } *saturationWarning = 0; // TODO(minyue): PUT IN RANGE CHECKING FOR INPUT LEVELS *outMicLevel = inMicLevel; int32_t error = WebRtcAgc_ComputeDigitalGains(&stt->digitalAgc, in_near, num_bands, stt->fs, stt->lowLevelSignal, gains); if (error == -1) { return -1; } if (stt->agcMode < kAgcModeFixedDigital && (stt->lowLevelSignal == 0 || stt->agcMode != kAgcModeAdaptiveDigital)) { if (WebRtcAgc_ProcessAnalog(agcInst, inMicLevel, outMicLevel, stt->vadMic.logRatio, echo, saturationWarning) == -1) { return -1; } } /* update queue */ if (stt->inQueue > 1) { memcpy(stt->env[0], stt->env[1], 10 * sizeof(int32_t)); memcpy(stt->Rxx16w32_array[0], stt->Rxx16w32_array[1], 5 * sizeof(int32_t)); } if (stt->inQueue > 0) { stt->inQueue--; } return 0; } int WebRtcAgc_Process(const void* agcInst, const int32_t gains[11], const int16_t* const* in_near, size_t num_bands, int16_t* const* out) { const LegacyAgc* stt = (const LegacyAgc*)agcInst; return WebRtcAgc_ApplyDigitalGains(gains, num_bands, stt->fs, in_near, out); } int WebRtcAgc_set_config(void* agcInst, WebRtcAgcConfig agcConfig) { LegacyAgc* stt; stt = reinterpret_cast(agcInst); if (stt == NULL) { return -1; } if (stt->initFlag != kInitCheck) { stt->lastError = AGC_UNINITIALIZED_ERROR; return -1; } if (agcConfig.limiterEnable != kAgcFalse && agcConfig.limiterEnable != kAgcTrue) { stt->lastError = AGC_BAD_PARAMETER_ERROR; return -1; } stt->limiterEnable = agcConfig.limiterEnable; stt->compressionGaindB = agcConfig.compressionGaindB; if ((agcConfig.targetLevelDbfs < 0) || (agcConfig.targetLevelDbfs > 31)) { stt->lastError = AGC_BAD_PARAMETER_ERROR; return -1; } stt->targetLevelDbfs = agcConfig.targetLevelDbfs; if (stt->agcMode == kAgcModeFixedDigital) { /* Adjust for different parameter interpretation in FixedDigital mode */ stt->compressionGaindB += agcConfig.targetLevelDbfs; } /* Update threshold levels for analog adaptation */ WebRtcAgc_UpdateAgcThresholds(stt); /* Recalculate gain table */ if (WebRtcAgc_CalculateGainTable( &(stt->digitalAgc.gainTable[0]), stt->compressionGaindB, stt->targetLevelDbfs, stt->limiterEnable, stt->analogTarget) == -1) { return -1; } /* Store the config in a WebRtcAgcConfig */ stt->usedConfig.compressionGaindB = agcConfig.compressionGaindB; stt->usedConfig.limiterEnable = agcConfig.limiterEnable; stt->usedConfig.targetLevelDbfs = agcConfig.targetLevelDbfs; return 0; } int WebRtcAgc_get_config(void* agcInst, WebRtcAgcConfig* config) { LegacyAgc* stt; stt = reinterpret_cast(agcInst); if (stt == NULL) { return -1; } if (config == NULL) { stt->lastError = AGC_NULL_POINTER_ERROR; return -1; } if (stt->initFlag != kInitCheck) { stt->lastError = AGC_UNINITIALIZED_ERROR; return -1; } config->limiterEnable = stt->usedConfig.limiterEnable; config->targetLevelDbfs = stt->usedConfig.targetLevelDbfs; config->compressionGaindB = stt->usedConfig.compressionGaindB; return 0; } void* WebRtcAgc_Create() { LegacyAgc* stt = static_cast(malloc(sizeof(LegacyAgc))); stt->initFlag = 0; stt->lastError = 0; return stt; } void WebRtcAgc_Free(void* state) { LegacyAgc* stt; stt = reinterpret_cast(state); free(stt); } /* minLevel - Minimum volume level * maxLevel - Maximum volume level */ int WebRtcAgc_Init(void* agcInst, int32_t minLevel, int32_t maxLevel, int16_t agcMode, uint32_t fs) { int32_t max_add, tmp32; int16_t i; int tmpNorm; LegacyAgc* stt; /* typecast state pointer */ stt = reinterpret_cast(agcInst); if (WebRtcAgc_InitDigital(&stt->digitalAgc, agcMode) != 0) { stt->lastError = AGC_UNINITIALIZED_ERROR; return -1; } /* Analog AGC variables */ stt->envSum = 0; /* mode = 0 - Only saturation protection * 1 - Analog Automatic Gain Control [-targetLevelDbfs (default -3 * dBOv)] * 2 - Digital Automatic Gain Control [-targetLevelDbfs (default -3 * dBOv)] * 3 - Fixed Digital Gain [compressionGaindB (default 8 dB)] */ if (agcMode < kAgcModeUnchanged || agcMode > kAgcModeFixedDigital) { return -1; } stt->agcMode = agcMode; stt->fs = fs; /* initialize input VAD */ WebRtcAgc_InitVad(&stt->vadMic); /* If the volume range is smaller than 0-256 then * the levels are shifted up to Q8-domain */ tmpNorm = WebRtcSpl_NormU32((uint32_t)maxLevel); stt->scale = tmpNorm - 23; if (stt->scale < 0) { stt->scale = 0; } // TODO(bjornv): Investigate if we really need to scale up a small range now // when we have // a guard against zero-increments. For now, we do not support scale up (scale // = 0). stt->scale = 0; maxLevel <<= stt->scale; minLevel <<= stt->scale; /* Make minLevel and maxLevel static in AdaptiveDigital */ if (stt->agcMode == kAgcModeAdaptiveDigital) { minLevel = 0; maxLevel = 255; stt->scale = 0; } /* The maximum supplemental volume range is based on a vague idea * of how much lower the gain will be than the real analog gain. */ max_add = (maxLevel - minLevel) / 4; /* Minimum/maximum volume level that can be set */ stt->minLevel = minLevel; stt->maxAnalog = maxLevel; stt->maxLevel = maxLevel + max_add; stt->maxInit = stt->maxLevel; stt->zeroCtrlMax = stt->maxAnalog; stt->lastInMicLevel = 0; /* Initialize micVol parameter */ stt->micVol = stt->maxAnalog; if (stt->agcMode == kAgcModeAdaptiveDigital) { stt->micVol = 127; /* Mid-point of mic level */ } stt->micRef = stt->micVol; stt->micGainIdx = 127; /* Minimum output volume is 4% higher than the available lowest volume level */ tmp32 = ((stt->maxLevel - stt->minLevel) * 10) >> 8; stt->minOutput = (stt->minLevel + tmp32); stt->msTooLow = 0; stt->msTooHigh = 0; stt->changeToSlowMode = 0; stt->firstCall = 0; stt->msZero = 0; stt->muteGuardMs = 0; stt->gainTableIdx = 0; stt->msecSpeechInnerChange = kMsecSpeechInner; stt->msecSpeechOuterChange = kMsecSpeechOuter; stt->activeSpeech = 0; stt->Rxx16_LPw32Max = 0; stt->vadThreshold = kNormalVadThreshold; stt->inActive = 0; for (i = 0; i < kRxxBufferLen; i++) { stt->Rxx16_vectorw32[i] = (int32_t)1000; /* -54dBm0 */ } stt->Rxx160w32 = 125 * kRxxBufferLen; /* (stt->Rxx16_vectorw32[0]>>3) = 125 */ stt->Rxx16pos = 0; stt->Rxx16_LPw32 = (int32_t)16284; /* Q(-4) */ for (i = 0; i < 5; i++) { stt->Rxx16w32_array[0][i] = 0; } for (i = 0; i < 10; i++) { stt->env[0][i] = 0; stt->env[1][i] = 0; } stt->inQueue = 0; WebRtcSpl_MemSetW32(stt->filterState, 0, 8); stt->initFlag = kInitCheck; // Default config settings. stt->defaultConfig.limiterEnable = kAgcTrue; stt->defaultConfig.targetLevelDbfs = AGC_DEFAULT_TARGET_LEVEL; stt->defaultConfig.compressionGaindB = AGC_DEFAULT_COMP_GAIN; if (WebRtcAgc_set_config(stt, stt->defaultConfig) == -1) { stt->lastError = AGC_UNSPECIFIED_ERROR; return -1; } stt->Rxx160_LPw32 = stt->analogTargetLevel; // Initialize rms value stt->lowLevelSignal = 0; /* Only positive values are allowed that are not too large */ if ((minLevel >= maxLevel) || (maxLevel & 0xFC000000)) { return -1; } else { return 0; } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc/legacy/analog_agc.h0000664000175000017500000001306514475643423027410 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC_LEGACY_ANALOG_AGC_H_ #define MODULES_AUDIO_PROCESSING_AGC_LEGACY_ANALOG_AGC_H_ #include "modules/audio_processing/agc/legacy/digital_agc.h" #include "modules/audio_processing/agc/legacy/gain_control.h" namespace webrtc { /* Analog Automatic Gain Control variables: * Constant declarations (inner limits inside which no changes are done) * In the beginning the range is narrower to widen as soon as the measure * 'Rxx160_LP' is inside it. Currently the starting limits are -22.2+/-1dBm0 * and the final limits -22.2+/-2.5dBm0. These levels makes the speech signal * go towards -25.4dBm0 (-31.4dBov). Tuned with wbfile-31.4dBov.pcm * The limits are created by running the AGC with a file having the desired * signal level and thereafter plotting Rxx160_LP in the dBm0-domain defined * by out=10*log10(in/260537279.7); Set the target level to the average level * of our measure Rxx160_LP. Remember that the levels are in blocks of 16 in * Q(-7). (Example matlab code: round(db2pow(-21.2)*16/2^7) ) */ constexpr int16_t kRxxBufferLen = 10; static const int16_t kMsecSpeechInner = 520; static const int16_t kMsecSpeechOuter = 340; static const int16_t kNormalVadThreshold = 400; static const int16_t kAlphaShortTerm = 6; // 1 >> 6 = 0.0156 static const int16_t kAlphaLongTerm = 10; // 1 >> 10 = 0.000977 typedef struct { // Configurable parameters/variables uint32_t fs; // Sampling frequency int16_t compressionGaindB; // Fixed gain level in dB int16_t targetLevelDbfs; // Target level in -dBfs of envelope (default -3) int16_t agcMode; // Hard coded mode (adaptAna/adaptDig/fixedDig) uint8_t limiterEnable; // Enabling limiter (on/off (default off)) WebRtcAgcConfig defaultConfig; WebRtcAgcConfig usedConfig; // General variables int16_t initFlag; int16_t lastError; // Target level parameters // Based on the above: analogTargetLevel = round((32767*10^(-22/20))^2*16/2^7) int32_t analogTargetLevel; // = kRxxBufferLen * 846805; -22 dBfs int32_t startUpperLimit; // = kRxxBufferLen * 1066064; -21 dBfs int32_t startLowerLimit; // = kRxxBufferLen * 672641; -23 dBfs int32_t upperPrimaryLimit; // = kRxxBufferLen * 1342095; -20 dBfs int32_t lowerPrimaryLimit; // = kRxxBufferLen * 534298; -24 dBfs int32_t upperSecondaryLimit; // = kRxxBufferLen * 2677832; -17 dBfs int32_t lowerSecondaryLimit; // = kRxxBufferLen * 267783; -27 dBfs uint16_t targetIdx; // Table index for corresponding target level int16_t analogTarget; // Digital reference level in ENV scale // Analog AGC specific variables int32_t filterState[8]; // For downsampling wb to nb int32_t upperLimit; // Upper limit for mic energy int32_t lowerLimit; // Lower limit for mic energy int32_t Rxx160w32; // Average energy for one frame int32_t Rxx16_LPw32; // Low pass filtered subframe energies int32_t Rxx160_LPw32; // Low pass filtered frame energies int32_t Rxx16_LPw32Max; // Keeps track of largest energy subframe int32_t Rxx16_vectorw32[kRxxBufferLen]; // Array with subframe energies int32_t Rxx16w32_array[2][5]; // Energy values of microphone signal int32_t env[2][10]; // Envelope values of subframes int16_t Rxx16pos; // Current position in the Rxx16_vectorw32 int16_t envSum; // Filtered scaled envelope in subframes int16_t vadThreshold; // Threshold for VAD decision int16_t inActive; // Inactive time in milliseconds int16_t msTooLow; // Milliseconds of speech at a too low level int16_t msTooHigh; // Milliseconds of speech at a too high level int16_t changeToSlowMode; // Change to slow mode after some time at target int16_t firstCall; // First call to the process-function int16_t msZero; // Milliseconds of zero input int16_t msecSpeechOuterChange; // Min ms of speech between volume changes int16_t msecSpeechInnerChange; // Min ms of speech between volume changes int16_t activeSpeech; // Milliseconds of active speech int16_t muteGuardMs; // Counter to prevent mute action int16_t inQueue; // 10 ms batch indicator // Microphone level variables int32_t micRef; // Remember ref. mic level for virtual mic uint16_t gainTableIdx; // Current position in virtual gain table int32_t micGainIdx; // Gain index of mic level to increase slowly int32_t micVol; // Remember volume between frames int32_t maxLevel; // Max possible vol level, incl dig gain int32_t maxAnalog; // Maximum possible analog volume level int32_t maxInit; // Initial value of "max" int32_t minLevel; // Minimum possible volume level int32_t minOutput; // Minimum output volume level int32_t zeroCtrlMax; // Remember max gain => don't amp low input int32_t lastInMicLevel; int16_t scale; // Scale factor for internal volume levels // Structs for VAD and digital_agc AgcVad vadMic; DigitalAgc digitalAgc; int16_t lowLevelSignal; } LegacyAgc; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC_LEGACY_ANALOG_AGC_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc/legacy/digital_agc.cc0000664000175000017500000005732714475643423027733 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc/legacy/digital_agc.h" #include #include "modules/audio_processing/agc/legacy/gain_control.h" #include "rtc_base/checks.h" namespace webrtc { namespace { // To generate the gaintable, copy&paste the following lines to a Matlab window: // MaxGain = 6; MinGain = 0; CompRatio = 3; Knee = 1; // zeros = 0:31; lvl = 2.^(1-zeros); // A = -10*log10(lvl) * (CompRatio - 1) / CompRatio; // B = MaxGain - MinGain; // gains = round(2^16*10.^(0.05 * (MinGain + B * ( // log(exp(-Knee*A)+exp(-Knee*B)) - log(1+exp(-Knee*B)) ) / // log(1/(1+exp(Knee*B)))))); // fprintf(1, '\t%i, %i, %i, %i,\n', gains); // % Matlab code for plotting the gain and input/output level characteristic // (copy/paste the following 3 lines): // in = 10*log10(lvl); out = 20*log10(gains/65536); // subplot(121); plot(in, out); axis([-30, 0, -5, 20]); grid on; xlabel('Input // (dB)'); ylabel('Gain (dB)'); // subplot(122); plot(in, in+out); axis([-30, 0, -30, 5]); grid on; // xlabel('Input (dB)'); ylabel('Output (dB)'); // zoom on; // Generator table for y=log2(1+e^x) in Q8. enum { kGenFuncTableSize = 128 }; static const uint16_t kGenFuncTable[kGenFuncTableSize] = { 256, 485, 786, 1126, 1484, 1849, 2217, 2586, 2955, 3324, 3693, 4063, 4432, 4801, 5171, 5540, 5909, 6279, 6648, 7017, 7387, 7756, 8125, 8495, 8864, 9233, 9603, 9972, 10341, 10711, 11080, 11449, 11819, 12188, 12557, 12927, 13296, 13665, 14035, 14404, 14773, 15143, 15512, 15881, 16251, 16620, 16989, 17359, 17728, 18097, 18466, 18836, 19205, 19574, 19944, 20313, 20682, 21052, 21421, 21790, 22160, 22529, 22898, 23268, 23637, 24006, 24376, 24745, 25114, 25484, 25853, 26222, 26592, 26961, 27330, 27700, 28069, 28438, 28808, 29177, 29546, 29916, 30285, 30654, 31024, 31393, 31762, 32132, 32501, 32870, 33240, 33609, 33978, 34348, 34717, 35086, 35456, 35825, 36194, 36564, 36933, 37302, 37672, 38041, 38410, 38780, 39149, 39518, 39888, 40257, 40626, 40996, 41365, 41734, 42104, 42473, 42842, 43212, 43581, 43950, 44320, 44689, 45058, 45428, 45797, 46166, 46536, 46905}; static const int16_t kAvgDecayTime = 250; // frames; < 3000 // the 32 most significant bits of A(19) * B(26) >> 13 #define AGC_MUL32(A, B) (((B) >> 13) * (A) + (((0x00001FFF & (B)) * (A)) >> 13)) // C + the 32 most significant bits of A * B #define AGC_SCALEDIFF32(A, B, C) \ ((C) + ((B) >> 16) * (A) + (((0x0000FFFF & (B)) * (A)) >> 16)) } // namespace int32_t WebRtcAgc_CalculateGainTable(int32_t* gainTable, // Q16 int16_t digCompGaindB, // Q0 int16_t targetLevelDbfs, // Q0 uint8_t limiterEnable, int16_t analogTarget) { // Q0 // This function generates the compressor gain table used in the fixed digital // part. uint32_t tmpU32no1, tmpU32no2, absInLevel, logApprox; int32_t inLevel, limiterLvl; int32_t tmp32, tmp32no1, tmp32no2, numFIX, den, y32; const uint16_t kLog10 = 54426; // log2(10) in Q14 const uint16_t kLog10_2 = 49321; // 10*log10(2) in Q14 const uint16_t kLogE_1 = 23637; // log2(e) in Q14 uint16_t constMaxGain; uint16_t tmpU16, intPart, fracPart; const int16_t kCompRatio = 3; const int16_t kSoftLimiterLeft = 1; int16_t limiterOffset = 0; // Limiter offset int16_t limiterIdx, limiterLvlX; int16_t constLinApprox, zeroGainLvl, maxGain, diffGain; int16_t i, tmp16, tmp16no1; int zeros, zerosScale; // Constants // kLogE_1 = 23637; // log2(e) in Q14 // kLog10 = 54426; // log2(10) in Q14 // kLog10_2 = 49321; // 10*log10(2) in Q14 // Calculate maximum digital gain and zero gain level tmp32no1 = (digCompGaindB - analogTarget) * (kCompRatio - 1); tmp16no1 = analogTarget - targetLevelDbfs; tmp16no1 += WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRatio); maxGain = WEBRTC_SPL_MAX(tmp16no1, (analogTarget - targetLevelDbfs)); tmp32no1 = maxGain * kCompRatio; zeroGainLvl = digCompGaindB; zeroGainLvl -= WebRtcSpl_DivW32W16ResW16(tmp32no1 + ((kCompRatio - 1) >> 1), kCompRatio - 1); if ((digCompGaindB <= analogTarget) && (limiterEnable)) { zeroGainLvl += (analogTarget - digCompGaindB + kSoftLimiterLeft); limiterOffset = 0; } // Calculate the difference between maximum gain and gain at 0dB0v: // diffGain = maxGain + (compRatio-1)*zeroGainLvl/compRatio // = (compRatio-1)*digCompGaindB/compRatio tmp32no1 = digCompGaindB * (kCompRatio - 1); diffGain = WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRatio); if (diffGain < 0 || diffGain >= kGenFuncTableSize) { RTC_DCHECK(0); return -1; } // Calculate the limiter level and index: // limiterLvlX = analogTarget - limiterOffset // limiterLvl = targetLevelDbfs + limiterOffset/compRatio limiterLvlX = analogTarget - limiterOffset; limiterIdx = 2 + WebRtcSpl_DivW32W16ResW16((int32_t)limiterLvlX * (1 << 13), kLog10_2 / 2); tmp16no1 = WebRtcSpl_DivW32W16ResW16(limiterOffset + (kCompRatio >> 1), kCompRatio); limiterLvl = targetLevelDbfs + tmp16no1; // Calculate (through table lookup): // constMaxGain = log2(1+2^(log2(e)*diffGain)); (in Q8) constMaxGain = kGenFuncTable[diffGain]; // in Q8 // Calculate a parameter used to approximate the fractional part of 2^x with a // piecewise linear function in Q14: // constLinApprox = round(3/2*(4*(3-2*sqrt(2))/(log(2)^2)-0.5)*2^14); constLinApprox = 22817; // in Q14 // Calculate a denominator used in the exponential part to convert from dB to // linear scale: // den = 20*constMaxGain (in Q8) den = WEBRTC_SPL_MUL_16_U16(20, constMaxGain); // in Q8 for (i = 0; i < 32; i++) { // Calculate scaled input level (compressor): // inLevel = // fix((-constLog10_2*(compRatio-1)*(1-i)+fix(compRatio/2))/compRatio) tmp16 = (int16_t)((kCompRatio - 1) * (i - 1)); // Q0 tmp32 = WEBRTC_SPL_MUL_16_U16(tmp16, kLog10_2) + 1; // Q14 inLevel = WebRtcSpl_DivW32W16(tmp32, kCompRatio); // Q14 // Calculate diffGain-inLevel, to map using the genFuncTable inLevel = (int32_t)diffGain * (1 << 14) - inLevel; // Q14 // Make calculations on abs(inLevel) and compensate for the sign afterwards. absInLevel = (uint32_t)WEBRTC_SPL_ABS_W32(inLevel); // Q14 // LUT with interpolation intPart = (uint16_t)(absInLevel >> 14); fracPart = (uint16_t)(absInLevel & 0x00003FFF); // extract the fractional part tmpU16 = kGenFuncTable[intPart + 1] - kGenFuncTable[intPart]; // Q8 tmpU32no1 = tmpU16 * fracPart; // Q22 tmpU32no1 += (uint32_t)kGenFuncTable[intPart] << 14; // Q22 logApprox = tmpU32no1 >> 8; // Q14 // Compensate for negative exponent using the relation: // log2(1 + 2^-x) = log2(1 + 2^x) - x if (inLevel < 0) { zeros = WebRtcSpl_NormU32(absInLevel); zerosScale = 0; if (zeros < 15) { // Not enough space for multiplication tmpU32no2 = absInLevel >> (15 - zeros); // Q(zeros-1) tmpU32no2 = WEBRTC_SPL_UMUL_32_16(tmpU32no2, kLogE_1); // Q(zeros+13) if (zeros < 9) { zerosScale = 9 - zeros; tmpU32no1 >>= zerosScale; // Q(zeros+13) } else { tmpU32no2 >>= zeros - 9; // Q22 } } else { tmpU32no2 = WEBRTC_SPL_UMUL_32_16(absInLevel, kLogE_1); // Q28 tmpU32no2 >>= 6; // Q22 } logApprox = 0; if (tmpU32no2 < tmpU32no1) { logApprox = (tmpU32no1 - tmpU32no2) >> (8 - zerosScale); // Q14 } } numFIX = (maxGain * constMaxGain) * (1 << 6); // Q14 numFIX -= (int32_t)logApprox * diffGain; // Q14 // Calculate ratio // Shift |numFIX| as much as possible. // Ensure we avoid wrap-around in |den| as well. if (numFIX > (den >> 8) || -numFIX > (den >> 8)) { // |den| is Q8. zeros = WebRtcSpl_NormW32(numFIX); } else { zeros = WebRtcSpl_NormW32(den) + 8; } numFIX *= 1 << zeros; // Q(14+zeros) // Shift den so we end up in Qy1 tmp32no1 = WEBRTC_SPL_SHIFT_W32(den, zeros - 9); // Q(zeros - 1) y32 = numFIX / tmp32no1; // in Q15 // This is to do rounding in Q14. y32 = y32 >= 0 ? (y32 + 1) >> 1 : -((-y32 + 1) >> 1); if (limiterEnable && (i < limiterIdx)) { tmp32 = WEBRTC_SPL_MUL_16_U16(i - 1, kLog10_2); // Q14 tmp32 -= limiterLvl * (1 << 14); // Q14 y32 = WebRtcSpl_DivW32W16(tmp32 + 10, 20); } if (y32 > 39000) { tmp32 = (y32 >> 1) * kLog10 + 4096; // in Q27 tmp32 >>= 13; // In Q14. } else { tmp32 = y32 * kLog10 + 8192; // in Q28 tmp32 >>= 14; // In Q14. } tmp32 += 16 << 14; // in Q14 (Make sure final output is in Q16) // Calculate power if (tmp32 > 0) { intPart = (int16_t)(tmp32 >> 14); fracPart = (uint16_t)(tmp32 & 0x00003FFF); // in Q14 if ((fracPart >> 13) != 0) { tmp16 = (2 << 14) - constLinApprox; tmp32no2 = (1 << 14) - fracPart; tmp32no2 *= tmp16; tmp32no2 >>= 13; tmp32no2 = (1 << 14) - tmp32no2; } else { tmp16 = constLinApprox - (1 << 14); tmp32no2 = (fracPart * tmp16) >> 13; } fracPart = (uint16_t)tmp32no2; gainTable[i] = (1 << intPart) + WEBRTC_SPL_SHIFT_W32(fracPart, intPart - 14); } else { gainTable[i] = 0; } } return 0; } int32_t WebRtcAgc_InitDigital(DigitalAgc* stt, int16_t agcMode) { if (agcMode == kAgcModeFixedDigital) { // start at minimum to find correct gain faster stt->capacitorSlow = 0; } else { // start out with 0 dB gain stt->capacitorSlow = 134217728; // (int32_t)(0.125f * 32768.0f * 32768.0f); } stt->capacitorFast = 0; stt->gain = 65536; stt->gatePrevious = 0; stt->agcMode = agcMode; // initialize VADs WebRtcAgc_InitVad(&stt->vadNearend); WebRtcAgc_InitVad(&stt->vadFarend); return 0; } int32_t WebRtcAgc_AddFarendToDigital(DigitalAgc* stt, const int16_t* in_far, size_t nrSamples) { RTC_DCHECK(stt); // VAD for far end WebRtcAgc_ProcessVad(&stt->vadFarend, in_far, nrSamples); return 0; } // Gains is an 11 element long array (one value per ms, incl start & end). int32_t WebRtcAgc_ComputeDigitalGains(DigitalAgc* stt, const int16_t* const* in_near, size_t num_bands, uint32_t FS, int16_t lowlevelSignal, int32_t gains[11]) { int32_t tmp32; int32_t env[10]; int32_t max_nrg; int32_t cur_level; int32_t gain32; int16_t logratio; int16_t lower_thr, upper_thr; int16_t zeros = 0, zeros_fast, frac = 0; int16_t decay; int16_t gate, gain_adj; int16_t k; size_t n, L; int16_t L2; // samples/subframe // determine number of samples per ms if (FS == 8000) { L = 8; L2 = 3; } else if (FS == 16000 || FS == 32000 || FS == 48000) { L = 16; L2 = 4; } else { return -1; } // VAD for near end logratio = WebRtcAgc_ProcessVad(&stt->vadNearend, in_near[0], L * 10); // Account for far end VAD if (stt->vadFarend.counter > 10) { tmp32 = 3 * logratio; logratio = (int16_t)((tmp32 - stt->vadFarend.logRatio) >> 2); } // Determine decay factor depending on VAD // upper_thr = 1.0f; // lower_thr = 0.25f; upper_thr = 1024; // Q10 lower_thr = 0; // Q10 if (logratio > upper_thr) { // decay = -2^17 / DecayTime; -> -65 decay = -65; } else if (logratio < lower_thr) { decay = 0; } else { // decay = (int16_t)(((lower_thr - logratio) // * (2^27/(DecayTime*(upper_thr-lower_thr)))) >> 10); // SUBSTITUTED: 2^27/(DecayTime*(upper_thr-lower_thr)) -> 65 tmp32 = (lower_thr - logratio) * 65; decay = (int16_t)(tmp32 >> 10); } // adjust decay factor for long silence (detected as low standard deviation) // This is only done in the adaptive modes if (stt->agcMode != kAgcModeFixedDigital) { if (stt->vadNearend.stdLongTerm < 4000) { decay = 0; } else if (stt->vadNearend.stdLongTerm < 8096) { // decay = (int16_t)(((stt->vadNearend.stdLongTerm - 4000) * decay) >> // 12); tmp32 = (stt->vadNearend.stdLongTerm - 4000) * decay; decay = (int16_t)(tmp32 >> 12); } if (lowlevelSignal != 0) { decay = 0; } } // Find max amplitude per sub frame // iterate over sub frames for (k = 0; k < 10; k++) { // iterate over samples max_nrg = 0; for (n = 0; n < L; n++) { int32_t nrg = in_near[0][k * L + n] * in_near[0][k * L + n]; if (nrg > max_nrg) { max_nrg = nrg; } } env[k] = max_nrg; } // Calculate gain per sub frame gains[0] = stt->gain; for (k = 0; k < 10; k++) { // Fast envelope follower // decay time = -131000 / -1000 = 131 (ms) stt->capacitorFast = AGC_SCALEDIFF32(-1000, stt->capacitorFast, stt->capacitorFast); if (env[k] > stt->capacitorFast) { stt->capacitorFast = env[k]; } // Slow envelope follower if (env[k] > stt->capacitorSlow) { // increase capacitorSlow stt->capacitorSlow = AGC_SCALEDIFF32(500, (env[k] - stt->capacitorSlow), stt->capacitorSlow); } else { // decrease capacitorSlow stt->capacitorSlow = AGC_SCALEDIFF32(decay, stt->capacitorSlow, stt->capacitorSlow); } // use maximum of both capacitors as current level if (stt->capacitorFast > stt->capacitorSlow) { cur_level = stt->capacitorFast; } else { cur_level = stt->capacitorSlow; } // Translate signal level into gain, using a piecewise linear approximation // find number of leading zeros zeros = WebRtcSpl_NormU32((uint32_t)cur_level); if (cur_level == 0) { zeros = 31; } tmp32 = ((uint32_t)cur_level << zeros) & 0x7FFFFFFF; frac = (int16_t)(tmp32 >> 19); // Q12. // Interpolate between gainTable[zeros] and gainTable[zeros-1]. tmp32 = ((stt->gainTable[zeros - 1] - stt->gainTable[zeros]) * (int64_t)frac) >> 12; gains[k + 1] = stt->gainTable[zeros] + tmp32; } // Gate processing (lower gain during absence of speech) zeros = (zeros << 9) - (frac >> 3); // find number of leading zeros zeros_fast = WebRtcSpl_NormU32((uint32_t)stt->capacitorFast); if (stt->capacitorFast == 0) { zeros_fast = 31; } tmp32 = ((uint32_t)stt->capacitorFast << zeros_fast) & 0x7FFFFFFF; zeros_fast <<= 9; zeros_fast -= (int16_t)(tmp32 >> 22); gate = 1000 + zeros_fast - zeros - stt->vadNearend.stdShortTerm; if (gate < 0) { stt->gatePrevious = 0; } else { tmp32 = stt->gatePrevious * 7; gate = (int16_t)((gate + tmp32) >> 3); stt->gatePrevious = gate; } // gate < 0 -> no gate // gate > 2500 -> max gate if (gate > 0) { if (gate < 2500) { gain_adj = (2500 - gate) >> 5; } else { gain_adj = 0; } for (k = 0; k < 10; k++) { if ((gains[k + 1] - stt->gainTable[0]) > 8388608) { // To prevent wraparound tmp32 = (gains[k + 1] - stt->gainTable[0]) >> 8; tmp32 *= 178 + gain_adj; } else { tmp32 = (gains[k + 1] - stt->gainTable[0]) * (178 + gain_adj); tmp32 >>= 8; } gains[k + 1] = stt->gainTable[0] + tmp32; } } // Limit gain to avoid overload distortion for (k = 0; k < 10; k++) { // Find a shift of gains[k + 1] such that it can be squared without // overflow, but at least by 10 bits. zeros = 10; if (gains[k + 1] > 47452159) { zeros = 16 - WebRtcSpl_NormW32(gains[k + 1]); } gain32 = (gains[k + 1] >> zeros) + 1; gain32 *= gain32; // check for overflow while (AGC_MUL32((env[k] >> 12) + 1, gain32) > WEBRTC_SPL_SHIFT_W32((int32_t)32767, 2 * (1 - zeros + 10))) { // multiply by 253/256 ==> -0.1 dB if (gains[k + 1] > 8388607) { // Prevent wrap around gains[k + 1] = (gains[k + 1] / 256) * 253; } else { gains[k + 1] = (gains[k + 1] * 253) / 256; } gain32 = (gains[k + 1] >> zeros) + 1; gain32 *= gain32; } } // gain reductions should be done 1 ms earlier than gain increases for (k = 1; k < 10; k++) { if (gains[k] > gains[k + 1]) { gains[k] = gains[k + 1]; } } // save start gain for next frame stt->gain = gains[10]; return 0; } int32_t WebRtcAgc_ApplyDigitalGains(const int32_t gains[11], size_t num_bands, uint32_t FS, const int16_t* const* in_near, int16_t* const* out) { // Apply gain // handle first sub frame separately size_t L; int16_t L2; // samples/subframe // determine number of samples per ms if (FS == 8000) { L = 8; L2 = 3; } else if (FS == 16000 || FS == 32000 || FS == 48000) { L = 16; L2 = 4; } else { return -1; } for (size_t i = 0; i < num_bands; ++i) { if (in_near[i] != out[i]) { // Only needed if they don't already point to the same place. memcpy(out[i], in_near[i], 10 * L * sizeof(in_near[i][0])); } } // iterate over samples int32_t delta = (gains[1] - gains[0]) * (1 << (4 - L2)); int32_t gain32 = gains[0] * (1 << 4); for (size_t n = 0; n < L; n++) { for (size_t i = 0; i < num_bands; ++i) { int32_t out_tmp = (int64_t)out[i][n] * ((gain32 + 127) >> 7) >> 16; if (out_tmp > 4095) { out[i][n] = (int16_t)32767; } else if (out_tmp < -4096) { out[i][n] = (int16_t)-32768; } else { int32_t tmp32 = ((int64_t)out[i][n] * (gain32 >> 4)) >> 16; out[i][n] = (int16_t)tmp32; } } gain32 += delta; } // iterate over subframes for (int k = 1; k < 10; k++) { delta = (gains[k + 1] - gains[k]) * (1 << (4 - L2)); gain32 = gains[k] * (1 << 4); // iterate over samples for (size_t n = 0; n < L; n++) { for (size_t i = 0; i < num_bands; ++i) { int64_t tmp64 = ((int64_t)(out[i][k * L + n])) * (gain32 >> 4); tmp64 = tmp64 >> 16; if (tmp64 > 32767) { out[i][k * L + n] = 32767; } else if (tmp64 < -32768) { out[i][k * L + n] = -32768; } else { out[i][k * L + n] = (int16_t)(tmp64); } } gain32 += delta; } } return 0; } void WebRtcAgc_InitVad(AgcVad* state) { int16_t k; state->HPstate = 0; // state of high pass filter state->logRatio = 0; // log( P(active) / P(inactive) ) // average input level (Q10) state->meanLongTerm = 15 << 10; // variance of input level (Q8) state->varianceLongTerm = 500 << 8; state->stdLongTerm = 0; // standard deviation of input level in dB // short-term average input level (Q10) state->meanShortTerm = 15 << 10; // short-term variance of input level (Q8) state->varianceShortTerm = 500 << 8; state->stdShortTerm = 0; // short-term standard deviation of input level in dB state->counter = 3; // counts updates for (k = 0; k < 8; k++) { // downsampling filter state->downState[k] = 0; } } int16_t WebRtcAgc_ProcessVad(AgcVad* state, // (i) VAD state const int16_t* in, // (i) Speech signal size_t nrSamples) { // (i) number of samples uint32_t nrg; int32_t out, tmp32, tmp32b; uint16_t tmpU16; int16_t k, subfr, tmp16; int16_t buf1[8]; int16_t buf2[4]; int16_t HPstate; int16_t zeros, dB; int64_t tmp64; // process in 10 sub frames of 1 ms (to save on memory) nrg = 0; HPstate = state->HPstate; for (subfr = 0; subfr < 10; subfr++) { // downsample to 4 kHz if (nrSamples == 160) { for (k = 0; k < 8; k++) { tmp32 = (int32_t)in[2 * k] + (int32_t)in[2 * k + 1]; tmp32 >>= 1; buf1[k] = (int16_t)tmp32; } in += 16; WebRtcSpl_DownsampleBy2(buf1, 8, buf2, state->downState); } else { WebRtcSpl_DownsampleBy2(in, 8, buf2, state->downState); in += 8; } // high pass filter and compute energy for (k = 0; k < 4; k++) { out = buf2[k] + HPstate; tmp32 = 600 * out; HPstate = (int16_t)((tmp32 >> 10) - buf2[k]); // Add 'out * out / 2**6' to 'nrg' in a non-overflowing // way. Guaranteed to work as long as 'out * out / 2**6' fits in // an int32_t. nrg += out * (out / (1 << 6)); nrg += out * (out % (1 << 6)) / (1 << 6); } } state->HPstate = HPstate; // find number of leading zeros if (!(0xFFFF0000 & nrg)) { zeros = 16; } else { zeros = 0; } if (!(0xFF000000 & (nrg << zeros))) { zeros += 8; } if (!(0xF0000000 & (nrg << zeros))) { zeros += 4; } if (!(0xC0000000 & (nrg << zeros))) { zeros += 2; } if (!(0x80000000 & (nrg << zeros))) { zeros += 1; } // energy level (range {-32..30}) (Q10) dB = (15 - zeros) * (1 << 11); // Update statistics if (state->counter < kAvgDecayTime) { // decay time = AvgDecTime * 10 ms state->counter++; } // update short-term estimate of mean energy level (Q10) tmp32 = state->meanShortTerm * 15 + dB; state->meanShortTerm = (int16_t)(tmp32 >> 4); // update short-term estimate of variance in energy level (Q8) tmp32 = (dB * dB) >> 12; tmp32 += state->varianceShortTerm * 15; state->varianceShortTerm = tmp32 / 16; // update short-term estimate of standard deviation in energy level (Q10) tmp32 = state->meanShortTerm * state->meanShortTerm; tmp32 = (state->varianceShortTerm << 12) - tmp32; state->stdShortTerm = (int16_t)WebRtcSpl_Sqrt(tmp32); // update long-term estimate of mean energy level (Q10) tmp32 = state->meanLongTerm * state->counter + dB; state->meanLongTerm = WebRtcSpl_DivW32W16ResW16(tmp32, WebRtcSpl_AddSatW16(state->counter, 1)); // update long-term estimate of variance in energy level (Q8) tmp32 = (dB * dB) >> 12; tmp32 += state->varianceLongTerm * state->counter; state->varianceLongTerm = WebRtcSpl_DivW32W16(tmp32, WebRtcSpl_AddSatW16(state->counter, 1)); // update long-term estimate of standard deviation in energy level (Q10) tmp32 = state->meanLongTerm * state->meanLongTerm; tmp32 = (state->varianceLongTerm << 12) - tmp32; state->stdLongTerm = (int16_t)WebRtcSpl_Sqrt(tmp32); // update voice activity measure (Q10) tmp16 = 3 << 12; // TODO(bjornv): (dB - state->meanLongTerm) can overflow, e.g., in // ApmTest.Process unit test. Previously the macro WEBRTC_SPL_MUL_16_16() // was used, which did an intermediate cast to (int16_t), hence losing // significant bits. This cause logRatio to max out positive, rather than // negative. This is a bug, but has very little significance. tmp32 = tmp16 * (int16_t)(dB - state->meanLongTerm); tmp32 = WebRtcSpl_DivW32W16(tmp32, state->stdLongTerm); tmpU16 = (13 << 12); tmp32b = WEBRTC_SPL_MUL_16_U16(state->logRatio, tmpU16); tmp64 = tmp32; tmp64 += tmp32b >> 10; tmp64 >>= 6; // limit if (tmp64 > 2048) { tmp64 = 2048; } else if (tmp64 < -2048) { tmp64 = -2048; } state->logRatio = (int16_t)tmp64; return state->logRatio; // Q10 } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc/legacy/digital_agc.h0000664000175000017500000000545314475643423027566 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC_LEGACY_DIGITAL_AGC_H_ #define MODULES_AUDIO_PROCESSING_AGC_LEGACY_DIGITAL_AGC_H_ #include "common_audio/signal_processing/include/signal_processing_library.h" namespace webrtc { typedef struct { int32_t downState[8]; int16_t HPstate; int16_t counter; int16_t logRatio; // log( P(active) / P(inactive) ) (Q10) int16_t meanLongTerm; // Q10 int32_t varianceLongTerm; // Q8 int16_t stdLongTerm; // Q10 int16_t meanShortTerm; // Q10 int32_t varianceShortTerm; // Q8 int16_t stdShortTerm; // Q10 } AgcVad; // total = 54 bytes typedef struct { int32_t capacitorSlow; int32_t capacitorFast; int32_t gain; int32_t gainTable[32]; int16_t gatePrevious; int16_t agcMode; AgcVad vadNearend; AgcVad vadFarend; } DigitalAgc; int32_t WebRtcAgc_InitDigital(DigitalAgc* digitalAgcInst, int16_t agcMode); int32_t WebRtcAgc_ComputeDigitalGains(DigitalAgc* digitalAgcInst, const int16_t* const* inNear, size_t num_bands, uint32_t FS, int16_t lowLevelSignal, int32_t gains[11]); int32_t WebRtcAgc_ApplyDigitalGains(const int32_t gains[11], size_t num_bands, uint32_t FS, const int16_t* const* in_near, int16_t* const* out); int32_t WebRtcAgc_AddFarendToDigital(DigitalAgc* digitalAgcInst, const int16_t* inFar, size_t nrSamples); void WebRtcAgc_InitVad(AgcVad* vadInst); int16_t WebRtcAgc_ProcessVad(AgcVad* vadInst, // (i) VAD state const int16_t* in, // (i) Speech signal size_t nrSamples); // (i) number of samples int32_t WebRtcAgc_CalculateGainTable(int32_t* gainTable, // Q16 int16_t compressionGaindB, // Q0 (in dB) int16_t targetLevelDbfs, // Q0 (in dB) uint8_t limiterEnable, int16_t analogTarget); } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC_LEGACY_DIGITAL_AGC_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc/legacy/gain_control.h0000664000175000017500000002164314475643423030014 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC_LEGACY_GAIN_CONTROL_H_ #define MODULES_AUDIO_PROCESSING_AGC_LEGACY_GAIN_CONTROL_H_ namespace webrtc { enum { kAgcModeUnchanged, kAgcModeAdaptiveAnalog, kAgcModeAdaptiveDigital, kAgcModeFixedDigital }; enum { kAgcFalse = 0, kAgcTrue }; typedef struct { int16_t targetLevelDbfs; // default 3 (-3 dBOv) int16_t compressionGaindB; // default 9 dB uint8_t limiterEnable; // default kAgcTrue (on) } WebRtcAgcConfig; /* * This function analyses the number of samples passed to * farend and produces any error code that could arise. * * Input: * - agcInst : AGC instance. * - samples : Number of samples in input vector. * * Return value: * : 0 - Normal operation. * : -1 - Error. */ int WebRtcAgc_GetAddFarendError(void* state, size_t samples); /* * This function processes a 10 ms frame of far-end speech to determine * if there is active speech. The length of the input speech vector must be * given in samples (80 when FS=8000, and 160 when FS=16000, FS=32000 or * FS=48000). * * Input: * - agcInst : AGC instance. * - inFar : Far-end input speech vector * - samples : Number of samples in input vector * * Return value: * : 0 - Normal operation. * : -1 - Error */ int WebRtcAgc_AddFarend(void* agcInst, const int16_t* inFar, size_t samples); /* * This function processes a 10 ms frame of microphone speech to determine * if there is active speech. The length of the input speech vector must be * given in samples (80 when FS=8000, and 160 when FS=16000, FS=32000 or * FS=48000). For very low input levels, the input signal is increased in level * by multiplying and overwriting the samples in inMic[]. * * This function should be called before any further processing of the * near-end microphone signal. * * Input: * - agcInst : AGC instance. * - inMic : Microphone input speech vector for each band * - num_bands : Number of bands in input vector * - samples : Number of samples in input vector * * Return value: * : 0 - Normal operation. * : -1 - Error */ int WebRtcAgc_AddMic(void* agcInst, int16_t* const* inMic, size_t num_bands, size_t samples); /* * This function replaces the analog microphone with a virtual one. * It is a digital gain applied to the input signal and is used in the * agcAdaptiveDigital mode where no microphone level is adjustable. The length * of the input speech vector must be given in samples (80 when FS=8000, and 160 * when FS=16000, FS=32000 or FS=48000). * * Input: * - agcInst : AGC instance. * - inMic : Microphone input speech vector for each band * - num_bands : Number of bands in input vector * - samples : Number of samples in input vector * - micLevelIn : Input level of microphone (static) * * Output: * - inMic : Microphone output after processing (L band) * - inMic_H : Microphone output after processing (H band) * - micLevelOut : Adjusted microphone level after processing * * Return value: * : 0 - Normal operation. * : -1 - Error */ int WebRtcAgc_VirtualMic(void* agcInst, int16_t* const* inMic, size_t num_bands, size_t samples, int32_t micLevelIn, int32_t* micLevelOut); /* * This function analyses a 10 ms frame and produces the analog and digital * gains required to normalize the signal. The gain adjustments are done only * during active periods of speech. The length of the speech vectors must be * given in samples (80 when FS=8000, and 160 when FS=16000, FS=32000 or * FS=48000). The echo parameter can be used to ensure the AGC will not adjust * upward in the presence of echo. * * This function should be called after processing the near-end microphone * signal, in any case after any echo cancellation. * * Input: * - agcInst : AGC instance * - inNear : Near-end input speech vector for each band * - num_bands : Number of bands in input/output vector * - samples : Number of samples in input/output vector * - inMicLevel : Current microphone volume level * - echo : Set to 0 if the signal passed to add_mic is * almost certainly free of echo; otherwise set * to 1. If you have no information regarding echo * set to 0. * * Output: * - outMicLevel : Adjusted microphone volume level * - saturationWarning : A returned value of 1 indicates a saturation event * has occurred and the volume cannot be further * reduced. Otherwise will be set to 0. * - gains : Vector of gains to apply for digital normalization * * Return value: * : 0 - Normal operation. * : -1 - Error */ int WebRtcAgc_Analyze(void* agcInst, const int16_t* const* inNear, size_t num_bands, size_t samples, int32_t inMicLevel, int32_t* outMicLevel, int16_t echo, uint8_t* saturationWarning, int32_t gains[11]); /* * This function processes a 10 ms frame by applying precomputed digital gains. * * Input: * - agcInst : AGC instance * - gains : Vector of gains to apply for digital normalization * - in_near : Near-end input speech vector for each band * - num_bands : Number of bands in input/output vector * * Output: * - out : Gain-adjusted near-end speech vector * : May be the same vector as the input. * * Return value: * : 0 - Normal operation. * : -1 - Error */ int WebRtcAgc_Process(const void* agcInst, const int32_t gains[11], const int16_t* const* in_near, size_t num_bands, int16_t* const* out); /* * This function sets the config parameters (targetLevelDbfs, * compressionGaindB and limiterEnable). * * Input: * - agcInst : AGC instance * - config : config struct * * Output: * * Return value: * : 0 - Normal operation. * : -1 - Error */ int WebRtcAgc_set_config(void* agcInst, WebRtcAgcConfig config); /* * This function returns the config parameters (targetLevelDbfs, * compressionGaindB and limiterEnable). * * Input: * - agcInst : AGC instance * * Output: * - config : config struct * * Return value: * : 0 - Normal operation. * : -1 - Error */ int WebRtcAgc_get_config(void* agcInst, WebRtcAgcConfig* config); /* * This function creates and returns an AGC instance, which will contain the * state information for one (duplex) channel. */ void* WebRtcAgc_Create(void); /* * This function frees the AGC instance created at the beginning. * * Input: * - agcInst : AGC instance. */ void WebRtcAgc_Free(void* agcInst); /* * This function initializes an AGC instance. * * Input: * - agcInst : AGC instance. * - minLevel : Minimum possible mic level * - maxLevel : Maximum possible mic level * - agcMode : 0 - Unchanged * : 1 - Adaptive Analog Automatic Gain Control -3dBOv * : 2 - Adaptive Digital Automatic Gain Control -3dBOv * : 3 - Fixed Digital Gain 0dB * - fs : Sampling frequency * * Return value : 0 - Ok * -1 - Error */ int WebRtcAgc_Init(void* agcInst, int32_t minLevel, int32_t maxLevel, int16_t agcMode, uint32_t fs); } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC_LEGACY_GAIN_CONTROL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc/loudness_histogram.cc0000664000175000017500000002005014475643423030130 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc/loudness_histogram.h" #include #include #include "rtc_base/checks.h" namespace webrtc { static const double kHistBinCenters[] = { 7.59621091765857e-02, 9.02036021061016e-02, 1.07115112009343e-01, 1.27197217770508e-01, 1.51044347572047e-01, 1.79362373905283e-01, 2.12989507320644e-01, 2.52921107370304e-01, 3.00339145144454e-01, 3.56647189489147e-01, 4.23511952494003e-01, 5.02912623991786e-01, 5.97199455365749e-01, 7.09163326739184e-01, 8.42118356728544e-01, 1.00000000000000e+00, 1.18748153630660e+00, 1.41011239906908e+00, 1.67448243801153e+00, 1.98841697800836e+00, 2.36120844786349e+00, 2.80389143520905e+00, 3.32956930911896e+00, 3.95380207843188e+00, 4.69506696634852e+00, 5.57530533426190e+00, 6.62057214370769e+00, 7.86180718043869e+00, 9.33575086877358e+00, 1.10860317842269e+01, 1.31644580546776e+01, 1.56325508754123e+01, 1.85633655299256e+01, 2.20436538184971e+01, 2.61764319021997e+01, 3.10840295702492e+01, 3.69117111886792e+01, 4.38319755100383e+01, 5.20496616180135e+01, 6.18080121423973e+01, 7.33958732149108e+01, 8.71562442838066e+01, 1.03496430860848e+02, 1.22900100720889e+02, 1.45941600416277e+02, 1.73302955873365e+02, 2.05794060286978e+02, 2.44376646872353e+02, 2.90192756065437e+02, 3.44598539797631e+02, 4.09204403447902e+02, 4.85922673669740e+02, 5.77024203055553e+02, 6.85205587130498e+02, 8.13668983291589e+02, 9.66216894324125e+02, 1.14736472207740e+03, 1.36247442287647e+03, 1.61791322085579e+03, 1.92124207711260e+03, 2.28143949334655e+03, 2.70916727454970e+03, 3.21708611729384e+03, 3.82023036499473e+03, 4.53645302286906e+03, 5.38695420497926e+03, 6.39690865534207e+03, 7.59621091765857e+03, 9.02036021061016e+03, 1.07115112009343e+04, 1.27197217770508e+04, 1.51044347572047e+04, 1.79362373905283e+04, 2.12989507320644e+04, 2.52921107370304e+04, 3.00339145144454e+04, 3.56647189489147e+04}; static const double kProbQDomain = 1024.0; // Loudness of -15 dB (smallest expected loudness) in log domain, // loudness_db = 13.5 * log10(rms); static const double kLogDomainMinBinCenter = -2.57752062648587; // Loudness step of 1 dB in log domain static const double kLogDomainStepSizeInverse = 5.81954605750359; static const int kTransientWidthThreshold = 7; static const double kLowProbabilityThreshold = 0.2; static const int kLowProbThresholdQ10 = static_cast(kLowProbabilityThreshold * kProbQDomain); LoudnessHistogram::LoudnessHistogram() : num_updates_(0), audio_content_q10_(0), bin_count_q10_(), activity_probability_(), hist_bin_index_(), buffer_index_(0), buffer_is_full_(false), len_circular_buffer_(0), len_high_activity_(0) { static_assert( kHistSize == sizeof(kHistBinCenters) / sizeof(kHistBinCenters[0]), "histogram bin centers incorrect size"); } LoudnessHistogram::LoudnessHistogram(int window_size) : num_updates_(0), audio_content_q10_(0), bin_count_q10_(), activity_probability_(new int[window_size]), hist_bin_index_(new int[window_size]), buffer_index_(0), buffer_is_full_(false), len_circular_buffer_(window_size), len_high_activity_(0) {} LoudnessHistogram::~LoudnessHistogram() {} void LoudnessHistogram::Update(double rms, double activity_probaility) { // If circular histogram is activated then remove the oldest entry. if (len_circular_buffer_ > 0) RemoveOldestEntryAndUpdate(); // Find the corresponding bin. int hist_index = GetBinIndex(rms); // To Q10 domain. int prob_q10 = static_cast(floor(activity_probaility * kProbQDomain)); InsertNewestEntryAndUpdate(prob_q10, hist_index); } // Doing nothing if buffer is not full, yet. void LoudnessHistogram::RemoveOldestEntryAndUpdate() { RTC_DCHECK_GT(len_circular_buffer_, 0); // Do nothing if circular buffer is not full. if (!buffer_is_full_) return; int oldest_prob = activity_probability_[buffer_index_]; int oldest_hist_index = hist_bin_index_[buffer_index_]; UpdateHist(-oldest_prob, oldest_hist_index); } void LoudnessHistogram::RemoveTransient() { // Don't expect to be here if high-activity region is longer than // |kTransientWidthThreshold| or there has not been any transient. RTC_DCHECK_LE(len_high_activity_, kTransientWidthThreshold); int index = (buffer_index_ > 0) ? (buffer_index_ - 1) : len_circular_buffer_ - 1; while (len_high_activity_ > 0) { UpdateHist(-activity_probability_[index], hist_bin_index_[index]); activity_probability_[index] = 0; index = (index > 0) ? (index - 1) : (len_circular_buffer_ - 1); len_high_activity_--; } } void LoudnessHistogram::InsertNewestEntryAndUpdate(int activity_prob_q10, int hist_index) { // Update the circular buffer if it is enabled. if (len_circular_buffer_ > 0) { // Removing transient. if (activity_prob_q10 <= kLowProbThresholdQ10) { // Lower than threshold probability, set it to zero. activity_prob_q10 = 0; // Check if this has been a transient. if (len_high_activity_ <= kTransientWidthThreshold) RemoveTransient(); // Remove this transient. len_high_activity_ = 0; } else if (len_high_activity_ <= kTransientWidthThreshold) { len_high_activity_++; } // Updating the circular buffer. activity_probability_[buffer_index_] = activity_prob_q10; hist_bin_index_[buffer_index_] = hist_index; // Increment the buffer index and check for wrap-around. buffer_index_++; if (buffer_index_ >= len_circular_buffer_) { buffer_index_ = 0; buffer_is_full_ = true; } } num_updates_++; if (num_updates_ < 0) num_updates_--; UpdateHist(activity_prob_q10, hist_index); } void LoudnessHistogram::UpdateHist(int activity_prob_q10, int hist_index) { bin_count_q10_[hist_index] += activity_prob_q10; audio_content_q10_ += activity_prob_q10; } double LoudnessHistogram::AudioContent() const { return audio_content_q10_ / kProbQDomain; } LoudnessHistogram* LoudnessHistogram::Create() { return new LoudnessHistogram; } LoudnessHistogram* LoudnessHistogram::Create(int window_size) { if (window_size < 0) return NULL; return new LoudnessHistogram(window_size); } void LoudnessHistogram::Reset() { // Reset the histogram, audio-content and number of updates. memset(bin_count_q10_, 0, sizeof(bin_count_q10_)); audio_content_q10_ = 0; num_updates_ = 0; // Empty the circular buffer. buffer_index_ = 0; buffer_is_full_ = false; len_high_activity_ = 0; } int LoudnessHistogram::GetBinIndex(double rms) { // First exclude overload cases. if (rms <= kHistBinCenters[0]) { return 0; } else if (rms >= kHistBinCenters[kHistSize - 1]) { return kHistSize - 1; } else { // The quantizer is uniform in log domain. Alternatively we could do binary // search in linear domain. double rms_log = log(rms); int index = static_cast( floor((rms_log - kLogDomainMinBinCenter) * kLogDomainStepSizeInverse)); // The final decision is in linear domain. double b = 0.5 * (kHistBinCenters[index] + kHistBinCenters[index + 1]); if (rms > b) { return index + 1; } return index; } } double LoudnessHistogram::CurrentRms() const { double p; double mean_val = 0; if (audio_content_q10_ > 0) { double p_total_inverse = 1. / static_cast(audio_content_q10_); for (int n = 0; n < kHistSize; n++) { p = static_cast(bin_count_q10_[n]) * p_total_inverse; mean_val += p * kHistBinCenters[n]; } } else { mean_val = kHistBinCenters[0]; } return mean_val; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc/loudness_histogram.h0000664000175000017500000000570214475643423030001 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC_LOUDNESS_HISTOGRAM_H_ #define MODULES_AUDIO_PROCESSING_AGC_LOUDNESS_HISTOGRAM_H_ #include #include namespace webrtc { // This class implements the histogram of loudness with circular buffers so that // the histogram tracks the last T seconds of the loudness. class LoudnessHistogram { public: // Create a non-sliding LoudnessHistogram. static LoudnessHistogram* Create(); // Create a sliding LoudnessHistogram, i.e. the histogram represents the last // |window_size| samples. static LoudnessHistogram* Create(int window_size); ~LoudnessHistogram(); // Insert RMS and the corresponding activity probability. void Update(double rms, double activity_probability); // Reset the histogram, forget the past. void Reset(); // Current loudness, which is actually the mean of histogram in loudness // domain. double CurrentRms() const; // Sum of the histogram content. double AudioContent() const; // Number of times the histogram has been updated. int num_updates() const { return num_updates_; } private: LoudnessHistogram(); explicit LoudnessHistogram(int window); // Find the histogram bin associated with the given |rms|. int GetBinIndex(double rms); void RemoveOldestEntryAndUpdate(); void InsertNewestEntryAndUpdate(int activity_prob_q10, int hist_index); void UpdateHist(int activity_prob_q10, int hist_index); void RemoveTransient(); // Number of histogram bins. static const int kHistSize = 77; // Number of times the histogram is updated int num_updates_; // Audio content, this should be equal to the sum of the components of // |bin_count_q10_|. int64_t audio_content_q10_; // LoudnessHistogram of input RMS in Q10 with |kHistSize_| bins. In each // 'Update(),' we increment the associated histogram-bin with the given // probability. The increment is implemented in Q10 to avoid rounding errors. int64_t bin_count_q10_[kHistSize]; // Circular buffer for probabilities std::unique_ptr activity_probability_; // Circular buffer for histogram-indices of probabilities. std::unique_ptr hist_bin_index_; // Current index of circular buffer, where the newest data will be written to, // therefore, pointing to the oldest data if buffer is full. int buffer_index_; // Indicating if buffer is full and we had a wrap around. int buffer_is_full_; // Size of circular buffer. int len_circular_buffer_; int len_high_activity_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC_LOUDNESS_HISTOGRAM_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc/mock_agc.h0000664000175000017500000000214514475643423025631 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC_MOCK_AGC_H_ #define MODULES_AUDIO_PROCESSING_AGC_MOCK_AGC_H_ #include "modules/audio_processing/agc/agc.h" #include "test/gmock.h" namespace webrtc { class MockAgc : public Agc { public: virtual ~MockAgc() {} MOCK_METHOD(void, Process, (const int16_t* audio, size_t length, int sample_rate_hz), (override)); MOCK_METHOD(bool, GetRmsErrorDb, (int* error), (override)); MOCK_METHOD(void, Reset, (), (override)); MOCK_METHOD(int, set_target_level_dbfs, (int level), (override)); MOCK_METHOD(int, target_level_dbfs, (), (const, override)); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC_MOCK_AGC_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc/utility.cc0000664000175000017500000000204714475643423025730 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc/utility.h" #include namespace webrtc { static const double kLog10 = 2.30258509299; static const double kLinear2DbScale = 20.0 / kLog10; static const double kLinear2LoudnessScale = 13.4 / kLog10; double Loudness2Db(double loudness) { return loudness * kLinear2DbScale / kLinear2LoudnessScale; } double Linear2Loudness(double rms) { if (rms == 0) return -15; return kLinear2LoudnessScale * log(rms); } double Db2Loudness(double db) { return db * kLinear2LoudnessScale / kLinear2DbScale; } double Dbfs2Loudness(double dbfs) { return Db2Loudness(90 + dbfs); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc/utility.h0000664000175000017500000000143314475643423025570 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC_UTILITY_H_ #define MODULES_AUDIO_PROCESSING_AGC_UTILITY_H_ namespace webrtc { // TODO(turajs): Add description of function. double Loudness2Db(double loudness); double Linear2Loudness(double rms); double Db2Loudness(double db); double Dbfs2Loudness(double dbfs); } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC_UTILITY_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/0000775000175000017500000000000014475643423023775 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/BUILD.gn0000664000175000017500000001515314475643423025167 0ustar00arunarun# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../../../webrtc.gni") group("agc2") { deps = [ ":adaptive_digital", ":fixed_digital", ] } rtc_library("level_estimation_agc") { sources = [ "adaptive_mode_level_estimator_agc.cc", "adaptive_mode_level_estimator_agc.h", ] configs += [ "..:apm_debug_dump" ] deps = [ ":adaptive_digital", ":common", ":gain_applier", ":noise_level_estimator", ":rnn_vad_with_level", "..:api", "..:apm_logging", "..:audio_frame_view", "../../../api:array_view", "../../../common_audio", "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", "../../../rtc_base:safe_minmax", "../agc:level_estimation", "../vad", ] } rtc_library("adaptive_digital") { sources = [ "adaptive_agc.cc", "adaptive_agc.h", "adaptive_digital_gain_applier.cc", "adaptive_digital_gain_applier.h", "adaptive_mode_level_estimator.cc", "adaptive_mode_level_estimator.h", "saturation_protector.cc", "saturation_protector.h", ] configs += [ "..:apm_debug_dump" ] deps = [ ":common", ":gain_applier", ":noise_level_estimator", ":rnn_vad_with_level", "..:api", "..:apm_logging", "..:audio_frame_view", "../../../api:array_view", "../../../common_audio", "../../../rtc_base:checks", "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", "../../../rtc_base:safe_compare", "../../../rtc_base:safe_minmax", "../../../system_wrappers:metrics", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("biquad_filter") { visibility = [ "./*" ] sources = [ "biquad_filter.cc", "biquad_filter.h", ] deps = [ "../../../api:array_view", "../../../rtc_base:rtc_base_approved", ] } rtc_source_set("common") { sources = [ "agc2_common.h" ] } rtc_library("fixed_digital") { sources = [ "fixed_digital_level_estimator.cc", "fixed_digital_level_estimator.h", "interpolated_gain_curve.cc", "interpolated_gain_curve.h", "limiter.cc", "limiter.h", ] configs += [ "..:apm_debug_dump" ] deps = [ ":common", "..:apm_logging", "..:audio_frame_view", "../../../api:array_view", "../../../common_audio", "../../../rtc_base:checks", "../../../rtc_base:gtest_prod", "../../../rtc_base:rtc_base_approved", "../../../rtc_base:safe_minmax", "../../../system_wrappers:metrics", ] } rtc_library("gain_applier") { sources = [ "gain_applier.cc", "gain_applier.h", ] deps = [ ":common", "..:audio_frame_view", "../../../api:array_view", "../../../rtc_base:safe_minmax", ] } rtc_library("noise_level_estimator") { sources = [ "down_sampler.cc", "down_sampler.h", "noise_level_estimator.cc", "noise_level_estimator.h", "noise_spectrum_estimator.cc", "noise_spectrum_estimator.h", "signal_classifier.cc", "signal_classifier.h", ] deps = [ ":biquad_filter", "..:apm_logging", "..:audio_frame_view", "../../../api:array_view", "../../../common_audio", "../../../common_audio/third_party/ooura:fft_size_128", "../../../rtc_base:checks", "../../../rtc_base:macromagic", "../../../system_wrappers", ] configs += [ "..:apm_debug_dump" ] } rtc_library("rnn_vad_with_level") { sources = [ "vad_with_level.cc", "vad_with_level.h", ] deps = [ ":common", "..:audio_frame_view", "../../../api:array_view", "../../../common_audio", "../../../rtc_base:checks", "rnn_vad", "rnn_vad:rnn_vad_common", ] } rtc_library("adaptive_digital_unittests") { testonly = true configs += [ "..:apm_debug_dump" ] sources = [ "adaptive_digital_gain_applier_unittest.cc", "adaptive_mode_level_estimator_unittest.cc", "gain_applier_unittest.cc", "saturation_protector_unittest.cc", ] deps = [ ":adaptive_digital", ":common", ":gain_applier", ":test_utils", "..:apm_logging", "..:audio_frame_view", "../../../api:array_view", "../../../common_audio", "../../../rtc_base:checks", "../../../rtc_base:gunit_helpers", "../../../rtc_base:rtc_base_approved", "../../../test:test_support", ] } rtc_library("biquad_filter_unittests") { testonly = true sources = [ "biquad_filter_unittest.cc" ] deps = [ ":biquad_filter", "../../../rtc_base:gunit_helpers", ] } rtc_library("fixed_digital_unittests") { testonly = true configs += [ "..:apm_debug_dump" ] sources = [ "agc2_testing_common_unittest.cc", "compute_interpolated_gain_curve.cc", "compute_interpolated_gain_curve.h", "fixed_digital_level_estimator_unittest.cc", "interpolated_gain_curve_unittest.cc", "limiter_db_gain_curve.cc", "limiter_db_gain_curve.h", "limiter_db_gain_curve_unittest.cc", "limiter_unittest.cc", ] deps = [ ":common", ":fixed_digital", ":test_utils", "..:apm_logging", "..:audio_frame_view", "../../../api:array_view", "../../../common_audio", "../../../rtc_base:checks", "../../../rtc_base:gunit_helpers", "../../../rtc_base:rtc_base_approved", "../../../system_wrappers:metrics", ] } rtc_library("noise_estimator_unittests") { testonly = true configs += [ "..:apm_debug_dump" ] sources = [ "noise_level_estimator_unittest.cc", "signal_classifier_unittest.cc", ] deps = [ ":noise_level_estimator", ":test_utils", "..:apm_logging", "..:audio_frame_view", "../../../api:array_view", "../../../rtc_base:checks", "../../../rtc_base:gunit_helpers", "../../../rtc_base:rtc_base_approved", ] } rtc_library("rnn_vad_with_level_unittests") { testonly = true sources = [ "vad_with_level_unittest.cc" ] deps = [ ":common", ":rnn_vad_with_level", "..:audio_frame_view", "../../../rtc_base:gunit_helpers", "../../../rtc_base:safe_compare", "../../../test:test_support", ] } rtc_library("test_utils") { testonly = true visibility = [ ":*", "..:audio_processing_unittests", ] sources = [ "agc2_testing_common.cc", "agc2_testing_common.h", "vector_float_frame.cc", "vector_float_frame.h", ] deps = [ "..:audio_frame_view", "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/adaptive_agc.cc0000664000175000017500000000702414475643423026716 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/adaptive_agc.h" #include "common_audio/include/audio_util.h" #include "modules/audio_processing/agc2/vad_with_level.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" namespace webrtc { namespace { void DumpDebugData(const AdaptiveDigitalGainApplier::FrameInfo& info, ApmDataDumper& dumper) { dumper.DumpRaw("agc2_vad_probability", info.vad_result.speech_probability); dumper.DumpRaw("agc2_vad_rms_dbfs", info.vad_result.rms_dbfs); dumper.DumpRaw("agc2_vad_peak_dbfs", info.vad_result.peak_dbfs); dumper.DumpRaw("agc2_noise_estimate_dbfs", info.input_noise_level_dbfs); dumper.DumpRaw("agc2_last_limiter_audio_level", info.limiter_envelope_dbfs); } constexpr int kGainApplierAdjacentSpeechFramesThreshold = 1; constexpr float kMaxGainChangePerSecondDb = 3.f; constexpr float kMaxOutputNoiseLevelDbfs = -50.f; } // namespace AdaptiveAgc::AdaptiveAgc(ApmDataDumper* apm_data_dumper) : speech_level_estimator_(apm_data_dumper), gain_applier_(apm_data_dumper, kGainApplierAdjacentSpeechFramesThreshold, kMaxGainChangePerSecondDb, kMaxOutputNoiseLevelDbfs), apm_data_dumper_(apm_data_dumper), noise_level_estimator_(apm_data_dumper) { RTC_DCHECK(apm_data_dumper); } AdaptiveAgc::AdaptiveAgc(ApmDataDumper* apm_data_dumper, const AudioProcessing::Config::GainController2& config) : speech_level_estimator_( apm_data_dumper, config.adaptive_digital.level_estimator, config.adaptive_digital .level_estimator_adjacent_speech_frames_threshold, config.adaptive_digital.initial_saturation_margin_db, config.adaptive_digital.extra_saturation_margin_db), vad_(config.adaptive_digital.vad_probability_attack), gain_applier_( apm_data_dumper, config.adaptive_digital.gain_applier_adjacent_speech_frames_threshold, config.adaptive_digital.max_gain_change_db_per_second, config.adaptive_digital.max_output_noise_level_dbfs), apm_data_dumper_(apm_data_dumper), noise_level_estimator_(apm_data_dumper) { RTC_DCHECK(apm_data_dumper); if (!config.adaptive_digital.use_saturation_protector) { RTC_LOG(LS_WARNING) << "The saturation protector cannot be disabled."; } } AdaptiveAgc::~AdaptiveAgc() = default; void AdaptiveAgc::Process(AudioFrameView frame, float limiter_envelope) { AdaptiveDigitalGainApplier::FrameInfo info; info.vad_result = vad_.AnalyzeFrame(frame); speech_level_estimator_.Update(info.vad_result); info.input_level_dbfs = speech_level_estimator_.level_dbfs(); info.input_noise_level_dbfs = noise_level_estimator_.Analyze(frame); info.limiter_envelope_dbfs = limiter_envelope > 0 ? FloatS16ToDbfs(limiter_envelope) : -90.f; info.estimate_is_confident = speech_level_estimator_.IsConfident(); DumpDebugData(info, *apm_data_dumper_); gain_applier_.Process(info, frame); } void AdaptiveAgc::Reset() { speech_level_estimator_.Reset(); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/adaptive_agc.h0000664000175000017500000000361614475643423026563 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_AGC_H_ #define MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_AGC_H_ #include "modules/audio_processing/agc2/adaptive_digital_gain_applier.h" #include "modules/audio_processing/agc2/adaptive_mode_level_estimator.h" #include "modules/audio_processing/agc2/noise_level_estimator.h" #include "modules/audio_processing/agc2/vad_with_level.h" #include "modules/audio_processing/include/audio_frame_view.h" #include "modules/audio_processing/include/audio_processing.h" namespace webrtc { class ApmDataDumper; // Adaptive digital gain controller. // TODO(crbug.com/webrtc/7494): Unify with `AdaptiveDigitalGainApplier`. class AdaptiveAgc { public: explicit AdaptiveAgc(ApmDataDumper* apm_data_dumper); // TODO(crbug.com/webrtc/7494): Remove ctor above. AdaptiveAgc(ApmDataDumper* apm_data_dumper, const AudioProcessing::Config::GainController2& config); ~AdaptiveAgc(); // Analyzes `frame` and applies a digital adaptive gain to it. Takes into // account the envelope measured by the limiter. // TODO(crbug.com/webrtc/7494): Make the class depend on the limiter. void Process(AudioFrameView frame, float limiter_envelope); void Reset(); private: AdaptiveModeLevelEstimator speech_level_estimator_; VadLevelAnalyzer vad_; AdaptiveDigitalGainApplier gain_applier_; ApmDataDumper* const apm_data_dumper_; NoiseLevelEstimator noise_level_estimator_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_AGC_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/adaptive_digital_gain_applier.cc0000664000175000017500000001665014475643423032320 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/adaptive_digital_gain_applier.h" #include #include "common_audio/include/audio_util.h" #include "modules/audio_processing/agc2/agc2_common.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_minmax.h" #include "system_wrappers/include/metrics.h" namespace webrtc { namespace { // This function maps input level to desired applied gain. We want to // boost the signal so that peaks are at -kHeadroomDbfs. We can't // apply more than kMaxGainDb gain. float ComputeGainDb(float input_level_dbfs) { // If the level is very low, boost it as much as we can. if (input_level_dbfs < -(kHeadroomDbfs + kMaxGainDb)) { return kMaxGainDb; } // We expect to end up here most of the time: the level is below // -headroom, but we can boost it to -headroom. if (input_level_dbfs < -kHeadroomDbfs) { return -kHeadroomDbfs - input_level_dbfs; } // Otherwise, the level is too high and we can't boost. The // LevelEstimator is responsible for not reporting bogus gain // values. RTC_DCHECK_LE(input_level_dbfs, 0.f); return 0.f; } // Returns `target_gain` if the output noise level is below // `max_output_noise_level_dbfs`; otherwise returns a capped gain so that the // output noise level equals `max_output_noise_level_dbfs`. float LimitGainByNoise(float target_gain, float input_noise_level_dbfs, float max_output_noise_level_dbfs, ApmDataDumper& apm_data_dumper) { const float noise_headroom_db = max_output_noise_level_dbfs - input_noise_level_dbfs; apm_data_dumper.DumpRaw("agc2_noise_headroom_db", noise_headroom_db); return std::min(target_gain, std::max(noise_headroom_db, 0.f)); } float LimitGainByLowConfidence(float target_gain, float last_gain, float limiter_audio_level_dbfs, bool estimate_is_confident) { if (estimate_is_confident || limiter_audio_level_dbfs <= kLimiterThresholdForAgcGainDbfs) { return target_gain; } const float limiter_level_before_gain = limiter_audio_level_dbfs - last_gain; // Compute a new gain so that limiter_level_before_gain + new_gain <= // kLimiterThreshold. const float new_target_gain = std::max( kLimiterThresholdForAgcGainDbfs - limiter_level_before_gain, 0.f); return std::min(new_target_gain, target_gain); } // Computes how the gain should change during this frame. // Return the gain difference in db to 'last_gain_db'. float ComputeGainChangeThisFrameDb(float target_gain_db, float last_gain_db, bool gain_increase_allowed, float max_gain_change_db) { float target_gain_difference_db = target_gain_db - last_gain_db; if (!gain_increase_allowed) { target_gain_difference_db = std::min(target_gain_difference_db, 0.f); } return rtc::SafeClamp(target_gain_difference_db, -max_gain_change_db, max_gain_change_db); } } // namespace AdaptiveDigitalGainApplier::AdaptiveDigitalGainApplier( ApmDataDumper* apm_data_dumper, int adjacent_speech_frames_threshold, float max_gain_change_db_per_second, float max_output_noise_level_dbfs) : apm_data_dumper_(apm_data_dumper), gain_applier_( /*hard_clip_samples=*/false, /*initial_gain_factor=*/DbToRatio(kInitialAdaptiveDigitalGainDb)), adjacent_speech_frames_threshold_(adjacent_speech_frames_threshold), max_gain_change_db_per_10ms_(max_gain_change_db_per_second * kFrameDurationMs / 1000.f), max_output_noise_level_dbfs_(max_output_noise_level_dbfs), calls_since_last_gain_log_(0), frames_to_gain_increase_allowed_(adjacent_speech_frames_threshold_), last_gain_db_(kInitialAdaptiveDigitalGainDb) { RTC_DCHECK_GT(max_gain_change_db_per_second, 0.f); RTC_DCHECK_GE(frames_to_gain_increase_allowed_, 1); RTC_DCHECK_GE(max_output_noise_level_dbfs_, -90.f); RTC_DCHECK_LE(max_output_noise_level_dbfs_, 0.f); } void AdaptiveDigitalGainApplier::Process(const FrameInfo& info, AudioFrameView frame) { RTC_DCHECK_GE(info.input_level_dbfs, -150.f); RTC_DCHECK_GE(frame.num_channels(), 1); RTC_DCHECK( frame.samples_per_channel() == 80 || frame.samples_per_channel() == 160 || frame.samples_per_channel() == 320 || frame.samples_per_channel() == 480) << "`frame` does not look like a 10 ms frame for an APM supported sample " "rate"; const float target_gain_db = LimitGainByLowConfidence( LimitGainByNoise(ComputeGainDb(std::min(info.input_level_dbfs, 0.f)), info.input_noise_level_dbfs, max_output_noise_level_dbfs_, *apm_data_dumper_), last_gain_db_, info.limiter_envelope_dbfs, info.estimate_is_confident); // Forbid increasing the gain until enough adjacent speech frames are // observed. if (info.vad_result.speech_probability < kVadConfidenceThreshold) { frames_to_gain_increase_allowed_ = adjacent_speech_frames_threshold_; } else if (frames_to_gain_increase_allowed_ > 0) { frames_to_gain_increase_allowed_--; } const float gain_change_this_frame_db = ComputeGainChangeThisFrameDb( target_gain_db, last_gain_db_, /*gain_increase_allowed=*/frames_to_gain_increase_allowed_ == 0, max_gain_change_db_per_10ms_); apm_data_dumper_->DumpRaw("agc2_want_to_change_by_db", target_gain_db - last_gain_db_); apm_data_dumper_->DumpRaw("agc2_will_change_by_db", gain_change_this_frame_db); // Optimization: avoid calling math functions if gain does not // change. if (gain_change_this_frame_db != 0.f) { gain_applier_.SetGainFactor( DbToRatio(last_gain_db_ + gain_change_this_frame_db)); } gain_applier_.ApplyGain(frame); // Remember that the gain has changed for the next iteration. last_gain_db_ = last_gain_db_ + gain_change_this_frame_db; apm_data_dumper_->DumpRaw("agc2_applied_gain_db", last_gain_db_); // Log every 10 seconds. calls_since_last_gain_log_++; if (calls_since_last_gain_log_ == 1000) { calls_since_last_gain_log_ = 0; RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.Agc2.DigitalGainApplied", last_gain_db_, 0, kMaxGainDb, kMaxGainDb + 1); RTC_HISTOGRAM_COUNTS_LINEAR( "WebRTC.Audio.Agc2.EstimatedSpeechPlusNoiseLevel", -info.input_level_dbfs, 0, 100, 101); RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.Agc2.EstimatedNoiseLevel", -info.input_noise_level_dbfs, 0, 100, 101); RTC_LOG(LS_INFO) << "AGC2 adaptive digital" << " | speech_plus_noise_dbfs: " << info.input_level_dbfs << " | noise_dbfs: " << info.input_noise_level_dbfs << " | gain_db: " << last_gain_db_; } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/adaptive_digital_gain_applier.h0000664000175000017500000000540314475643423032154 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_DIGITAL_GAIN_APPLIER_H_ #define MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_DIGITAL_GAIN_APPLIER_H_ #include "modules/audio_processing/agc2/gain_applier.h" #include "modules/audio_processing/agc2/vad_with_level.h" #include "modules/audio_processing/include/audio_frame_view.h" namespace webrtc { class ApmDataDumper; // Part of the adaptive digital controller that applies a digital adaptive gain. // The gain is updated towards a target. The logic decides when gain updates are // allowed, it controls the adaptation speed and caps the target based on the // estimated noise level and the speech level estimate confidence. class AdaptiveDigitalGainApplier { public: // Information about a frame to process. struct FrameInfo { float input_level_dbfs; // Estimated speech plus noise level. float input_noise_level_dbfs; // Estimated noise level. VadLevelAnalyzer::Result vad_result; float limiter_envelope_dbfs; // Envelope level from the limiter. bool estimate_is_confident; }; // Ctor. // `adjacent_speech_frames_threshold` indicates how many speech frames are // required before a gain increase is allowed. `max_gain_change_db_per_second` // limits the adaptation speed (uniformly operated across frames). // `max_output_noise_level_dbfs` limits the output noise level. AdaptiveDigitalGainApplier(ApmDataDumper* apm_data_dumper, int adjacent_speech_frames_threshold, float max_gain_change_db_per_second, float max_output_noise_level_dbfs); AdaptiveDigitalGainApplier(const AdaptiveDigitalGainApplier&) = delete; AdaptiveDigitalGainApplier& operator=(const AdaptiveDigitalGainApplier&) = delete; // Analyzes `info`, updates the digital gain and applies it to a 10 ms // `frame`. Supports any sample rate supported by APM. void Process(const FrameInfo& info, AudioFrameView frame); private: ApmDataDumper* const apm_data_dumper_; GainApplier gain_applier_; const int adjacent_speech_frames_threshold_; const float max_gain_change_db_per_10ms_; const float max_output_noise_level_dbfs_; int calls_since_last_gain_log_; int frames_to_gain_increase_allowed_; float last_gain_db_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_DIGITAL_GAIN_APPLIER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator.cc0000664000175000017500000002021114475643423032357 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/adaptive_mode_level_estimator.h" #include "modules/audio_processing/agc2/agc2_common.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_minmax.h" namespace webrtc { namespace { using LevelEstimatorType = AudioProcessing::Config::GainController2::LevelEstimator; // Combines a level estimation with the saturation protector margins. float ComputeLevelEstimateDbfs(float level_estimate_dbfs, float saturation_margin_db, float extra_saturation_margin_db) { return rtc::SafeClamp( level_estimate_dbfs + saturation_margin_db + extra_saturation_margin_db, -90.f, 30.f); } // Returns the level of given type from `vad_level`. float GetLevel(const VadLevelAnalyzer::Result& vad_level, LevelEstimatorType type) { switch (type) { case LevelEstimatorType::kRms: return vad_level.rms_dbfs; break; case LevelEstimatorType::kPeak: return vad_level.peak_dbfs; break; } } } // namespace bool AdaptiveModeLevelEstimator::LevelEstimatorState::operator==( const AdaptiveModeLevelEstimator::LevelEstimatorState& b) const { return time_to_full_buffer_ms == b.time_to_full_buffer_ms && level_dbfs.numerator == b.level_dbfs.numerator && level_dbfs.denominator == b.level_dbfs.denominator && saturation_protector == b.saturation_protector; } float AdaptiveModeLevelEstimator::LevelEstimatorState::Ratio::GetRatio() const { RTC_DCHECK_NE(denominator, 0.f); return numerator / denominator; } AdaptiveModeLevelEstimator::AdaptiveModeLevelEstimator( ApmDataDumper* apm_data_dumper) : AdaptiveModeLevelEstimator( apm_data_dumper, AudioProcessing::Config::GainController2::LevelEstimator::kRms, kDefaultLevelEstimatorAdjacentSpeechFramesThreshold, kDefaultInitialSaturationMarginDb, kDefaultExtraSaturationMarginDb) {} AdaptiveModeLevelEstimator::AdaptiveModeLevelEstimator( ApmDataDumper* apm_data_dumper, AudioProcessing::Config::GainController2::LevelEstimator level_estimator, int adjacent_speech_frames_threshold, float initial_saturation_margin_db, float extra_saturation_margin_db) : apm_data_dumper_(apm_data_dumper), level_estimator_type_(level_estimator), adjacent_speech_frames_threshold_(adjacent_speech_frames_threshold), initial_saturation_margin_db_(initial_saturation_margin_db), extra_saturation_margin_db_(extra_saturation_margin_db), level_dbfs_(ComputeLevelEstimateDbfs(kInitialSpeechLevelEstimateDbfs, initial_saturation_margin_db_, extra_saturation_margin_db_)) { RTC_DCHECK(apm_data_dumper_); RTC_DCHECK_GE(adjacent_speech_frames_threshold_, 1); Reset(); } void AdaptiveModeLevelEstimator::Update( const VadLevelAnalyzer::Result& vad_level) { RTC_DCHECK_GT(vad_level.rms_dbfs, -150.f); RTC_DCHECK_LT(vad_level.rms_dbfs, 50.f); RTC_DCHECK_GT(vad_level.peak_dbfs, -150.f); RTC_DCHECK_LT(vad_level.peak_dbfs, 50.f); RTC_DCHECK_GE(vad_level.speech_probability, 0.f); RTC_DCHECK_LE(vad_level.speech_probability, 1.f); DumpDebugData(); if (vad_level.speech_probability < kVadConfidenceThreshold) { // Not a speech frame. if (adjacent_speech_frames_threshold_ > 1) { // When two or more adjacent speech frames are required in order to update // the state, we need to decide whether to discard or confirm the updates // based on the speech sequence length. if (num_adjacent_speech_frames_ >= adjacent_speech_frames_threshold_) { // First non-speech frame after a long enough sequence of speech frames. // Update the reliable state. reliable_state_ = preliminary_state_; } else if (num_adjacent_speech_frames_ > 0) { // First non-speech frame after a too short sequence of speech frames. // Reset to the last reliable state. preliminary_state_ = reliable_state_; } } num_adjacent_speech_frames_ = 0; return; } // Speech frame observed. num_adjacent_speech_frames_++; // Update preliminary level estimate. RTC_DCHECK_GE(preliminary_state_.time_to_full_buffer_ms, 0); const bool buffer_is_full = preliminary_state_.time_to_full_buffer_ms == 0; if (!buffer_is_full) { preliminary_state_.time_to_full_buffer_ms -= kFrameDurationMs; } // Weighted average of levels with speech probability as weight. RTC_DCHECK_GT(vad_level.speech_probability, 0.f); const float leak_factor = buffer_is_full ? kFullBufferLeakFactor : 1.f; preliminary_state_.level_dbfs.numerator = preliminary_state_.level_dbfs.numerator * leak_factor + GetLevel(vad_level, level_estimator_type_) * vad_level.speech_probability; preliminary_state_.level_dbfs.denominator = preliminary_state_.level_dbfs.denominator * leak_factor + vad_level.speech_probability; const float level_dbfs = preliminary_state_.level_dbfs.GetRatio(); UpdateSaturationProtectorState(vad_level.peak_dbfs, level_dbfs, preliminary_state_.saturation_protector); if (num_adjacent_speech_frames_ >= adjacent_speech_frames_threshold_) { // `preliminary_state_` is now reliable. Update the last level estimation. level_dbfs_ = ComputeLevelEstimateDbfs( level_dbfs, preliminary_state_.saturation_protector.margin_db, extra_saturation_margin_db_); } } bool AdaptiveModeLevelEstimator::IsConfident() const { if (adjacent_speech_frames_threshold_ == 1) { // Ignore `reliable_state_` when a single frame is enough to update the // level estimate (because it is not used). return preliminary_state_.time_to_full_buffer_ms == 0; } // Once confident, it remains confident. RTC_DCHECK(reliable_state_.time_to_full_buffer_ms != 0 || preliminary_state_.time_to_full_buffer_ms == 0); // During the first long enough speech sequence, `reliable_state_` must be // ignored since `preliminary_state_` is used. return reliable_state_.time_to_full_buffer_ms == 0 || (num_adjacent_speech_frames_ >= adjacent_speech_frames_threshold_ && preliminary_state_.time_to_full_buffer_ms == 0); } void AdaptiveModeLevelEstimator::Reset() { ResetLevelEstimatorState(preliminary_state_); ResetLevelEstimatorState(reliable_state_); level_dbfs_ = ComputeLevelEstimateDbfs(kInitialSpeechLevelEstimateDbfs, initial_saturation_margin_db_, extra_saturation_margin_db_); num_adjacent_speech_frames_ = 0; } void AdaptiveModeLevelEstimator::ResetLevelEstimatorState( LevelEstimatorState& state) const { state.time_to_full_buffer_ms = kFullBufferSizeMs; state.level_dbfs.numerator = 0.f; state.level_dbfs.denominator = 0.f; ResetSaturationProtectorState(initial_saturation_margin_db_, state.saturation_protector); } void AdaptiveModeLevelEstimator::DumpDebugData() const { apm_data_dumper_->DumpRaw("agc2_adaptive_level_estimate_dbfs", level_dbfs_); apm_data_dumper_->DumpRaw("agc2_adaptive_num_adjacent_speech_frames_", num_adjacent_speech_frames_); apm_data_dumper_->DumpRaw("agc2_adaptive_preliminary_level_estimate_num", preliminary_state_.level_dbfs.numerator); apm_data_dumper_->DumpRaw("agc2_adaptive_preliminary_level_estimate_den", preliminary_state_.level_dbfs.denominator); apm_data_dumper_->DumpRaw("agc2_adaptive_preliminary_saturation_margin_db", preliminary_state_.saturation_protector.margin_db); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator.h0000664000175000017500000000600014475643423032221 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_MODE_LEVEL_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_MODE_LEVEL_ESTIMATOR_H_ #include #include #include "modules/audio_processing/agc2/agc2_common.h" #include "modules/audio_processing/agc2/saturation_protector.h" #include "modules/audio_processing/agc2/vad_with_level.h" #include "modules/audio_processing/include/audio_processing.h" namespace webrtc { class ApmDataDumper; // Level estimator for the digital adaptive gain controller. class AdaptiveModeLevelEstimator { public: explicit AdaptiveModeLevelEstimator(ApmDataDumper* apm_data_dumper); AdaptiveModeLevelEstimator(const AdaptiveModeLevelEstimator&) = delete; AdaptiveModeLevelEstimator& operator=(const AdaptiveModeLevelEstimator&) = delete; AdaptiveModeLevelEstimator( ApmDataDumper* apm_data_dumper, AudioProcessing::Config::GainController2::LevelEstimator level_estimator, int adjacent_speech_frames_threshold, float initial_saturation_margin_db, float extra_saturation_margin_db); // Updates the level estimation. void Update(const VadLevelAnalyzer::Result& vad_data); // Returns the estimated speech plus noise level. float level_dbfs() const { return level_dbfs_; } // Returns true if the estimator is confident on its current estimate. bool IsConfident() const; void Reset(); private: // Part of the level estimator state used for check-pointing and restore ops. struct LevelEstimatorState { bool operator==(const LevelEstimatorState& s) const; inline bool operator!=(const LevelEstimatorState& s) const { return !(*this == s); } struct Ratio { float numerator; float denominator; float GetRatio() const; }; // TODO(crbug.com/webrtc/7494): Remove time_to_full_buffer_ms if redundant. int time_to_full_buffer_ms; Ratio level_dbfs; SaturationProtectorState saturation_protector; }; static_assert(std::is_trivially_copyable::value, ""); void ResetLevelEstimatorState(LevelEstimatorState& state) const; void DumpDebugData() const; ApmDataDumper* const apm_data_dumper_; const AudioProcessing::Config::GainController2::LevelEstimator level_estimator_type_; const int adjacent_speech_frames_threshold_; const float initial_saturation_margin_db_; const float extra_saturation_margin_db_; LevelEstimatorState preliminary_state_; LevelEstimatorState reliable_state_; float level_dbfs_; int num_adjacent_speech_frames_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_MODE_LEVEL_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000020500000000000010212 xustar00111 path=webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.cc 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.c0000664000175000017500000000455514475643423033043 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.h" #include #include #include "modules/audio_processing/agc2/agc2_common.h" #include "modules/audio_processing/include/audio_frame_view.h" namespace webrtc { AdaptiveModeLevelEstimatorAgc::AdaptiveModeLevelEstimatorAgc( ApmDataDumper* apm_data_dumper) : level_estimator_(apm_data_dumper) { set_target_level_dbfs(kDefaultAgc2LevelHeadroomDbfs); } // |audio| must be mono; in a multi-channel stream, provide the first (usually // left) channel. void AdaptiveModeLevelEstimatorAgc::Process(const int16_t* audio, size_t length, int sample_rate_hz) { std::vector float_audio_frame(audio, audio + length); const float* const first_channel = &float_audio_frame[0]; AudioFrameView frame_view(&first_channel, 1 /* num channels */, length); const auto vad_prob = agc2_vad_.AnalyzeFrame(frame_view); latest_voice_probability_ = vad_prob.speech_probability; if (latest_voice_probability_ > kVadConfidenceThreshold) { time_in_ms_since_last_estimate_ += kFrameDurationMs; } level_estimator_.Update(vad_prob); } // Retrieves the difference between the target RMS level and the current // signal RMS level in dB. Returns true if an update is available and false // otherwise, in which case |error| should be ignored and no action taken. bool AdaptiveModeLevelEstimatorAgc::GetRmsErrorDb(int* error) { if (time_in_ms_since_last_estimate_ <= kTimeUntilConfidentMs) { return false; } *error = std::floor(target_level_dbfs() - level_estimator_.level_dbfs() + 0.5f); time_in_ms_since_last_estimate_ = 0; return true; } void AdaptiveModeLevelEstimatorAgc::Reset() { level_estimator_.Reset(); } float AdaptiveModeLevelEstimatorAgc::voice_probability() const { return latest_voice_probability_; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.h0000664000175000017500000000363714475643423033050 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_MODE_LEVEL_ESTIMATOR_AGC_H_ #define MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_MODE_LEVEL_ESTIMATOR_AGC_H_ #include #include #include "modules/audio_processing/agc/agc.h" #include "modules/audio_processing/agc2/adaptive_mode_level_estimator.h" #include "modules/audio_processing/agc2/saturation_protector.h" #include "modules/audio_processing/agc2/vad_with_level.h" namespace webrtc { class AdaptiveModeLevelEstimatorAgc : public Agc { public: explicit AdaptiveModeLevelEstimatorAgc(ApmDataDumper* apm_data_dumper); // |audio| must be mono; in a multi-channel stream, provide the first (usually // left) channel. void Process(const int16_t* audio, size_t length, int sample_rate_hz) override; // Retrieves the difference between the target RMS level and the current // signal RMS level in dB. Returns true if an update is available and false // otherwise, in which case |error| should be ignored and no action taken. bool GetRmsErrorDb(int* error) override; void Reset() override; float voice_probability() const override; private: static constexpr int kTimeUntilConfidentMs = 700; static constexpr int kDefaultAgc2LevelHeadroomDbfs = -1; int32_t time_in_ms_since_last_estimate_ = 0; AdaptiveModeLevelEstimator level_estimator_; VadLevelAnalyzer agc2_vad_; float latest_voice_probability_ = 0.f; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_MODE_LEVEL_ESTIMATOR_AGC_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/agc2_common.h0000664000175000017500000000674214475643423026343 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_AGC2_COMMON_H_ #define MODULES_AUDIO_PROCESSING_AGC2_AGC2_COMMON_H_ #include namespace webrtc { constexpr float kMinFloatS16Value = -32768.f; constexpr float kMaxFloatS16Value = 32767.f; constexpr float kMaxAbsFloatS16Value = 32768.0f; constexpr size_t kFrameDurationMs = 10; constexpr size_t kSubFramesInFrame = 20; constexpr size_t kMaximalNumberOfSamplesPerChannel = 480; constexpr float kAttackFilterConstant = 0.f; // Adaptive digital gain applier settings below. constexpr float kHeadroomDbfs = 1.f; constexpr float kMaxGainDb = 30.f; constexpr float kInitialAdaptiveDigitalGainDb = 8.f; // At what limiter levels should we start decreasing the adaptive digital gain. constexpr float kLimiterThresholdForAgcGainDbfs = -kHeadroomDbfs; // This is the threshold for speech. Speech frames are used for updating the // speech level, measuring the amount of speech, and decide when to allow target // gain reduction. constexpr float kVadConfidenceThreshold = 0.9f; // The amount of 'memory' of the Level Estimator. Decides leak factors. constexpr size_t kFullBufferSizeMs = 1200; constexpr float kFullBufferLeakFactor = 1.f - 1.f / kFullBufferSizeMs; constexpr float kInitialSpeechLevelEstimateDbfs = -30.f; // Robust VAD probability and speech decisions. constexpr float kDefaultSmoothedVadProbabilityAttack = 1.f; constexpr int kDefaultLevelEstimatorAdjacentSpeechFramesThreshold = 1; // Saturation Protector settings. constexpr float kDefaultInitialSaturationMarginDb = 20.f; constexpr float kDefaultExtraSaturationMarginDb = 2.f; constexpr size_t kPeakEnveloperSuperFrameLengthMs = 400; static_assert(kFullBufferSizeMs % kPeakEnveloperSuperFrameLengthMs == 0, "Full buffer size should be a multiple of super frame length for " "optimal Saturation Protector performance."); constexpr size_t kPeakEnveloperBufferSize = kFullBufferSizeMs / kPeakEnveloperSuperFrameLengthMs + 1; // This value is 10 ** (-1/20 * frame_size_ms / satproc_attack_ms), // where satproc_attack_ms is 5000. constexpr float kSaturationProtectorAttackConstant = 0.9988493699365052f; // This value is 10 ** (-1/20 * frame_size_ms / satproc_decay_ms), // where satproc_decay_ms is 1000. constexpr float kSaturationProtectorDecayConstant = 0.9997697679981565f; // This is computed from kDecayMs by // 10 ** (-1/20 * subframe_duration / kDecayMs). // |subframe_duration| is |kFrameDurationMs / kSubFramesInFrame|. // kDecayMs is defined in agc2_testing_common.h constexpr float kDecayFilterConstant = 0.9998848773724686f; // Number of interpolation points for each region of the limiter. // These values have been tuned to limit the interpolated gain curve error given // the limiter parameters and allowing a maximum error of +/- 32768^-1. constexpr size_t kInterpolatedGainCurveKneePoints = 22; constexpr size_t kInterpolatedGainCurveBeyondKneePoints = 10; constexpr size_t kInterpolatedGainCurveTotalPoints = kInterpolatedGainCurveKneePoints + kInterpolatedGainCurveBeyondKneePoints; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_AGC2_COMMON_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/agc2_testing_common.cc0000664000175000017500000000177714475643423030241 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/agc2_testing_common.h" #include "rtc_base/checks.h" namespace webrtc { namespace test { std::vector LinSpace(const double l, const double r, size_t num_points) { RTC_CHECK(num_points >= 2); std::vector points(num_points); const double step = (r - l) / (num_points - 1.0); points[0] = l; for (size_t i = 1; i < num_points - 1; i++) { points[i] = static_cast(l) + i * step; } points[num_points - 1] = r; return points; } } // namespace test } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/agc2_testing_common.h0000664000175000017500000000375614475643423030102 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_AGC2_TESTING_COMMON_H_ #define MODULES_AUDIO_PROCESSING_AGC2_AGC2_TESTING_COMMON_H_ #include #include #include #include "rtc_base/checks.h" namespace webrtc { namespace test { // Level Estimator test parameters. constexpr float kDecayMs = 500.f; // Limiter parameters. constexpr float kLimiterMaxInputLevelDbFs = 1.f; constexpr float kLimiterKneeSmoothnessDb = 1.f; constexpr float kLimiterCompressionRatio = 5.f; constexpr float kPi = 3.1415926536f; std::vector LinSpace(const double l, const double r, size_t num_points); class SineGenerator { public: SineGenerator(float frequency, int rate) : frequency_(frequency), rate_(rate) {} float operator()() { x_radians_ += frequency_ / rate_ * 2 * kPi; if (x_radians_ > 2 * kPi) { x_radians_ -= 2 * kPi; } return 1000.f * sinf(x_radians_); } private: float frequency_; int rate_; float x_radians_ = 0.f; }; class PulseGenerator { public: PulseGenerator(float frequency, int rate) : samples_period_( static_cast(static_cast(rate) / frequency)) { RTC_DCHECK_GT(rate, frequency); } float operator()() { sample_counter_++; if (sample_counter_ >= samples_period_) { sample_counter_ -= samples_period_; } return static_cast( sample_counter_ == 0 ? std::numeric_limits::max() : 10.f); } private: int samples_period_; int sample_counter_ = 0; }; } // namespace test } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_AGC2_TESTING_COMMON_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/biquad_filter.cc0000664000175000017500000000252214475643423027117 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/biquad_filter.h" #include namespace webrtc { // Transposed direct form I implementation of a bi-quad filter applied to an // input signal |x| to produce an output signal |y|. void BiQuadFilter::Process(rtc::ArrayView x, rtc::ArrayView y) { for (size_t k = 0; k < x.size(); ++k) { // Use temporary variable for x[k] to allow in-place function call // (that x and y refer to the same array). const float tmp = x[k]; y[k] = coefficients_.b[0] * tmp + coefficients_.b[1] * biquad_state_.b[0] + coefficients_.b[2] * biquad_state_.b[1] - coefficients_.a[0] * biquad_state_.a[0] - coefficients_.a[1] * biquad_state_.a[1]; biquad_state_.b[1] = biquad_state_.b[0]; biquad_state_.b[0] = tmp; biquad_state_.a[1] = biquad_state_.a[0]; biquad_state_.a[0] = y[k]; } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/biquad_filter.h0000664000175000017500000000331114475643423026756 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_BIQUAD_FILTER_H_ #define MODULES_AUDIO_PROCESSING_AGC2_BIQUAD_FILTER_H_ #include #include "api/array_view.h" #include "rtc_base/arraysize.h" #include "rtc_base/constructor_magic.h" namespace webrtc { class BiQuadFilter { public: // Normalized filter coefficients. // b_0 + b_1 • z^(-1) + b_2 • z^(-2) // H(z) = --------------------------------- // 1 + a_1 • z^(-1) + a_2 • z^(-2) struct BiQuadCoefficients { float b[3]; float a[2]; }; BiQuadFilter() = default; void Initialize(const BiQuadCoefficients& coefficients) { coefficients_ = coefficients; } void Reset() { biquad_state_.Reset(); } // Produces a filtered output y of the input x. Both x and y need to // have the same length. In-place modification is allowed. void Process(rtc::ArrayView x, rtc::ArrayView y); private: struct BiQuadState { BiQuadState() { Reset(); } void Reset() { std::fill(b, b + arraysize(b), 0.f); std::fill(a, a + arraysize(a), 0.f); } float b[2]; float a[2]; }; BiQuadState biquad_state_; BiQuadCoefficients coefficients_; RTC_DISALLOW_COPY_AND_ASSIGN(BiQuadFilter); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_BIQUAD_FILTER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/compute_interpolated_gain_curve.cc0000664000175000017500000002221014475643423032731 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/compute_interpolated_gain_curve.h" #include #include #include #include #include #include #include "modules/audio_processing/agc2/agc2_common.h" #include "modules/audio_processing/agc2/agc2_testing_common.h" #include "modules/audio_processing/agc2/limiter_db_gain_curve.h" #include "rtc_base/checks.h" namespace webrtc { namespace { std::pair ComputeLinearApproximationParams( const LimiterDbGainCurve* limiter, const double x) { const double m = limiter->GetGainFirstDerivativeLinear(x); const double q = limiter->GetGainLinear(x) - m * x; return {m, q}; } double ComputeAreaUnderPiecewiseLinearApproximation( const LimiterDbGainCurve* limiter, const double x0, const double x1) { RTC_CHECK_LT(x0, x1); // Linear approximation in x0 and x1. double m0, q0, m1, q1; std::tie(m0, q0) = ComputeLinearApproximationParams(limiter, x0); std::tie(m1, q1) = ComputeLinearApproximationParams(limiter, x1); // Intersection point between two adjacent linear pieces. RTC_CHECK_NE(m1, m0); const double x_split = (q0 - q1) / (m1 - m0); RTC_CHECK_LT(x0, x_split); RTC_CHECK_LT(x_split, x1); auto area_under_linear_piece = [](double x_l, double x_r, double m, double q) { return x_r * (m * x_r / 2.0 + q) - x_l * (m * x_l / 2.0 + q); }; return area_under_linear_piece(x0, x_split, m0, q0) + area_under_linear_piece(x_split, x1, m1, q1); } // Computes the approximation error in the limiter region for a given interval. // The error is computed as the difference between the areas beneath the limiter // curve to approximate and its linear under-approximation. double LimiterUnderApproximationNegativeError(const LimiterDbGainCurve* limiter, const double x0, const double x1) { const double area_limiter = limiter->GetGainIntegralLinear(x0, x1); const double area_interpolated_curve = ComputeAreaUnderPiecewiseLinearApproximation(limiter, x0, x1); RTC_CHECK_GE(area_limiter, area_interpolated_curve); return area_limiter - area_interpolated_curve; } // Automatically finds where to sample the beyond-knee region of a limiter using // a greedy optimization algorithm that iteratively decreases the approximation // error. // The solution is sub-optimal because the algorithm is greedy and the points // are assigned by halving intervals (starting with the whole beyond-knee region // as a single interval). However, even if sub-optimal, this algorithm works // well in practice and it is efficiently implemented using priority queues. std::vector SampleLimiterRegion(const LimiterDbGainCurve* limiter) { static_assert(kInterpolatedGainCurveBeyondKneePoints > 2, ""); struct Interval { Interval() = default; // Ctor required by std::priority_queue. Interval(double l, double r, double e) : x0(l), x1(r), error(e) { RTC_CHECK(x0 < x1); } bool operator<(const Interval& other) const { return error < other.error; } double x0; double x1; double error; }; std::priority_queue> q; q.emplace(limiter->limiter_start_linear(), limiter->max_input_level_linear(), LimiterUnderApproximationNegativeError( limiter, limiter->limiter_start_linear(), limiter->max_input_level_linear())); // Iteratively find points by halving the interval with greatest error. while (q.size() < kInterpolatedGainCurveBeyondKneePoints) { // Get the interval with highest error. const auto interval = q.top(); q.pop(); // Split |interval| and enqueue. double x_split = (interval.x0 + interval.x1) / 2.0; q.emplace(interval.x0, x_split, LimiterUnderApproximationNegativeError(limiter, interval.x0, x_split)); // Left. q.emplace(x_split, interval.x1, LimiterUnderApproximationNegativeError(limiter, x_split, interval.x1)); // Right. } // Copy x1 values and sort them. RTC_CHECK_EQ(q.size(), kInterpolatedGainCurveBeyondKneePoints); std::vector samples(kInterpolatedGainCurveBeyondKneePoints); for (size_t i = 0; i < kInterpolatedGainCurveBeyondKneePoints; ++i) { const auto interval = q.top(); q.pop(); samples[i] = interval.x1; } RTC_CHECK(q.empty()); std::sort(samples.begin(), samples.end()); return samples; } // Compute the parameters to over-approximate the knee region via linear // interpolation. Over-approximating is saturation-safe since the knee region is // convex. void PrecomputeKneeApproxParams(const LimiterDbGainCurve* limiter, test::InterpolatedParameters* parameters) { static_assert(kInterpolatedGainCurveKneePoints > 2, ""); // Get |kInterpolatedGainCurveKneePoints| - 1 equally spaced points. const std::vector points = test::LinSpace( limiter->knee_start_linear(), limiter->limiter_start_linear(), kInterpolatedGainCurveKneePoints - 1); // Set the first two points. The second is computed to help with the beginning // of the knee region, which has high curvature. parameters->computed_approximation_params_x[0] = points[0]; parameters->computed_approximation_params_x[1] = (points[0] + points[1]) / 2.0; // Copy the remaining points. std::copy(std::begin(points) + 1, std::end(points), std::begin(parameters->computed_approximation_params_x) + 2); // Compute (m, q) pairs for each linear piece y = mx + q. for (size_t i = 0; i < kInterpolatedGainCurveKneePoints - 1; ++i) { const double x0 = parameters->computed_approximation_params_x[i]; const double x1 = parameters->computed_approximation_params_x[i + 1]; const double y0 = limiter->GetGainLinear(x0); const double y1 = limiter->GetGainLinear(x1); RTC_CHECK_NE(x1, x0); parameters->computed_approximation_params_m[i] = (y1 - y0) / (x1 - x0); parameters->computed_approximation_params_q[i] = y0 - parameters->computed_approximation_params_m[i] * x0; } } // Compute the parameters to under-approximate the beyond-knee region via linear // interpolation and greedy sampling. Under-approximating is saturation-safe // since the beyond-knee region is concave. void PrecomputeBeyondKneeApproxParams( const LimiterDbGainCurve* limiter, test::InterpolatedParameters* parameters) { // Find points on which the linear pieces are tangent to the gain curve. const auto samples = SampleLimiterRegion(limiter); // Parametrize each linear piece. double m, q; std::tie(m, q) = ComputeLinearApproximationParams( limiter, parameters ->computed_approximation_params_x[kInterpolatedGainCurveKneePoints - 1]); parameters ->computed_approximation_params_m[kInterpolatedGainCurveKneePoints - 1] = m; parameters ->computed_approximation_params_q[kInterpolatedGainCurveKneePoints - 1] = q; for (size_t i = 0; i < samples.size(); ++i) { std::tie(m, q) = ComputeLinearApproximationParams(limiter, samples[i]); parameters ->computed_approximation_params_m[i + kInterpolatedGainCurveKneePoints] = m; parameters ->computed_approximation_params_q[i + kInterpolatedGainCurveKneePoints] = q; } // Find the point of intersection between adjacent linear pieces. They will be // used as boundaries between adjacent linear pieces. for (size_t i = kInterpolatedGainCurveKneePoints; i < kInterpolatedGainCurveKneePoints + kInterpolatedGainCurveBeyondKneePoints; ++i) { RTC_CHECK_NE(parameters->computed_approximation_params_m[i], parameters->computed_approximation_params_m[i - 1]); parameters->computed_approximation_params_x[i] = ( // Formula: (q0 - q1) / (m1 - m0). parameters->computed_approximation_params_q[i - 1] - parameters->computed_approximation_params_q[i]) / (parameters->computed_approximation_params_m[i] - parameters->computed_approximation_params_m[i - 1]); } } } // namespace namespace test { InterpolatedParameters ComputeInterpolatedGainCurveApproximationParams() { InterpolatedParameters parameters; LimiterDbGainCurve limiter; parameters.computed_approximation_params_x.fill(0.0f); parameters.computed_approximation_params_m.fill(0.0f); parameters.computed_approximation_params_q.fill(0.0f); PrecomputeKneeApproxParams(&limiter, ¶meters); PrecomputeBeyondKneeApproxParams(&limiter, ¶meters); return parameters; } } // namespace test } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/compute_interpolated_gain_curve.h0000664000175000017500000000343414475643423032602 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_COMPUTE_INTERPOLATED_GAIN_CURVE_H_ #define MODULES_AUDIO_PROCESSING_AGC2_COMPUTE_INTERPOLATED_GAIN_CURVE_H_ #include #include "modules/audio_processing/agc2/agc2_common.h" namespace webrtc { namespace test { // Parameters for interpolated gain curve using under-approximation to // avoid saturation. // // The saturation gain is defined in order to let hard-clipping occur for // those samples having a level that falls in the saturation region. It is an // upper bound of the actual gain to apply - i.e., that returned by the // limiter. // Knee and beyond-knee regions approximation parameters. // The gain curve is approximated as a piece-wise linear function. // |approx_params_x_| are the boundaries between adjacent linear pieces, // |approx_params_m_| and |approx_params_q_| are the slope and the y-intercept // values of each piece. struct InterpolatedParameters { std::array computed_approximation_params_x; std::array computed_approximation_params_m; std::array computed_approximation_params_q; }; InterpolatedParameters ComputeInterpolatedGainCurveApproximationParams(); } // namespace test } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_COMPUTE_INTERPOLATED_GAIN_CURVE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/down_sampler.cc0000664000175000017500000000651714475643423027007 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/down_sampler.h" #include #include #include "modules/audio_processing/agc2/biquad_filter.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" namespace webrtc { namespace { constexpr int kChunkSizeMs = 10; constexpr int kSampleRate8kHz = 8000; constexpr int kSampleRate16kHz = 16000; constexpr int kSampleRate32kHz = 32000; constexpr int kSampleRate48kHz = 48000; // Bandlimiter coefficients computed based on that only // the first 40 bins of the spectrum for the downsampled // signal are used. // [B,A] = butter(2,(41/64*4000)/8000) const BiQuadFilter::BiQuadCoefficients kLowPassFilterCoefficients_16kHz = { {0.1455f, 0.2911f, 0.1455f}, {-0.6698f, 0.2520f}}; // [B,A] = butter(2,(41/64*4000)/16000) const BiQuadFilter::BiQuadCoefficients kLowPassFilterCoefficients_32kHz = { {0.0462f, 0.0924f, 0.0462f}, {-1.3066f, 0.4915f}}; // [B,A] = butter(2,(41/64*4000)/24000) const BiQuadFilter::BiQuadCoefficients kLowPassFilterCoefficients_48kHz = { {0.0226f, 0.0452f, 0.0226f}, {-1.5320f, 0.6224f}}; } // namespace DownSampler::DownSampler(ApmDataDumper* data_dumper) : data_dumper_(data_dumper) { Initialize(48000); } void DownSampler::Initialize(int sample_rate_hz) { RTC_DCHECK( sample_rate_hz == kSampleRate8kHz || sample_rate_hz == kSampleRate16kHz || sample_rate_hz == kSampleRate32kHz || sample_rate_hz == kSampleRate48kHz); sample_rate_hz_ = sample_rate_hz; down_sampling_factor_ = rtc::CheckedDivExact(sample_rate_hz_, 8000); /// Note that the down sampling filter is not used if the sample rate is 8 /// kHz. if (sample_rate_hz_ == kSampleRate16kHz) { low_pass_filter_.Initialize(kLowPassFilterCoefficients_16kHz); } else if (sample_rate_hz_ == kSampleRate32kHz) { low_pass_filter_.Initialize(kLowPassFilterCoefficients_32kHz); } else if (sample_rate_hz_ == kSampleRate48kHz) { low_pass_filter_.Initialize(kLowPassFilterCoefficients_48kHz); } } void DownSampler::DownSample(rtc::ArrayView in, rtc::ArrayView out) { data_dumper_->DumpWav("lc_down_sampler_input", in, sample_rate_hz_, 1); RTC_DCHECK_EQ(sample_rate_hz_ * kChunkSizeMs / 1000, in.size()); RTC_DCHECK_EQ(kSampleRate8kHz * kChunkSizeMs / 1000, out.size()); const size_t kMaxNumFrames = kSampleRate48kHz * kChunkSizeMs / 1000; float x[kMaxNumFrames]; // Band-limit the signal to 4 kHz. if (sample_rate_hz_ != kSampleRate8kHz) { low_pass_filter_.Process(in, rtc::ArrayView(x, in.size())); // Downsample the signal. size_t k = 0; for (size_t j = 0; j < out.size(); ++j) { RTC_DCHECK_GT(kMaxNumFrames, k); out[j] = x[k]; k += down_sampling_factor_; } } else { std::copy(in.data(), in.data() + in.size(), out.data()); } data_dumper_->DumpWav("lc_down_sampler_output", out, kSampleRate8kHz, 1); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/down_sampler.h0000664000175000017500000000224514475643423026643 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_DOWN_SAMPLER_H_ #define MODULES_AUDIO_PROCESSING_AGC2_DOWN_SAMPLER_H_ #include "api/array_view.h" #include "modules/audio_processing/agc2/biquad_filter.h" namespace webrtc { class ApmDataDumper; class DownSampler { public: explicit DownSampler(ApmDataDumper* data_dumper); DownSampler() = delete; DownSampler(const DownSampler&) = delete; DownSampler& operator=(const DownSampler&) = delete; void Initialize(int sample_rate_hz); void DownSample(rtc::ArrayView in, rtc::ArrayView out); private: ApmDataDumper* data_dumper_; int sample_rate_hz_; int down_sampling_factor_; BiQuadFilter low_pass_filter_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_DOWN_SAMPLER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/fixed_digital_level_estimator.cc0000664000175000017500000001012714475643423032357 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/fixed_digital_level_estimator.h" #include #include #include "api/array_view.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" namespace webrtc { namespace { constexpr float kInitialFilterStateLevel = 0.f; } // namespace FixedDigitalLevelEstimator::FixedDigitalLevelEstimator( size_t sample_rate_hz, ApmDataDumper* apm_data_dumper) : apm_data_dumper_(apm_data_dumper), filter_state_level_(kInitialFilterStateLevel) { SetSampleRate(sample_rate_hz); CheckParameterCombination(); RTC_DCHECK(apm_data_dumper_); apm_data_dumper_->DumpRaw("agc2_level_estimator_samplerate", sample_rate_hz); } void FixedDigitalLevelEstimator::CheckParameterCombination() { RTC_DCHECK_GT(samples_in_frame_, 0); RTC_DCHECK_LE(kSubFramesInFrame, samples_in_frame_); RTC_DCHECK_EQ(samples_in_frame_ % kSubFramesInFrame, 0); RTC_DCHECK_GT(samples_in_sub_frame_, 1); } std::array FixedDigitalLevelEstimator::ComputeLevel( const AudioFrameView& float_frame) { RTC_DCHECK_GT(float_frame.num_channels(), 0); RTC_DCHECK_EQ(float_frame.samples_per_channel(), samples_in_frame_); // Compute max envelope without smoothing. std::array envelope{}; for (size_t channel_idx = 0; channel_idx < float_frame.num_channels(); ++channel_idx) { const auto channel = float_frame.channel(channel_idx); for (size_t sub_frame = 0; sub_frame < kSubFramesInFrame; ++sub_frame) { for (size_t sample_in_sub_frame = 0; sample_in_sub_frame < samples_in_sub_frame_; ++sample_in_sub_frame) { envelope[sub_frame] = std::max(envelope[sub_frame], std::abs(channel[sub_frame * samples_in_sub_frame_ + sample_in_sub_frame])); } } } // Make sure envelope increases happen one step earlier so that the // corresponding *gain decrease* doesn't miss a sudden signal // increase due to interpolation. for (size_t sub_frame = 0; sub_frame < kSubFramesInFrame - 1; ++sub_frame) { if (envelope[sub_frame] < envelope[sub_frame + 1]) { envelope[sub_frame] = envelope[sub_frame + 1]; } } // Add attack / decay smoothing. for (size_t sub_frame = 0; sub_frame < kSubFramesInFrame; ++sub_frame) { const float envelope_value = envelope[sub_frame]; if (envelope_value > filter_state_level_) { envelope[sub_frame] = envelope_value * (1 - kAttackFilterConstant) + filter_state_level_ * kAttackFilterConstant; } else { envelope[sub_frame] = envelope_value * (1 - kDecayFilterConstant) + filter_state_level_ * kDecayFilterConstant; } filter_state_level_ = envelope[sub_frame]; // Dump data for debug. RTC_DCHECK(apm_data_dumper_); const auto channel = float_frame.channel(0); apm_data_dumper_->DumpRaw("agc2_level_estimator_samples", samples_in_sub_frame_, &channel[sub_frame * samples_in_sub_frame_]); apm_data_dumper_->DumpRaw("agc2_level_estimator_level", envelope[sub_frame]); } return envelope; } void FixedDigitalLevelEstimator::SetSampleRate(size_t sample_rate_hz) { samples_in_frame_ = rtc::CheckedDivExact(sample_rate_hz * kFrameDurationMs, static_cast(1000)); samples_in_sub_frame_ = rtc::CheckedDivExact(samples_in_frame_, kSubFramesInFrame); CheckParameterCombination(); } void FixedDigitalLevelEstimator::Reset() { filter_state_level_ = kInitialFilterStateLevel; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/fixed_digital_level_estimator.h0000664000175000017500000000454014475643423032223 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_FIXED_DIGITAL_LEVEL_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_AGC2_FIXED_DIGITAL_LEVEL_ESTIMATOR_H_ #include #include #include "modules/audio_processing/agc2/agc2_common.h" #include "modules/audio_processing/include/audio_frame_view.h" #include "rtc_base/constructor_magic.h" namespace webrtc { class ApmDataDumper; // Produces a smooth signal level estimate from an input audio // stream. The estimate smoothing is done through exponential // filtering. class FixedDigitalLevelEstimator { public: // Sample rates are allowed if the number of samples in a frame // (sample_rate_hz * kFrameDurationMs / 1000) is divisible by // kSubFramesInSample. For kFrameDurationMs=10 and // kSubFramesInSample=20, this means that sample_rate_hz has to be // divisible by 2000. FixedDigitalLevelEstimator(size_t sample_rate_hz, ApmDataDumper* apm_data_dumper); // The input is assumed to be in FloatS16 format. Scaled input will // produce similarly scaled output. A frame of with kFrameDurationMs // ms of audio produces a level estimates in the same scale. The // level estimate contains kSubFramesInFrame values. std::array ComputeLevel( const AudioFrameView& float_frame); // Rate may be changed at any time (but not concurrently) from the // value passed to the constructor. The class is not thread safe. void SetSampleRate(size_t sample_rate_hz); // Resets the level estimator internal state. void Reset(); float LastAudioLevel() const { return filter_state_level_; } private: void CheckParameterCombination(); ApmDataDumper* const apm_data_dumper_ = nullptr; float filter_state_level_; size_t samples_in_frame_; size_t samples_in_sub_frame_; RTC_DISALLOW_COPY_AND_ASSIGN(FixedDigitalLevelEstimator); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_FIXED_DIGITAL_LEVEL_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/fixed_gain_controller.cc0000664000175000017500000000727014475643423030652 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/fixed_gain_controller.h" #include "api/array_view.h" #include "common_audio/include/audio_util.h" #include "modules/audio_processing/agc2/agc2_common.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_minmax.h" namespace webrtc { namespace { // Returns true when the gain factor is so close to 1 that it would // not affect int16 samples. bool CloseToOne(float gain_factor) { return 1.f - 1.f / kMaxFloatS16Value <= gain_factor && gain_factor <= 1.f + 1.f / kMaxFloatS16Value; } } // namespace FixedGainController::FixedGainController(ApmDataDumper* apm_data_dumper) : FixedGainController(apm_data_dumper, "Agc2") {} FixedGainController::FixedGainController(ApmDataDumper* apm_data_dumper, std::string histogram_name_prefix) : apm_data_dumper_(apm_data_dumper), limiter_(48000, apm_data_dumper_, histogram_name_prefix) { // Do update histograms.xml when adding name prefixes. RTC_DCHECK(histogram_name_prefix == "" || histogram_name_prefix == "Test" || histogram_name_prefix == "AudioMixer" || histogram_name_prefix == "Agc2"); } void FixedGainController::SetGain(float gain_to_apply_db) { // Changes in gain_to_apply_ cause discontinuities. We assume // gain_to_apply_ is set in the beginning of the call. If it is // frequently changed, we should add interpolation between the // values. // The gain RTC_DCHECK_LE(-50.f, gain_to_apply_db); RTC_DCHECK_LE(gain_to_apply_db, 50.f); const float previous_applied_gained = gain_to_apply_; gain_to_apply_ = DbToRatio(gain_to_apply_db); RTC_DCHECK_LT(0.f, gain_to_apply_); RTC_DLOG(LS_INFO) << "Gain to apply: " << gain_to_apply_db << " db."; // Reset the gain curve applier to quickly react on abrupt level changes // caused by large changes of the applied gain. if (previous_applied_gained != gain_to_apply_) { limiter_.Reset(); } } void FixedGainController::SetSampleRate(size_t sample_rate_hz) { limiter_.SetSampleRate(sample_rate_hz); } void FixedGainController::Process(AudioFrameView signal) { // Apply fixed digital gain. One of the // planned usages of the FGC is to only use the limiter. In that // case, the gain would be 1.0. Not doing the multiplications speeds // it up considerably. Hence the check. if (!CloseToOne(gain_to_apply_)) { for (size_t k = 0; k < signal.num_channels(); ++k) { rtc::ArrayView channel_view = signal.channel(k); for (auto& sample : channel_view) { sample *= gain_to_apply_; } } } // Use the limiter. limiter_.Process(signal); // Dump data for debug. const auto channel_view = signal.channel(0); apm_data_dumper_->DumpRaw("agc2_fixed_digital_gain_curve_applier", channel_view.size(), channel_view.data()); // Hard-clipping. for (size_t k = 0; k < signal.num_channels(); ++k) { rtc::ArrayView channel_view = signal.channel(k); for (auto& sample : channel_view) { sample = rtc::SafeClamp(sample, kMinFloatS16Value, kMaxFloatS16Value); } } } float FixedGainController::LastAudioLevel() const { return limiter_.LastAudioLevel(); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/gain_applier.cc0000664000175000017500000000651614475643423026746 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/gain_applier.h" #include "api/array_view.h" #include "modules/audio_processing/agc2/agc2_common.h" #include "rtc_base/numerics/safe_minmax.h" namespace webrtc { namespace { // Returns true when the gain factor is so close to 1 that it would // not affect int16 samples. bool GainCloseToOne(float gain_factor) { return 1.f - 1.f / kMaxFloatS16Value <= gain_factor && gain_factor <= 1.f + 1.f / kMaxFloatS16Value; } void ClipSignal(AudioFrameView signal) { for (size_t k = 0; k < signal.num_channels(); ++k) { rtc::ArrayView channel_view = signal.channel(k); for (auto& sample : channel_view) { sample = rtc::SafeClamp(sample, kMinFloatS16Value, kMaxFloatS16Value); } } } void ApplyGainWithRamping(float last_gain_linear, float gain_at_end_of_frame_linear, float inverse_samples_per_channel, AudioFrameView float_frame) { // Do not modify the signal. if (last_gain_linear == gain_at_end_of_frame_linear && GainCloseToOne(gain_at_end_of_frame_linear)) { return; } // Gain is constant and different from 1. if (last_gain_linear == gain_at_end_of_frame_linear) { for (size_t k = 0; k < float_frame.num_channels(); ++k) { rtc::ArrayView channel_view = float_frame.channel(k); for (auto& sample : channel_view) { sample *= gain_at_end_of_frame_linear; } } return; } // The gain changes. We have to change slowly to avoid discontinuities. const float increment = (gain_at_end_of_frame_linear - last_gain_linear) * inverse_samples_per_channel; float gain = last_gain_linear; for (size_t i = 0; i < float_frame.samples_per_channel(); ++i) { for (size_t ch = 0; ch < float_frame.num_channels(); ++ch) { float_frame.channel(ch)[i] *= gain; } gain += increment; } } } // namespace GainApplier::GainApplier(bool hard_clip_samples, float initial_gain_factor) : hard_clip_samples_(hard_clip_samples), last_gain_factor_(initial_gain_factor), current_gain_factor_(initial_gain_factor) {} void GainApplier::ApplyGain(AudioFrameView signal) { if (static_cast(signal.samples_per_channel()) != samples_per_channel_) { Initialize(signal.samples_per_channel()); } ApplyGainWithRamping(last_gain_factor_, current_gain_factor_, inverse_samples_per_channel_, signal); last_gain_factor_ = current_gain_factor_; if (hard_clip_samples_) { ClipSignal(signal); } } void GainApplier::SetGainFactor(float gain_factor) { RTC_DCHECK_GT(gain_factor, 0.f); current_gain_factor_ = gain_factor; } void GainApplier::Initialize(size_t samples_per_channel) { RTC_DCHECK_GT(samples_per_channel, 0); samples_per_channel_ = static_cast(samples_per_channel); inverse_samples_per_channel_ = 1.f / samples_per_channel_; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/gain_applier.h0000664000175000017500000000264314475643423026605 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_GAIN_APPLIER_H_ #define MODULES_AUDIO_PROCESSING_AGC2_GAIN_APPLIER_H_ #include #include "modules/audio_processing/include/audio_frame_view.h" namespace webrtc { class GainApplier { public: GainApplier(bool hard_clip_samples, float initial_gain_factor); void ApplyGain(AudioFrameView signal); void SetGainFactor(float gain_factor); float GetGainFactor() const { return current_gain_factor_; } private: void Initialize(size_t samples_per_channel); // Whether to clip samples after gain is applied. If 'true', result // will fit in FloatS16 range. const bool hard_clip_samples_; float last_gain_factor_; // If this value is not equal to 'last_gain_factor', gain will be // ramped from 'last_gain_factor_' to this value during the next // 'ApplyGain'. float current_gain_factor_; int samples_per_channel_ = -1; float inverse_samples_per_channel_ = -1.f; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_GAIN_APPLIER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/interpolated_gain_curve.cc0000664000175000017500000001635114475643423031206 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/interpolated_gain_curve.h" #include #include #include "modules/audio_processing/agc2/agc2_common.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" namespace webrtc { constexpr std::array InterpolatedGainCurve::approximation_params_x_; constexpr std::array InterpolatedGainCurve::approximation_params_m_; constexpr std::array InterpolatedGainCurve::approximation_params_q_; InterpolatedGainCurve::InterpolatedGainCurve(ApmDataDumper* apm_data_dumper, std::string histogram_name_prefix) : region_logger_("WebRTC.Audio." + histogram_name_prefix + ".FixedDigitalGainCurveRegion.Identity", "WebRTC.Audio." + histogram_name_prefix + ".FixedDigitalGainCurveRegion.Knee", "WebRTC.Audio." + histogram_name_prefix + ".FixedDigitalGainCurveRegion.Limiter", "WebRTC.Audio." + histogram_name_prefix + ".FixedDigitalGainCurveRegion.Saturation"), apm_data_dumper_(apm_data_dumper) {} InterpolatedGainCurve::~InterpolatedGainCurve() { if (stats_.available) { RTC_DCHECK(apm_data_dumper_); apm_data_dumper_->DumpRaw("agc2_interp_gain_curve_lookups_identity", stats_.look_ups_identity_region); apm_data_dumper_->DumpRaw("agc2_interp_gain_curve_lookups_knee", stats_.look_ups_knee_region); apm_data_dumper_->DumpRaw("agc2_interp_gain_curve_lookups_limiter", stats_.look_ups_limiter_region); apm_data_dumper_->DumpRaw("agc2_interp_gain_curve_lookups_saturation", stats_.look_ups_saturation_region); region_logger_.LogRegionStats(stats_); } } InterpolatedGainCurve::RegionLogger::RegionLogger( std::string identity_histogram_name, std::string knee_histogram_name, std::string limiter_histogram_name, std::string saturation_histogram_name) : identity_histogram( metrics::HistogramFactoryGetCounts(identity_histogram_name, 1, 10000, 50)), knee_histogram(metrics::HistogramFactoryGetCounts(knee_histogram_name, 1, 10000, 50)), limiter_histogram( metrics::HistogramFactoryGetCounts(limiter_histogram_name, 1, 10000, 50)), saturation_histogram( metrics::HistogramFactoryGetCounts(saturation_histogram_name, 1, 10000, 50)) {} InterpolatedGainCurve::RegionLogger::~RegionLogger() = default; void InterpolatedGainCurve::RegionLogger::LogRegionStats( const InterpolatedGainCurve::Stats& stats) const { using Region = InterpolatedGainCurve::GainCurveRegion; const int duration_s = stats.region_duration_frames / (1000 / kFrameDurationMs); switch (stats.region) { case Region::kIdentity: { if (identity_histogram) { metrics::HistogramAdd(identity_histogram, duration_s); } break; } case Region::kKnee: { if (knee_histogram) { metrics::HistogramAdd(knee_histogram, duration_s); } break; } case Region::kLimiter: { if (limiter_histogram) { metrics::HistogramAdd(limiter_histogram, duration_s); } break; } case Region::kSaturation: { if (saturation_histogram) { metrics::HistogramAdd(saturation_histogram, duration_s); } break; } default: { RTC_NOTREACHED(); } } } void InterpolatedGainCurve::UpdateStats(float input_level) const { stats_.available = true; GainCurveRegion region; if (input_level < approximation_params_x_[0]) { stats_.look_ups_identity_region++; region = GainCurveRegion::kIdentity; } else if (input_level < approximation_params_x_[kInterpolatedGainCurveKneePoints - 1]) { stats_.look_ups_knee_region++; region = GainCurveRegion::kKnee; } else if (input_level < kMaxInputLevelLinear) { stats_.look_ups_limiter_region++; region = GainCurveRegion::kLimiter; } else { stats_.look_ups_saturation_region++; region = GainCurveRegion::kSaturation; } if (region == stats_.region) { ++stats_.region_duration_frames; } else { region_logger_.LogRegionStats(stats_); stats_.region_duration_frames = 0; stats_.region = region; } } // Looks up a gain to apply given a non-negative input level. // The cost of this operation depends on the region in which |input_level| // falls. // For the identity and the saturation regions the cost is O(1). // For the other regions, namely knee and limiter, the cost is // O(2 + log2(|LightkInterpolatedGainCurveTotalPoints|), plus O(1) for the // linear interpolation (one product and one sum). float InterpolatedGainCurve::LookUpGainToApply(float input_level) const { UpdateStats(input_level); if (input_level <= approximation_params_x_[0]) { // Identity region. return 1.0f; } if (input_level >= kMaxInputLevelLinear) { // Saturating lower bound. The saturing samples exactly hit the clipping // level. This method achieves has the lowest harmonic distorsion, but it // may reduce the amplitude of the non-saturating samples too much. return 32768.f / input_level; } // Knee and limiter regions; find the linear piece index. Spelling // out the complete type was the only way to silence both the clang // plugin and the windows compilers. std::array::const_iterator it = std::lower_bound(approximation_params_x_.begin(), approximation_params_x_.end(), input_level); const size_t index = std::distance(approximation_params_x_.begin(), it) - 1; RTC_DCHECK_LE(0, index); RTC_DCHECK_LT(index, approximation_params_m_.size()); RTC_DCHECK_LE(approximation_params_x_[index], input_level); if (index < approximation_params_m_.size() - 1) { RTC_DCHECK_LE(input_level, approximation_params_x_[index + 1]); } // Piece-wise linear interploation. const float gain = approximation_params_m_[index] * input_level + approximation_params_q_[index]; RTC_DCHECK_LE(0.f, gain); return gain; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/interpolated_gain_curve.h0000664000175000017500000001444014475643423031045 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_INTERPOLATED_GAIN_CURVE_H_ #define MODULES_AUDIO_PROCESSING_AGC2_INTERPOLATED_GAIN_CURVE_H_ #include #include #include "modules/audio_processing/agc2/agc2_common.h" #include "rtc_base/constructor_magic.h" #include "rtc_base/gtest_prod_util.h" #include "system_wrappers/include/metrics.h" namespace webrtc { class ApmDataDumper; constexpr float kInputLevelScalingFactor = 32768.0f; // Defined as DbfsToLinear(kLimiterMaxInputLevelDbFs) constexpr float kMaxInputLevelLinear = static_cast(36766.300710566735); // Interpolated gain curve using under-approximation to avoid saturation. // // The goal of this class is allowing fast look ups to get an accurate // estimates of the gain to apply given an estimated input level. class InterpolatedGainCurve { public: enum class GainCurveRegion { kIdentity = 0, kKnee = 1, kLimiter = 2, kSaturation = 3 }; struct Stats { // Region in which the output level equals the input one. size_t look_ups_identity_region = 0; // Smoothing between the identity and the limiter regions. size_t look_ups_knee_region = 0; // Limiter region in which the output and input levels are linearly related. size_t look_ups_limiter_region = 0; // Region in which saturation may occur since the input level is beyond the // maximum expected by the limiter. size_t look_ups_saturation_region = 0; // True if stats have been populated. bool available = false; // The current region, and for how many frames the level has been // in that region. GainCurveRegion region = GainCurveRegion::kIdentity; int64_t region_duration_frames = 0; }; InterpolatedGainCurve(ApmDataDumper* apm_data_dumper, std::string histogram_name_prefix); ~InterpolatedGainCurve(); Stats get_stats() const { return stats_; } // Given a non-negative input level (linear scale), a scalar factor to apply // to a sub-frame is returned. // Levels above kLimiterMaxInputLevelDbFs will be reduced to 0 dBFS // after applying this gain float LookUpGainToApply(float input_level) const; private: // For comparing 'approximation_params_*_' with ones computed by // ComputeInterpolatedGainCurve. FRIEND_TEST_ALL_PREFIXES(AutomaticGainController2InterpolatedGainCurve, CheckApproximationParams); struct RegionLogger { metrics::Histogram* identity_histogram; metrics::Histogram* knee_histogram; metrics::Histogram* limiter_histogram; metrics::Histogram* saturation_histogram; RegionLogger(std::string identity_histogram_name, std::string knee_histogram_name, std::string limiter_histogram_name, std::string saturation_histogram_name); ~RegionLogger(); void LogRegionStats(const InterpolatedGainCurve::Stats& stats) const; } region_logger_; void UpdateStats(float input_level) const; ApmDataDumper* const apm_data_dumper_; static constexpr std::array approximation_params_x_ = { {30057.296875, 30148.986328125, 30240.67578125, 30424.052734375, 30607.4296875, 30790.806640625, 30974.18359375, 31157.560546875, 31340.939453125, 31524.31640625, 31707.693359375, 31891.0703125, 32074.447265625, 32257.82421875, 32441.201171875, 32624.580078125, 32807.95703125, 32991.33203125, 33174.7109375, 33358.08984375, 33541.46484375, 33724.84375, 33819.53515625, 34009.5390625, 34200.05859375, 34389.81640625, 34674.48828125, 35054.375, 35434.86328125, 35814.81640625, 36195.16796875, 36575.03125}}; static constexpr std::array approximation_params_m_ = { {-3.515235675877192989e-07, -1.050251626111275982e-06, -2.085213736791047268e-06, -3.443004743530764244e-06, -4.773849468620028347e-06, -6.077375928725814447e-06, -7.353257842623861507e-06, -8.601219633419532329e-06, -9.821013009059242904e-06, -1.101243378798244521e-05, -1.217532644659513608e-05, -1.330956911260727793e-05, -1.441507538402220234e-05, -1.549179251014720649e-05, -1.653970684856176376e-05, -1.755882840370759368e-05, -1.854918446042574942e-05, -1.951086778717581183e-05, -2.044398024736437947e-05, -2.1348627342376858e-05, -2.222496914328075945e-05, -2.265374678245279938e-05, -2.242570917587727308e-05, -2.220122041762806475e-05, -2.19802095671184361e-05, -2.176260204578284174e-05, -2.133731686626560986e-05, -2.092481918225530535e-05, -2.052459603874012828e-05, -2.013615448959171772e-05, -1.975903069251216948e-05, -1.939277899509761482e-05}}; static constexpr std::array approximation_params_q_ = { {1.010565876960754395, 1.031631827354431152, 1.062929749488830566, 1.104239225387573242, 1.144973039627075195, 1.185109615325927734, 1.224629044532775879, 1.263512492179870605, 1.301741957664489746, 1.339300632476806641, 1.376173257827758789, 1.412345528602600098, 1.447803974151611328, 1.482536554336547852, 1.516532182693481445, 1.549780607223510742, 1.582272171974182129, 1.613999366760253906, 1.644955039024353027, 1.675132393836975098, 1.704526185989379883, 1.718986630439758301, 1.711274504661560059, 1.703639745712280273, 1.696081161499023438, 1.688597679138183594, 1.673851132392883301, 1.659391283988952637, 1.645209431648254395, 1.631297469139099121, 1.617647409439086914, 1.604251742362976074}}; // Stats. mutable Stats stats_; RTC_DISALLOW_COPY_AND_ASSIGN(InterpolatedGainCurve); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_INTERPOLATED_GAIN_CURVE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/limiter.cc0000664000175000017500000001272714475643423025762 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/limiter.h" #include #include #include #include "api/array_view.h" #include "modules/audio_processing/agc2/agc2_common.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_minmax.h" namespace webrtc { namespace { // This constant affects the way scaling factors are interpolated for the first // sub-frame of a frame. Only in the case in which the first sub-frame has an // estimated level which is greater than the that of the previous analyzed // sub-frame, linear interpolation is replaced with a power function which // reduces the chances of over-shooting (and hence saturation), however reducing // the fixed gain effectiveness. constexpr float kAttackFirstSubframeInterpolationPower = 8.f; void InterpolateFirstSubframe(float last_factor, float current_factor, rtc::ArrayView subframe) { const auto n = subframe.size(); constexpr auto p = kAttackFirstSubframeInterpolationPower; for (size_t i = 0; i < n; ++i) { subframe[i] = std::pow(1.f - i / n, p) * (last_factor - current_factor) + current_factor; } } void ComputePerSampleSubframeFactors( const std::array& scaling_factors, size_t samples_per_channel, rtc::ArrayView per_sample_scaling_factors) { const size_t num_subframes = scaling_factors.size() - 1; const size_t subframe_size = rtc::CheckedDivExact(samples_per_channel, num_subframes); // Handle first sub-frame differently in case of attack. const bool is_attack = scaling_factors[0] > scaling_factors[1]; if (is_attack) { InterpolateFirstSubframe( scaling_factors[0], scaling_factors[1], rtc::ArrayView( per_sample_scaling_factors.subview(0, subframe_size))); } for (size_t i = is_attack ? 1 : 0; i < num_subframes; ++i) { const size_t subframe_start = i * subframe_size; const float scaling_start = scaling_factors[i]; const float scaling_end = scaling_factors[i + 1]; const float scaling_diff = (scaling_end - scaling_start) / subframe_size; for (size_t j = 0; j < subframe_size; ++j) { per_sample_scaling_factors[subframe_start + j] = scaling_start + scaling_diff * j; } } } void ScaleSamples(rtc::ArrayView per_sample_scaling_factors, AudioFrameView signal) { const size_t samples_per_channel = signal.samples_per_channel(); RTC_DCHECK_EQ(samples_per_channel, per_sample_scaling_factors.size()); for (size_t i = 0; i < signal.num_channels(); ++i) { auto channel = signal.channel(i); for (size_t j = 0; j < samples_per_channel; ++j) { channel[j] = rtc::SafeClamp(channel[j] * per_sample_scaling_factors[j], kMinFloatS16Value, kMaxFloatS16Value); } } } void CheckLimiterSampleRate(size_t sample_rate_hz) { // Check that per_sample_scaling_factors_ is large enough. RTC_DCHECK_LE(sample_rate_hz, kMaximalNumberOfSamplesPerChannel * 1000 / kFrameDurationMs); } } // namespace Limiter::Limiter(size_t sample_rate_hz, ApmDataDumper* apm_data_dumper, std::string histogram_name) : interp_gain_curve_(apm_data_dumper, histogram_name), level_estimator_(sample_rate_hz, apm_data_dumper), apm_data_dumper_(apm_data_dumper) { CheckLimiterSampleRate(sample_rate_hz); } Limiter::~Limiter() = default; void Limiter::Process(AudioFrameView signal) { const auto level_estimate = level_estimator_.ComputeLevel(signal); RTC_DCHECK_EQ(level_estimate.size() + 1, scaling_factors_.size()); scaling_factors_[0] = last_scaling_factor_; std::transform(level_estimate.begin(), level_estimate.end(), scaling_factors_.begin() + 1, [this](float x) { return interp_gain_curve_.LookUpGainToApply(x); }); const size_t samples_per_channel = signal.samples_per_channel(); RTC_DCHECK_LE(samples_per_channel, kMaximalNumberOfSamplesPerChannel); auto per_sample_scaling_factors = rtc::ArrayView( &per_sample_scaling_factors_[0], samples_per_channel); ComputePerSampleSubframeFactors(scaling_factors_, samples_per_channel, per_sample_scaling_factors); ScaleSamples(per_sample_scaling_factors, signal); last_scaling_factor_ = scaling_factors_.back(); // Dump data for debug. apm_data_dumper_->DumpRaw("agc2_gain_curve_applier_scaling_factors", samples_per_channel, per_sample_scaling_factors_.data()); } InterpolatedGainCurve::Stats Limiter::GetGainCurveStats() const { return interp_gain_curve_.get_stats(); } void Limiter::SetSampleRate(size_t sample_rate_hz) { CheckLimiterSampleRate(sample_rate_hz); level_estimator_.SetSampleRate(sample_rate_hz); } void Limiter::Reset() { level_estimator_.Reset(); } float Limiter::LastAudioLevel() const { return level_estimator_.LastAudioLevel(); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/limiter.h0000664000175000017500000000411614475643423025615 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_LIMITER_H_ #define MODULES_AUDIO_PROCESSING_AGC2_LIMITER_H_ #include #include #include "modules/audio_processing/agc2/fixed_digital_level_estimator.h" #include "modules/audio_processing/agc2/interpolated_gain_curve.h" #include "modules/audio_processing/include/audio_frame_view.h" #include "rtc_base/constructor_magic.h" namespace webrtc { class ApmDataDumper; class Limiter { public: Limiter(size_t sample_rate_hz, ApmDataDumper* apm_data_dumper, std::string histogram_name_prefix); Limiter(const Limiter& limiter) = delete; Limiter& operator=(const Limiter& limiter) = delete; ~Limiter(); // Applies limiter and hard-clipping to |signal|. void Process(AudioFrameView signal); InterpolatedGainCurve::Stats GetGainCurveStats() const; // Supported rates must be // * supported by FixedDigitalLevelEstimator // * below kMaximalNumberOfSamplesPerChannel*1000/kFrameDurationMs // so that samples_per_channel fit in the // per_sample_scaling_factors_ array. void SetSampleRate(size_t sample_rate_hz); // Resets the internal state. void Reset(); float LastAudioLevel() const; private: const InterpolatedGainCurve interp_gain_curve_; FixedDigitalLevelEstimator level_estimator_; ApmDataDumper* const apm_data_dumper_ = nullptr; // Work array containing the sub-frame scaling factors to be interpolated. std::array scaling_factors_ = {}; std::array per_sample_scaling_factors_ = {}; float last_scaling_factor_ = 1.f; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_LIMITER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/limiter_db_gain_curve.cc0000664000175000017500000001310014475643423030613 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/limiter_db_gain_curve.h" #include #include "common_audio/include/audio_util.h" #include "modules/audio_processing/agc2/agc2_common.h" #include "rtc_base/checks.h" namespace webrtc { namespace { double ComputeKneeStart(double max_input_level_db, double knee_smoothness_db, double compression_ratio) { RTC_CHECK_LT((compression_ratio - 1.0) * knee_smoothness_db / (2.0 * compression_ratio), max_input_level_db); return -knee_smoothness_db / 2.0 - max_input_level_db / (compression_ratio - 1.0); } std::array ComputeKneeRegionPolynomial(double knee_start_dbfs, double knee_smoothness_db, double compression_ratio) { const double a = (1.0 - compression_ratio) / (2.0 * knee_smoothness_db * compression_ratio); const double b = 1.0 - 2.0 * a * knee_start_dbfs; const double c = a * knee_start_dbfs * knee_start_dbfs; return {{a, b, c}}; } double ComputeLimiterD1(double max_input_level_db, double compression_ratio) { return (std::pow(10.0, -max_input_level_db / (20.0 * compression_ratio)) * (1.0 - compression_ratio) / compression_ratio) / kMaxAbsFloatS16Value; } constexpr double ComputeLimiterD2(double compression_ratio) { return (1.0 - 2.0 * compression_ratio) / compression_ratio; } double ComputeLimiterI2(double max_input_level_db, double compression_ratio, double gain_curve_limiter_i1) { RTC_CHECK_NE(gain_curve_limiter_i1, 0.f); return std::pow(10.0, -max_input_level_db / (20.0 * compression_ratio)) / gain_curve_limiter_i1 / std::pow(kMaxAbsFloatS16Value, gain_curve_limiter_i1 - 1); } } // namespace LimiterDbGainCurve::LimiterDbGainCurve() : max_input_level_linear_(DbfsToFloatS16(max_input_level_db_)), knee_start_dbfs_(ComputeKneeStart(max_input_level_db_, knee_smoothness_db_, compression_ratio_)), knee_start_linear_(DbfsToFloatS16(knee_start_dbfs_)), limiter_start_dbfs_(knee_start_dbfs_ + knee_smoothness_db_), limiter_start_linear_(DbfsToFloatS16(limiter_start_dbfs_)), knee_region_polynomial_(ComputeKneeRegionPolynomial(knee_start_dbfs_, knee_smoothness_db_, compression_ratio_)), gain_curve_limiter_d1_( ComputeLimiterD1(max_input_level_db_, compression_ratio_)), gain_curve_limiter_d2_(ComputeLimiterD2(compression_ratio_)), gain_curve_limiter_i1_(1.0 / compression_ratio_), gain_curve_limiter_i2_(ComputeLimiterI2(max_input_level_db_, compression_ratio_, gain_curve_limiter_i1_)) { static_assert(knee_smoothness_db_ > 0.0f, ""); static_assert(compression_ratio_ > 1.0f, ""); RTC_CHECK_GE(max_input_level_db_, knee_start_dbfs_ + knee_smoothness_db_); } constexpr double LimiterDbGainCurve::max_input_level_db_; constexpr double LimiterDbGainCurve::knee_smoothness_db_; constexpr double LimiterDbGainCurve::compression_ratio_; double LimiterDbGainCurve::GetOutputLevelDbfs(double input_level_dbfs) const { if (input_level_dbfs < knee_start_dbfs_) { return input_level_dbfs; } else if (input_level_dbfs < limiter_start_dbfs_) { return GetKneeRegionOutputLevelDbfs(input_level_dbfs); } return GetCompressorRegionOutputLevelDbfs(input_level_dbfs); } double LimiterDbGainCurve::GetGainLinear(double input_level_linear) const { if (input_level_linear < knee_start_linear_) { return 1.0; } return DbfsToFloatS16( GetOutputLevelDbfs(FloatS16ToDbfs(input_level_linear))) / input_level_linear; } // Computes the first derivative of GetGainLinear() in |x|. double LimiterDbGainCurve::GetGainFirstDerivativeLinear(double x) const { // Beyond-knee region only. RTC_CHECK_GE(x, limiter_start_linear_ - 1e-7 * kMaxAbsFloatS16Value); return gain_curve_limiter_d1_ * std::pow(x / kMaxAbsFloatS16Value, gain_curve_limiter_d2_); } // Computes the integral of GetGainLinear() in the range [x0, x1]. double LimiterDbGainCurve::GetGainIntegralLinear(double x0, double x1) const { RTC_CHECK_LE(x0, x1); // Valid interval. RTC_CHECK_GE(x0, limiter_start_linear_); // Beyond-knee region only. auto limiter_integral = [this](const double& x) { return gain_curve_limiter_i2_ * std::pow(x, gain_curve_limiter_i1_); }; return limiter_integral(x1) - limiter_integral(x0); } double LimiterDbGainCurve::GetKneeRegionOutputLevelDbfs( double input_level_dbfs) const { return knee_region_polynomial_[0] * input_level_dbfs * input_level_dbfs + knee_region_polynomial_[1] * input_level_dbfs + knee_region_polynomial_[2]; } double LimiterDbGainCurve::GetCompressorRegionOutputLevelDbfs( double input_level_dbfs) const { return (input_level_dbfs - max_input_level_db_) / compression_ratio_; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/limiter_db_gain_curve.h0000664000175000017500000000571514475643423030472 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_LIMITER_DB_GAIN_CURVE_H_ #define MODULES_AUDIO_PROCESSING_AGC2_LIMITER_DB_GAIN_CURVE_H_ #include #include "modules/audio_processing/agc2/agc2_testing_common.h" namespace webrtc { // A class for computing a limiter gain curve (in dB scale) given a set of // hard-coded parameters (namely, kLimiterDbGainCurveMaxInputLevelDbFs, // kLimiterDbGainCurveKneeSmoothnessDb, and // kLimiterDbGainCurveCompressionRatio). The generated curve consists of four // regions: identity (linear), knee (quadratic polynomial), compression // (linear), saturation (linear). The aforementioned constants are used to shape // the different regions. class LimiterDbGainCurve { public: LimiterDbGainCurve(); double max_input_level_db() const { return max_input_level_db_; } double max_input_level_linear() const { return max_input_level_linear_; } double knee_start_linear() const { return knee_start_linear_; } double limiter_start_linear() const { return limiter_start_linear_; } // These methods can be marked 'constexpr' in C++ 14. double GetOutputLevelDbfs(double input_level_dbfs) const; double GetGainLinear(double input_level_linear) const; double GetGainFirstDerivativeLinear(double x) const; double GetGainIntegralLinear(double x0, double x1) const; private: double GetKneeRegionOutputLevelDbfs(double input_level_dbfs) const; double GetCompressorRegionOutputLevelDbfs(double input_level_dbfs) const; static constexpr double max_input_level_db_ = test::kLimiterMaxInputLevelDbFs; static constexpr double knee_smoothness_db_ = test::kLimiterKneeSmoothnessDb; static constexpr double compression_ratio_ = test::kLimiterCompressionRatio; const double max_input_level_linear_; // Do not modify signal with level <= knee_start_dbfs_. const double knee_start_dbfs_; const double knee_start_linear_; // The upper end of the knee region, which is between knee_start_dbfs_ and // limiter_start_dbfs_. const double limiter_start_dbfs_; const double limiter_start_linear_; // Coefficients {a, b, c} of the knee region polynomial // ax^2 + bx + c in the DB scale. const std::array knee_region_polynomial_; // Parameters for the computation of the first derivative of GetGainLinear(). const double gain_curve_limiter_d1_; const double gain_curve_limiter_d2_; // Parameters for the computation of the integral of GetGainLinear(). const double gain_curve_limiter_i1_; const double gain_curve_limiter_i2_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_LIMITER_DB_GAIN_CURVE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/noise_level_estimator.cc0000664000175000017500000000724514475643423030707 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/noise_level_estimator.h" #include #include #include #include #include "api/array_view.h" #include "common_audio/include/audio_util.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" namespace webrtc { namespace { constexpr int kFramesPerSecond = 100; float FrameEnergy(const AudioFrameView& audio) { float energy = 0.f; for (size_t k = 0; k < audio.num_channels(); ++k) { float channel_energy = std::accumulate(audio.channel(k).begin(), audio.channel(k).end(), 0.f, [](float a, float b) -> float { return a + b * b; }); energy = std::max(channel_energy, energy); } return energy; } float EnergyToDbfs(float signal_energy, size_t num_samples) { const float rms = std::sqrt(signal_energy / num_samples); return FloatS16ToDbfs(rms); } } // namespace NoiseLevelEstimator::NoiseLevelEstimator(ApmDataDumper* data_dumper) : signal_classifier_(data_dumper) { Initialize(48000); } NoiseLevelEstimator::~NoiseLevelEstimator() {} void NoiseLevelEstimator::Initialize(int sample_rate_hz) { sample_rate_hz_ = sample_rate_hz; noise_energy_ = 1.f; first_update_ = true; min_noise_energy_ = sample_rate_hz * 2.f * 2.f / kFramesPerSecond; noise_energy_hold_counter_ = 0; signal_classifier_.Initialize(sample_rate_hz); } float NoiseLevelEstimator::Analyze(const AudioFrameView& frame) { const int rate = static_cast(frame.samples_per_channel() * kFramesPerSecond); if (rate != sample_rate_hz_) { Initialize(rate); } const float frame_energy = FrameEnergy(frame); if (frame_energy <= 0.f) { RTC_DCHECK_GE(frame_energy, 0.f); return EnergyToDbfs(noise_energy_, frame.samples_per_channel()); } if (first_update_) { // Initialize the noise energy to the frame energy. first_update_ = false; return EnergyToDbfs( noise_energy_ = std::max(frame_energy, min_noise_energy_), frame.samples_per_channel()); } const SignalClassifier::SignalType signal_type = signal_classifier_.Analyze(frame.channel(0)); // Update the noise estimate in a minimum statistics-type manner. if (signal_type == SignalClassifier::SignalType::kStationary) { if (frame_energy > noise_energy_) { // Leak the estimate upwards towards the frame energy if no recent // downward update. noise_energy_hold_counter_ = std::max(noise_energy_hold_counter_ - 1, 0); if (noise_energy_hold_counter_ == 0) { noise_energy_ = std::min(noise_energy_ * 1.01f, frame_energy); } } else { // Update smoothly downwards with a limited maximum update magnitude. noise_energy_ = std::max(noise_energy_ * 0.9f, noise_energy_ + 0.05f * (frame_energy - noise_energy_)); noise_energy_hold_counter_ = 1000; } } else { // For a non-stationary signal, leak the estimate downwards in order to // avoid estimate locking due to incorrect signal classification. noise_energy_ = noise_energy_ * 0.99f; } // Ensure a minimum of the estimate. return EnergyToDbfs( noise_energy_ = std::max(noise_energy_, min_noise_energy_), frame.samples_per_channel()); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/noise_level_estimator.h0000664000175000017500000000246714475643423030552 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_NOISE_LEVEL_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_AGC2_NOISE_LEVEL_ESTIMATOR_H_ #include "modules/audio_processing/agc2/signal_classifier.h" #include "modules/audio_processing/include/audio_frame_view.h" #include "rtc_base/constructor_magic.h" namespace webrtc { class ApmDataDumper; class NoiseLevelEstimator { public: NoiseLevelEstimator(ApmDataDumper* data_dumper); ~NoiseLevelEstimator(); // Returns the estimated noise level in dBFS. float Analyze(const AudioFrameView& frame); private: void Initialize(int sample_rate_hz); int sample_rate_hz_; float min_noise_energy_; bool first_update_; float noise_energy_; int noise_energy_hold_counter_; SignalClassifier signal_classifier_; RTC_DISALLOW_COPY_AND_ASSIGN(NoiseLevelEstimator); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_NOISE_LEVEL_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/noise_spectrum_estimator.cc0000664000175000017500000000437214475643423031440 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/noise_spectrum_estimator.h" #include #include #include "api/array_view.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/arraysize.h" #include "rtc_base/checks.h" namespace webrtc { namespace { constexpr float kMinNoisePower = 100.f; } // namespace NoiseSpectrumEstimator::NoiseSpectrumEstimator(ApmDataDumper* data_dumper) : data_dumper_(data_dumper) { Initialize(); } void NoiseSpectrumEstimator::Initialize() { std::fill(noise_spectrum_, noise_spectrum_ + arraysize(noise_spectrum_), kMinNoisePower); } void NoiseSpectrumEstimator::Update(rtc::ArrayView spectrum, bool first_update) { RTC_DCHECK_EQ(65, spectrum.size()); if (first_update) { // Initialize the noise spectral estimate with the signal spectrum. std::copy(spectrum.data(), spectrum.data() + spectrum.size(), noise_spectrum_); } else { // Smoothly update the noise spectral estimate towards the signal spectrum // such that the magnitude of the updates are limited. for (size_t k = 0; k < spectrum.size(); ++k) { if (noise_spectrum_[k] < spectrum[k]) { noise_spectrum_[k] = std::min( 1.01f * noise_spectrum_[k], noise_spectrum_[k] + 0.05f * (spectrum[k] - noise_spectrum_[k])); } else { noise_spectrum_[k] = std::max( 0.99f * noise_spectrum_[k], noise_spectrum_[k] + 0.05f * (spectrum[k] - noise_spectrum_[k])); } } } // Ensure that the noise spectal estimate does not become too low. for (auto& v : noise_spectrum_) { v = std::max(v, kMinNoisePower); } data_dumper_->DumpRaw("lc_noise_spectrum", 65, noise_spectrum_); data_dumper_->DumpRaw("lc_signal_spectrum", spectrum); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/noise_spectrum_estimator.h0000664000175000017500000000240314475643423031273 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_NOISE_SPECTRUM_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_AGC2_NOISE_SPECTRUM_ESTIMATOR_H_ #include "api/array_view.h" namespace webrtc { class ApmDataDumper; class NoiseSpectrumEstimator { public: explicit NoiseSpectrumEstimator(ApmDataDumper* data_dumper); NoiseSpectrumEstimator() = delete; NoiseSpectrumEstimator(const NoiseSpectrumEstimator&) = delete; NoiseSpectrumEstimator& operator=(const NoiseSpectrumEstimator&) = delete; void Initialize(); void Update(rtc::ArrayView spectrum, bool first_update); rtc::ArrayView GetNoiseSpectrum() const { return rtc::ArrayView(noise_spectrum_); } private: ApmDataDumper* data_dumper_; float noise_spectrum_[65]; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_NOISE_SPECTRUM_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/0000775000175000017500000000000014475643423025424 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/BUILD.gn0000664000175000017500000001273614475643423026622 0ustar00arunarun# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../../../../webrtc.gni") rtc_library("rnn_vad") { visibility = [ "../*" ] sources = [ "features_extraction.cc", "features_extraction.h", "rnn.cc", "rnn.h", ] if (rtc_build_with_neon && current_cpu != "arm64") { suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ] cflags = [ "-mfpu=neon" ] } deps = [ ":rnn_vad_common", ":rnn_vad_lp_residual", ":rnn_vad_pitch", ":rnn_vad_sequence_buffer", ":rnn_vad_spectral_features", "..:biquad_filter", "../../../../api:array_view", "../../../../api:function_view", "../../../../rtc_base:checks", "../../../../rtc_base:logging", "../../../../rtc_base/system:arch", "//third_party/rnnoise:rnn_vad", ] } rtc_library("rnn_vad_auto_correlation") { sources = [ "auto_correlation.cc", "auto_correlation.h", ] deps = [ ":rnn_vad_common", "../../../../api:array_view", "../../../../rtc_base:checks", "../../utility:pffft_wrapper", ] } rtc_library("rnn_vad_common") { # TODO(alessiob): Make this target visibility private. visibility = [ ":*", "..:rnn_vad_with_level", ] sources = [ "common.cc", "common.h", ] deps = [ "../../../../rtc_base/system:arch", "../../../../system_wrappers", ] } rtc_library("rnn_vad_lp_residual") { sources = [ "lp_residual.cc", "lp_residual.h", ] deps = [ "../../../../api:array_view", "../../../../rtc_base:checks", ] } rtc_library("rnn_vad_pitch") { sources = [ "pitch_info.h", "pitch_search.cc", "pitch_search.h", "pitch_search_internal.cc", "pitch_search_internal.h", ] deps = [ ":rnn_vad_auto_correlation", ":rnn_vad_common", "../../../../api:array_view", "../../../../rtc_base:checks", ] } rtc_source_set("rnn_vad_ring_buffer") { sources = [ "ring_buffer.h" ] deps = [ "../../../../api:array_view", "../../../../rtc_base:checks", ] } rtc_source_set("rnn_vad_sequence_buffer") { sources = [ "sequence_buffer.h" ] deps = [ "../../../../api:array_view", "../../../../rtc_base:checks", ] } rtc_library("rnn_vad_spectral_features") { sources = [ "spectral_features.cc", "spectral_features.h", "spectral_features_internal.cc", "spectral_features_internal.h", ] deps = [ ":rnn_vad_common", ":rnn_vad_ring_buffer", ":rnn_vad_symmetric_matrix_buffer", "../../../../api:array_view", "../../../../rtc_base:checks", "../../utility:pffft_wrapper", ] } rtc_source_set("rnn_vad_symmetric_matrix_buffer") { sources = [ "symmetric_matrix_buffer.h" ] deps = [ "../../../../api:array_view", "../../../../rtc_base:checks", ] } if (rtc_include_tests) { rtc_library("test_utils") { testonly = true sources = [ "test_utils.cc", "test_utils.h", ] deps = [ ":rnn_vad", ":rnn_vad_common", "../../../../api:array_view", "../../../../api:scoped_refptr", "../../../../rtc_base:checks", "../../../../rtc_base/system:arch", "../../../../system_wrappers", "../../../../test:fileutils", "../../../../test:test_support", ] } unittest_resources = [ "../../../../resources/audio_processing/agc2/rnn_vad/band_energies.dat", "../../../../resources/audio_processing/agc2/rnn_vad/pitch_buf_24k.dat", "../../../../resources/audio_processing/agc2/rnn_vad/pitch_lp_res.dat", "../../../../resources/audio_processing/agc2/rnn_vad/pitch_search_int.dat", "../../../../resources/audio_processing/agc2/rnn_vad/samples.pcm", "../../../../resources/audio_processing/agc2/rnn_vad/vad_prob.dat", ] if (is_ios) { bundle_data("unittests_bundle_data") { testonly = true sources = unittest_resources outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ] } } rtc_library("unittests") { testonly = true sources = [ "auto_correlation_unittest.cc", "features_extraction_unittest.cc", "lp_residual_unittest.cc", "pitch_search_internal_unittest.cc", "pitch_search_unittest.cc", "ring_buffer_unittest.cc", "rnn_unittest.cc", "rnn_vad_unittest.cc", "sequence_buffer_unittest.cc", "spectral_features_internal_unittest.cc", "spectral_features_unittest.cc", "symmetric_matrix_buffer_unittest.cc", ] deps = [ ":rnn_vad", ":rnn_vad_auto_correlation", ":rnn_vad_common", ":rnn_vad_lp_residual", ":rnn_vad_pitch", ":rnn_vad_ring_buffer", ":rnn_vad_sequence_buffer", ":rnn_vad_spectral_features", ":rnn_vad_symmetric_matrix_buffer", ":test_utils", "../..:audioproc_test_utils", "../../../../api:array_view", "../../../../common_audio/", "../../../../rtc_base:checks", "../../../../rtc_base:logging", "../../../../rtc_base/system:arch", "../../../../test:test_support", "../../utility:pffft_wrapper", "//third_party/rnnoise:rnn_vad", ] absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] data = unittest_resources if (is_ios) { deps += [ ":unittests_bundle_data" ] } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/auto_correlation.cc0000664000175000017500000000741714475643423031315 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/rnn_vad/auto_correlation.h" #include #include "rtc_base/checks.h" namespace webrtc { namespace rnn_vad { namespace { constexpr int kAutoCorrelationFftOrder = 9; // Length-512 FFT. static_assert(1 << kAutoCorrelationFftOrder > kNumInvertedLags12kHz + kBufSize12kHz - kMaxPitch12kHz, ""); } // namespace AutoCorrelationCalculator::AutoCorrelationCalculator() : fft_(1 << kAutoCorrelationFftOrder, Pffft::FftType::kReal), tmp_(fft_.CreateBuffer()), X_(fft_.CreateBuffer()), H_(fft_.CreateBuffer()) {} AutoCorrelationCalculator::~AutoCorrelationCalculator() = default; // The auto-correlations coefficients are computed as follows: // |.........|...........| <- pitch buffer // [ x (fixed) ] // [ y_0 ] // [ y_{m-1} ] // x and y are sub-array of equal length; x is never moved, whereas y slides. // The cross-correlation between y_0 and x corresponds to the auto-correlation // for the maximum pitch period. Hence, the first value in |auto_corr| has an // inverted lag equal to 0 that corresponds to a lag equal to the maximum // pitch period. void AutoCorrelationCalculator::ComputeOnPitchBuffer( rtc::ArrayView pitch_buf, rtc::ArrayView auto_corr) { RTC_DCHECK_LT(auto_corr.size(), kMaxPitch12kHz); RTC_DCHECK_GT(pitch_buf.size(), kMaxPitch12kHz); constexpr size_t kFftFrameSize = 1 << kAutoCorrelationFftOrder; constexpr size_t kConvolutionLength = kBufSize12kHz - kMaxPitch12kHz; static_assert(kConvolutionLength == kFrameSize20ms12kHz, "Mismatch between pitch buffer size, frame size and maximum " "pitch period."); static_assert(kFftFrameSize > kNumInvertedLags12kHz + kConvolutionLength, "The FFT length is not sufficiently big to avoid cyclic " "convolution errors."); auto tmp = tmp_->GetView(); // Compute the FFT for the reversed reference frame - i.e., // pitch_buf[-kConvolutionLength:]. std::reverse_copy(pitch_buf.end() - kConvolutionLength, pitch_buf.end(), tmp.begin()); std::fill(tmp.begin() + kConvolutionLength, tmp.end(), 0.f); fft_.ForwardTransform(*tmp_, H_.get(), /*ordered=*/false); // Compute the FFT for the sliding frames chunk. The sliding frames are // defined as pitch_buf[i:i+kConvolutionLength] where i in // [0, kNumInvertedLags12kHz). The chunk includes all of them, hence it is // defined as pitch_buf[:kNumInvertedLags12kHz+kConvolutionLength]. std::copy(pitch_buf.begin(), pitch_buf.begin() + kConvolutionLength + kNumInvertedLags12kHz, tmp.begin()); std::fill(tmp.begin() + kNumInvertedLags12kHz + kConvolutionLength, tmp.end(), 0.f); fft_.ForwardTransform(*tmp_, X_.get(), /*ordered=*/false); // Convolve in the frequency domain. constexpr float kScalingFactor = 1.f / static_cast(kFftFrameSize); std::fill(tmp.begin(), tmp.end(), 0.f); fft_.FrequencyDomainConvolve(*X_, *H_, tmp_.get(), kScalingFactor); fft_.BackwardTransform(*tmp_, tmp_.get(), /*ordered=*/false); // Extract the auto-correlation coefficients. std::copy(tmp.begin() + kConvolutionLength - 1, tmp.begin() + kConvolutionLength + kNumInvertedLags12kHz - 1, auto_corr.begin()); } } // namespace rnn_vad } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/auto_correlation.h0000664000175000017500000000317514475643423031154 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_AUTO_CORRELATION_H_ #define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_AUTO_CORRELATION_H_ #include #include "api/array_view.h" #include "modules/audio_processing/agc2/rnn_vad/common.h" #include "modules/audio_processing/utility/pffft_wrapper.h" namespace webrtc { namespace rnn_vad { // Class to compute the auto correlation on the pitch buffer for a target pitch // interval. class AutoCorrelationCalculator { public: AutoCorrelationCalculator(); AutoCorrelationCalculator(const AutoCorrelationCalculator&) = delete; AutoCorrelationCalculator& operator=(const AutoCorrelationCalculator&) = delete; ~AutoCorrelationCalculator(); // Computes the auto-correlation coefficients for a target pitch interval. // |auto_corr| indexes are inverted lags. void ComputeOnPitchBuffer( rtc::ArrayView pitch_buf, rtc::ArrayView auto_corr); private: Pffft fft_; std::unique_ptr tmp_; std::unique_ptr X_; std::unique_ptr H_; }; } // namespace rnn_vad } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_AUTO_CORRELATION_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/common.cc0000664000175000017500000000160514475643423027225 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/rnn_vad/common.h" #include "rtc_base/system/arch.h" #include "system_wrappers/include/cpu_features_wrapper.h" namespace webrtc { namespace rnn_vad { Optimization DetectOptimization() { #if defined(WEBRTC_ARCH_X86_FAMILY) if (GetCPUInfo(kSSE2) != 0) { return Optimization::kSse2; } #endif #if defined(WEBRTC_HAS_NEON) return Optimization::kNeon; #endif return Optimization::kNone; } } // namespace rnn_vad } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/common.h0000664000175000017500000000577314475643423027101 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_COMMON_H_ #define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_COMMON_H_ #include namespace webrtc { namespace rnn_vad { constexpr double kPi = 3.14159265358979323846; constexpr size_t kSampleRate24kHz = 24000; constexpr size_t kFrameSize10ms24kHz = kSampleRate24kHz / 100; constexpr size_t kFrameSize20ms24kHz = kFrameSize10ms24kHz * 2; // Pitch buffer. constexpr size_t kMinPitch24kHz = kSampleRate24kHz / 800; // 0.00125 s. constexpr size_t kMaxPitch24kHz = kSampleRate24kHz / 62.5; // 0.016 s. constexpr size_t kBufSize24kHz = kMaxPitch24kHz + kFrameSize20ms24kHz; static_assert((kBufSize24kHz & 1) == 0, "The buffer size must be even."); // 24 kHz analysis. // Define a higher minimum pitch period for the initial search. This is used to // avoid searching for very short periods, for which a refinement step is // responsible. constexpr size_t kInitialMinPitch24kHz = 3 * kMinPitch24kHz; static_assert(kMinPitch24kHz < kInitialMinPitch24kHz, ""); static_assert(kInitialMinPitch24kHz < kMaxPitch24kHz, ""); static_assert(kMaxPitch24kHz > kInitialMinPitch24kHz, ""); constexpr size_t kNumInvertedLags24kHz = kMaxPitch24kHz - kInitialMinPitch24kHz; // 12 kHz analysis. constexpr size_t kSampleRate12kHz = 12000; constexpr size_t kFrameSize10ms12kHz = kSampleRate12kHz / 100; constexpr size_t kFrameSize20ms12kHz = kFrameSize10ms12kHz * 2; constexpr size_t kBufSize12kHz = kBufSize24kHz / 2; constexpr size_t kInitialMinPitch12kHz = kInitialMinPitch24kHz / 2; constexpr size_t kMaxPitch12kHz = kMaxPitch24kHz / 2; static_assert(kMaxPitch12kHz > kInitialMinPitch12kHz, ""); // The inverted lags for the pitch interval [|kInitialMinPitch12kHz|, // |kMaxPitch12kHz|] are in the range [0, |kNumInvertedLags12kHz|]. constexpr size_t kNumInvertedLags12kHz = kMaxPitch12kHz - kInitialMinPitch12kHz; // 48 kHz constants. constexpr size_t kMinPitch48kHz = kMinPitch24kHz * 2; constexpr size_t kMaxPitch48kHz = kMaxPitch24kHz * 2; // Spectral features. constexpr size_t kNumBands = 22; constexpr size_t kNumLowerBands = 6; static_assert((0 < kNumLowerBands) && (kNumLowerBands < kNumBands), ""); constexpr size_t kCepstralCoeffsHistorySize = 8; static_assert(kCepstralCoeffsHistorySize > 2, "The history size must at least be 3 to compute first and second " "derivatives."); constexpr size_t kFeatureVectorSize = 42; enum class Optimization { kNone, kSse2, kNeon }; // Detects what kind of optimizations to use for the code. Optimization DetectOptimization(); } // namespace rnn_vad } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_COMMON_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/features_extraction.cc0000664000175000017500000000677214475643423032025 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/rnn_vad/features_extraction.h" #include #include "modules/audio_processing/agc2/rnn_vad/lp_residual.h" #include "rtc_base/checks.h" namespace webrtc { namespace rnn_vad { namespace { // Generated via "B, A = scipy.signal.butter(2, 30/12000, btype='highpass')" const BiQuadFilter::BiQuadCoefficients kHpfConfig24k = { {0.99446179f, -1.98892358f, 0.99446179f}, {-1.98889291f, 0.98895425f}}; } // namespace FeaturesExtractor::FeaturesExtractor() : use_high_pass_filter_(false), pitch_buf_24kHz_(), pitch_buf_24kHz_view_(pitch_buf_24kHz_.GetBufferView()), lp_residual_(kBufSize24kHz), lp_residual_view_(lp_residual_.data(), kBufSize24kHz), pitch_estimator_(), reference_frame_view_(pitch_buf_24kHz_.GetMostRecentValuesView()) { RTC_DCHECK_EQ(kBufSize24kHz, lp_residual_.size()); hpf_.Initialize(kHpfConfig24k); Reset(); } FeaturesExtractor::~FeaturesExtractor() = default; void FeaturesExtractor::Reset() { pitch_buf_24kHz_.Reset(); spectral_features_extractor_.Reset(); if (use_high_pass_filter_) hpf_.Reset(); } bool FeaturesExtractor::CheckSilenceComputeFeatures( rtc::ArrayView samples, rtc::ArrayView feature_vector) { // Pre-processing. if (use_high_pass_filter_) { std::array samples_filtered; hpf_.Process(samples, samples_filtered); // Feed buffer with the pre-processed version of |samples|. pitch_buf_24kHz_.Push(samples_filtered); } else { // Feed buffer with |samples|. pitch_buf_24kHz_.Push(samples); } // Extract the LP residual. float lpc_coeffs[kNumLpcCoefficients]; ComputeAndPostProcessLpcCoefficients(pitch_buf_24kHz_view_, lpc_coeffs); ComputeLpResidual(lpc_coeffs, pitch_buf_24kHz_view_, lp_residual_view_); // Estimate pitch on the LP-residual and write the normalized pitch period // into the output vector (normalization based on training data stats). pitch_info_48kHz_ = pitch_estimator_.Estimate(lp_residual_view_); feature_vector[kFeatureVectorSize - 2] = 0.01f * (static_cast(pitch_info_48kHz_.period) - 300); // Extract lagged frames (according to the estimated pitch period). RTC_DCHECK_LE(pitch_info_48kHz_.period / 2, kMaxPitch24kHz); auto lagged_frame = pitch_buf_24kHz_view_.subview( kMaxPitch24kHz - pitch_info_48kHz_.period / 2, kFrameSize20ms24kHz); // Analyze reference and lagged frames checking if silence has been detected // and write the feature vector. return spectral_features_extractor_.CheckSilenceComputeFeatures( reference_frame_view_, {lagged_frame.data(), kFrameSize20ms24kHz}, {feature_vector.data() + kNumLowerBands, kNumBands - kNumLowerBands}, {feature_vector.data(), kNumLowerBands}, {feature_vector.data() + kNumBands, kNumLowerBands}, {feature_vector.data() + kNumBands + kNumLowerBands, kNumLowerBands}, {feature_vector.data() + kNumBands + 2 * kNumLowerBands, kNumLowerBands}, &feature_vector[kFeatureVectorSize - 1]); } } // namespace rnn_vad } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/features_extraction.h0000664000175000017500000000470314475643423031657 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_FEATURES_EXTRACTION_H_ #define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_FEATURES_EXTRACTION_H_ #include #include "api/array_view.h" #include "modules/audio_processing/agc2/biquad_filter.h" #include "modules/audio_processing/agc2/rnn_vad/common.h" #include "modules/audio_processing/agc2/rnn_vad/pitch_info.h" #include "modules/audio_processing/agc2/rnn_vad/pitch_search.h" #include "modules/audio_processing/agc2/rnn_vad/sequence_buffer.h" #include "modules/audio_processing/agc2/rnn_vad/spectral_features.h" namespace webrtc { namespace rnn_vad { // Feature extractor to feed the VAD RNN. class FeaturesExtractor { public: FeaturesExtractor(); FeaturesExtractor(const FeaturesExtractor&) = delete; FeaturesExtractor& operator=(const FeaturesExtractor&) = delete; ~FeaturesExtractor(); void Reset(); // Analyzes the samples, computes the feature vector and returns true if // silence is detected (false if not). When silence is detected, // |feature_vector| is partially written and therefore must not be used to // feed the VAD RNN. bool CheckSilenceComputeFeatures( rtc::ArrayView samples, rtc::ArrayView feature_vector); private: const bool use_high_pass_filter_; // TODO(bugs.webrtc.org/7494): Remove HPF depending on how AGC2 is used in APM // and on whether an HPF is already used as pre-processing step in APM. BiQuadFilter hpf_; SequenceBuffer pitch_buf_24kHz_; rtc::ArrayView pitch_buf_24kHz_view_; std::vector lp_residual_; rtc::ArrayView lp_residual_view_; PitchEstimator pitch_estimator_; rtc::ArrayView reference_frame_view_; SpectralFeaturesExtractor spectral_features_extractor_; PitchInfo pitch_info_48kHz_; }; } // namespace rnn_vad } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_FEATURES_EXTRACTION_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/lp_residual.cc0000664000175000017500000001151214475643423030236 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/rnn_vad/lp_residual.h" #include #include #include #include #include "rtc_base/checks.h" namespace webrtc { namespace rnn_vad { namespace { // Computes cross-correlation coefficients between |x| and |y| and writes them // in |x_corr|. The lag values are in {0, ..., max_lag - 1}, where max_lag // equals the size of |x_corr|. // The |x| and |y| sub-arrays used to compute a cross-correlation coefficients // for a lag l have both size "size of |x| - l" - i.e., the longest sub-array is // used. |x| and |y| must have the same size. void ComputeCrossCorrelation( rtc::ArrayView x, rtc::ArrayView y, rtc::ArrayView x_corr) { constexpr size_t max_lag = x_corr.size(); RTC_DCHECK_EQ(x.size(), y.size()); RTC_DCHECK_LT(max_lag, x.size()); for (size_t lag = 0; lag < max_lag; ++lag) { x_corr[lag] = std::inner_product(x.begin(), x.end() - lag, y.begin() + lag, 0.f); } } // Applies denoising to the auto-correlation coefficients. void DenoiseAutoCorrelation( rtc::ArrayView auto_corr) { // Assume -40 dB white noise floor. auto_corr[0] *= 1.0001f; for (size_t i = 1; i < kNumLpcCoefficients; ++i) { auto_corr[i] -= auto_corr[i] * (0.008f * i) * (0.008f * i); } } // Computes the initial inverse filter coefficients given the auto-correlation // coefficients of an input frame. void ComputeInitialInverseFilterCoefficients( rtc::ArrayView auto_corr, rtc::ArrayView lpc_coeffs) { float error = auto_corr[0]; for (size_t i = 0; i < kNumLpcCoefficients - 1; ++i) { float reflection_coeff = 0.f; for (size_t j = 0; j < i; ++j) { reflection_coeff += lpc_coeffs[j] * auto_corr[i - j]; } reflection_coeff += auto_corr[i + 1]; // Avoid division by numbers close to zero. constexpr float kMinErrorMagnitude = 1e-6f; if (std::fabs(error) < kMinErrorMagnitude) { error = std::copysign(kMinErrorMagnitude, error); } reflection_coeff /= -error; // Update LPC coefficients and total error. lpc_coeffs[i] = reflection_coeff; for (size_t j = 0; j<(i + 1)>> 1; ++j) { const float tmp1 = lpc_coeffs[j]; const float tmp2 = lpc_coeffs[i - 1 - j]; lpc_coeffs[j] = tmp1 + reflection_coeff * tmp2; lpc_coeffs[i - 1 - j] = tmp2 + reflection_coeff * tmp1; } error -= reflection_coeff * reflection_coeff * error; if (error < 0.001f * auto_corr[0]) { break; } } } } // namespace void ComputeAndPostProcessLpcCoefficients( rtc::ArrayView x, rtc::ArrayView lpc_coeffs) { std::array auto_corr; ComputeCrossCorrelation(x, x, {auto_corr.data(), auto_corr.size()}); if (auto_corr[0] == 0.f) { // Empty frame. std::fill(lpc_coeffs.begin(), lpc_coeffs.end(), 0); return; } DenoiseAutoCorrelation({auto_corr.data(), auto_corr.size()}); std::array lpc_coeffs_pre{}; ComputeInitialInverseFilterCoefficients(auto_corr, lpc_coeffs_pre); // LPC coefficients post-processing. // TODO(bugs.webrtc.org/9076): Consider removing these steps. float c1 = 1.f; for (size_t i = 0; i < kNumLpcCoefficients - 1; ++i) { c1 *= 0.9f; lpc_coeffs_pre[i] *= c1; } const float c2 = 0.8f; lpc_coeffs[0] = lpc_coeffs_pre[0] + c2; lpc_coeffs[1] = lpc_coeffs_pre[1] + c2 * lpc_coeffs_pre[0]; lpc_coeffs[2] = lpc_coeffs_pre[2] + c2 * lpc_coeffs_pre[1]; lpc_coeffs[3] = lpc_coeffs_pre[3] + c2 * lpc_coeffs_pre[2]; lpc_coeffs[4] = c2 * lpc_coeffs_pre[3]; } void ComputeLpResidual( rtc::ArrayView lpc_coeffs, rtc::ArrayView x, rtc::ArrayView y) { RTC_DCHECK_LT(kNumLpcCoefficients, x.size()); RTC_DCHECK_EQ(x.size(), y.size()); std::array input_chunk; input_chunk.fill(0.f); for (size_t i = 0; i < y.size(); ++i) { const float sum = std::inner_product(input_chunk.begin(), input_chunk.end(), lpc_coeffs.begin(), x[i]); // Circular shift and add a new sample. for (size_t j = kNumLpcCoefficients - 1; j > 0; --j) input_chunk[j] = input_chunk[j - 1]; input_chunk[0] = x[i]; // Copy result. y[i] = sum; } } } // namespace rnn_vad } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/lp_residual.h0000664000175000017500000000254314475643423030104 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_LP_RESIDUAL_H_ #define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_LP_RESIDUAL_H_ #include #include "api/array_view.h" namespace webrtc { namespace rnn_vad { // LPC inverse filter length. constexpr size_t kNumLpcCoefficients = 5; // Given a frame |x|, computes a post-processed version of LPC coefficients // tailored for pitch estimation. void ComputeAndPostProcessLpcCoefficients( rtc::ArrayView x, rtc::ArrayView lpc_coeffs); // Computes the LP residual for the input frame |x| and the LPC coefficients // |lpc_coeffs|. |y| and |x| can point to the same array for in-place // computation. void ComputeLpResidual( rtc::ArrayView lpc_coeffs, rtc::ArrayView x, rtc::ArrayView y); } // namespace rnn_vad } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_LP_RESIDUAL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_info.h0000664000175000017500000000167314475643423027726 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_INFO_H_ #define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_INFO_H_ namespace webrtc { namespace rnn_vad { // Stores pitch period and gain information. The pitch gain measures the // strength of the pitch (the higher, the stronger). struct PitchInfo { PitchInfo() : period(0), gain(0.f) {} PitchInfo(int p, float g) : period(p), gain(g) {} int period; float gain; }; } // namespace rnn_vad } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_INFO_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search.cc0000664000175000017500000000427114475643423030373 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/rnn_vad/pitch_search.h" #include #include #include "rtc_base/checks.h" namespace webrtc { namespace rnn_vad { PitchEstimator::PitchEstimator() : pitch_buf_decimated_(kBufSize12kHz), pitch_buf_decimated_view_(pitch_buf_decimated_.data(), kBufSize12kHz), auto_corr_(kNumInvertedLags12kHz), auto_corr_view_(auto_corr_.data(), kNumInvertedLags12kHz) { RTC_DCHECK_EQ(kBufSize12kHz, pitch_buf_decimated_.size()); RTC_DCHECK_EQ(kNumInvertedLags12kHz, auto_corr_view_.size()); } PitchEstimator::~PitchEstimator() = default; PitchInfo PitchEstimator::Estimate( rtc::ArrayView pitch_buf) { // Perform the initial pitch search at 12 kHz. Decimate2x(pitch_buf, pitch_buf_decimated_view_); auto_corr_calculator_.ComputeOnPitchBuffer(pitch_buf_decimated_view_, auto_corr_view_); std::array pitch_candidates_inv_lags = FindBestPitchPeriods( auto_corr_view_, pitch_buf_decimated_view_, kMaxPitch12kHz); // Refine the pitch period estimation. // The refinement is done using the pitch buffer that contains 24 kHz samples. // Therefore, adapt the inverted lags in |pitch_candidates_inv_lags| from 12 // to 24 kHz. pitch_candidates_inv_lags[0] *= 2; pitch_candidates_inv_lags[1] *= 2; size_t pitch_inv_lag_48kHz = RefinePitchPeriod48kHz(pitch_buf, pitch_candidates_inv_lags); // Look for stronger harmonics to find the final pitch period and its gain. RTC_DCHECK_LT(pitch_inv_lag_48kHz, kMaxPitch48kHz); last_pitch_48kHz_ = CheckLowerPitchPeriodsAndComputePitchGain( pitch_buf, kMaxPitch48kHz - pitch_inv_lag_48kHz, last_pitch_48kHz_); return last_pitch_48kHz_; } } // namespace rnn_vad } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search.h0000664000175000017500000000323714475643423030236 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_SEARCH_H_ #define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_SEARCH_H_ #include #include #include "api/array_view.h" #include "modules/audio_processing/agc2/rnn_vad/auto_correlation.h" #include "modules/audio_processing/agc2/rnn_vad/common.h" #include "modules/audio_processing/agc2/rnn_vad/pitch_info.h" #include "modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h" namespace webrtc { namespace rnn_vad { // Pitch estimator. class PitchEstimator { public: PitchEstimator(); PitchEstimator(const PitchEstimator&) = delete; PitchEstimator& operator=(const PitchEstimator&) = delete; ~PitchEstimator(); // Estimates the pitch period and gain. Returns the pitch estimation data for // 48 kHz. PitchInfo Estimate(rtc::ArrayView pitch_buf); private: PitchInfo last_pitch_48kHz_; AutoCorrelationCalculator auto_corr_calculator_; std::vector pitch_buf_decimated_; rtc::ArrayView pitch_buf_decimated_view_; std::vector auto_corr_; rtc::ArrayView auto_corr_view_; }; } // namespace rnn_vad } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_SEARCH_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.cc0000664000175000017500000004144214475643423032270 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h" #include #include #include #include #include #include "modules/audio_processing/agc2/rnn_vad/common.h" #include "rtc_base/checks.h" namespace webrtc { namespace rnn_vad { namespace { // Converts a lag to an inverted lag (only for 24kHz). size_t GetInvertedLag(size_t lag) { RTC_DCHECK_LE(lag, kMaxPitch24kHz); return kMaxPitch24kHz - lag; } float ComputeAutoCorrelationCoeff(rtc::ArrayView pitch_buf, size_t inv_lag, size_t max_pitch_period) { RTC_DCHECK_LT(inv_lag, pitch_buf.size()); RTC_DCHECK_LT(max_pitch_period, pitch_buf.size()); RTC_DCHECK_LE(inv_lag, max_pitch_period); // TODO(bugs.webrtc.org/9076): Maybe optimize using vectorization. return std::inner_product(pitch_buf.begin() + max_pitch_period, pitch_buf.end(), pitch_buf.begin() + inv_lag, 0.f); } // Computes a pseudo-interpolation offset for an estimated pitch period |lag| by // looking at the auto-correlation coefficients in the neighborhood of |lag|. // (namely, |prev_auto_corr|, |lag_auto_corr| and |next_auto_corr|). The output // is a lag in {-1, 0, +1}. // TODO(bugs.webrtc.org/9076): Consider removing pseudo-i since it // is relevant only if the spectral analysis works at a sample rate that is // twice as that of the pitch buffer (not so important instead for the estimated // pitch period feature fed into the RNN). int GetPitchPseudoInterpolationOffset(size_t lag, float prev_auto_corr, float lag_auto_corr, float next_auto_corr) { const float& a = prev_auto_corr; const float& b = lag_auto_corr; const float& c = next_auto_corr; int offset = 0; if ((c - a) > 0.7f * (b - a)) { offset = 1; // |c| is the largest auto-correlation coefficient. } else if ((a - c) > 0.7f * (b - c)) { offset = -1; // |a| is the largest auto-correlation coefficient. } return offset; } // Refines a pitch period |lag| encoded as lag with pseudo-interpolation. The // output sample rate is twice as that of |lag|. size_t PitchPseudoInterpolationLagPitchBuf( size_t lag, rtc::ArrayView pitch_buf) { int offset = 0; // Cannot apply pseudo-interpolation at the boundaries. if (lag > 0 && lag < kMaxPitch24kHz) { offset = GetPitchPseudoInterpolationOffset( lag, ComputeAutoCorrelationCoeff(pitch_buf, GetInvertedLag(lag - 1), kMaxPitch24kHz), ComputeAutoCorrelationCoeff(pitch_buf, GetInvertedLag(lag), kMaxPitch24kHz), ComputeAutoCorrelationCoeff(pitch_buf, GetInvertedLag(lag + 1), kMaxPitch24kHz)); } return 2 * lag + offset; } // Refines a pitch period |inv_lag| encoded as inverted lag with // pseudo-interpolation. The output sample rate is twice as that of // |inv_lag|. size_t PitchPseudoInterpolationInvLagAutoCorr( size_t inv_lag, rtc::ArrayView auto_corr) { int offset = 0; // Cannot apply pseudo-interpolation at the boundaries. if (inv_lag > 0 && inv_lag < auto_corr.size() - 1) { offset = GetPitchPseudoInterpolationOffset(inv_lag, auto_corr[inv_lag + 1], auto_corr[inv_lag], auto_corr[inv_lag - 1]); } // TODO(bugs.webrtc.org/9076): When retraining, check if |offset| below should // be subtracted since |inv_lag| is an inverted lag but offset is a lag. return 2 * inv_lag + offset; } // Integer multipliers used in CheckLowerPitchPeriodsAndComputePitchGain() when // looking for sub-harmonics. // The values have been chosen to serve the following algorithm. Given the // initial pitch period T, we examine whether one of its harmonics is the true // fundamental frequency. We consider T/k with k in {2, ..., 15}. For each of // these harmonics, in addition to the pitch gain of itself, we choose one // multiple of its pitch period, n*T/k, to validate it (by averaging their pitch // gains). The multiplier n is chosen so that n*T/k is used only one time over // all k. When for example k = 4, we should also expect a peak at 3*T/4. When // k = 8 instead we don't want to look at 2*T/8, since we have already checked // T/4 before. Instead, we look at T*3/8. // The array can be generate in Python as follows: // from fractions import Fraction // # Smallest positive integer not in X. // def mex(X): // for i in range(1, int(max(X)+2)): // if i not in X: // return i // # Visited multiples of the period. // S = {1} // for n in range(2, 16): // sn = mex({n * i for i in S} | {1}) // S = S | {Fraction(1, n), Fraction(sn, n)} // print(sn, end=', ') constexpr std::array kSubHarmonicMultipliers = { {3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2}}; // Initial pitch period candidate thresholds for ComputePitchGainThreshold() for // a sample rate of 24 kHz. Computed as [5*k*k for k in range(16)]. constexpr std::array kInitialPitchPeriodThresholds = { {20, 45, 80, 125, 180, 245, 320, 405, 500, 605, 720, 845, 980, 1125}}; } // namespace void Decimate2x(rtc::ArrayView src, rtc::ArrayView dst) { // TODO(bugs.webrtc.org/9076): Consider adding anti-aliasing filter. static_assert(2 * dst.size() == src.size(), ""); for (size_t i = 0; i < dst.size(); ++i) { dst[i] = src[2 * i]; } } float ComputePitchGainThreshold(int candidate_pitch_period, int pitch_period_ratio, int initial_pitch_period, float initial_pitch_gain, int prev_pitch_period, float prev_pitch_gain) { // Map arguments to more compact aliases. const int& t1 = candidate_pitch_period; const int& k = pitch_period_ratio; const int& t0 = initial_pitch_period; const float& g0 = initial_pitch_gain; const int& t_prev = prev_pitch_period; const float& g_prev = prev_pitch_gain; // Validate input. RTC_DCHECK_GE(t1, 0); RTC_DCHECK_GE(k, 2); RTC_DCHECK_GE(t0, 0); RTC_DCHECK_GE(t_prev, 0); // Compute a term that lowers the threshold when |t1| is close to the last // estimated period |t_prev| - i.e., pitch tracking. float lower_threshold_term = 0; if (abs(t1 - t_prev) <= 1) { // The candidate pitch period is within 1 sample from the previous one. // Make the candidate at |t1| very easy to be accepted. lower_threshold_term = g_prev; } else if (abs(t1 - t_prev) == 2 && t0 > kInitialPitchPeriodThresholds[k - 2]) { // The candidate pitch period is 2 samples far from the previous one and the // period |t0| (from which |t1| has been derived) is greater than a // threshold. Make |t1| easy to be accepted. lower_threshold_term = 0.5f * g_prev; } // Set the threshold based on the gain of the initial estimate |t0|. Also // reduce the chance of false positives caused by a bias towards high // frequencies (originating from short-term correlations). float threshold = std::max(0.3f, 0.7f * g0 - lower_threshold_term); if (static_cast(t1) < 3 * kMinPitch24kHz) { // High frequency. threshold = std::max(0.4f, 0.85f * g0 - lower_threshold_term); } else if (static_cast(t1) < 2 * kMinPitch24kHz) { // Even higher frequency. threshold = std::max(0.5f, 0.9f * g0 - lower_threshold_term); } return threshold; } void ComputeSlidingFrameSquareEnergies( rtc::ArrayView pitch_buf, rtc::ArrayView yy_values) { float yy = ComputeAutoCorrelationCoeff(pitch_buf, kMaxPitch24kHz, kMaxPitch24kHz); yy_values[0] = yy; for (size_t i = 1; i < yy_values.size(); ++i) { RTC_DCHECK_LE(i, kMaxPitch24kHz + kFrameSize20ms24kHz); RTC_DCHECK_LE(i, kMaxPitch24kHz); const float old_coeff = pitch_buf[kMaxPitch24kHz + kFrameSize20ms24kHz - i]; const float new_coeff = pitch_buf[kMaxPitch24kHz - i]; yy -= old_coeff * old_coeff; yy += new_coeff * new_coeff; yy = std::max(0.f, yy); yy_values[i] = yy; } } std::array FindBestPitchPeriods( rtc::ArrayView auto_corr, rtc::ArrayView pitch_buf, size_t max_pitch_period) { // Stores a pitch candidate period and strength information. struct PitchCandidate { // Pitch period encoded as inverted lag. size_t period_inverted_lag = 0; // Pitch strength encoded as a ratio. float strength_numerator = -1.f; float strength_denominator = 0.f; // Compare the strength of two pitch candidates. bool HasStrongerPitchThan(const PitchCandidate& b) const { // Comparing the numerator/denominator ratios without using divisions. return strength_numerator * b.strength_denominator > b.strength_numerator * strength_denominator; } }; RTC_DCHECK_GT(max_pitch_period, auto_corr.size()); RTC_DCHECK_LT(max_pitch_period, pitch_buf.size()); const size_t frame_size = pitch_buf.size() - max_pitch_period; // TODO(bugs.webrtc.org/9076): Maybe optimize using vectorization. float yy = std::inner_product(pitch_buf.begin(), pitch_buf.begin() + frame_size + 1, pitch_buf.begin(), 1.f); // Search best and second best pitches by looking at the scaled // auto-correlation. PitchCandidate candidate; PitchCandidate best; PitchCandidate second_best; second_best.period_inverted_lag = 1; for (size_t inv_lag = 0; inv_lag < auto_corr.size(); ++inv_lag) { // A pitch candidate must have positive correlation. if (auto_corr[inv_lag] > 0) { candidate.period_inverted_lag = inv_lag; candidate.strength_numerator = auto_corr[inv_lag] * auto_corr[inv_lag]; candidate.strength_denominator = yy; if (candidate.HasStrongerPitchThan(second_best)) { if (candidate.HasStrongerPitchThan(best)) { second_best = best; best = candidate; } else { second_best = candidate; } } } // Update |squared_energy_y| for the next inverted lag. const float old_coeff = pitch_buf[inv_lag]; const float new_coeff = pitch_buf[inv_lag + frame_size]; yy -= old_coeff * old_coeff; yy += new_coeff * new_coeff; yy = std::max(0.f, yy); } return {{best.period_inverted_lag, second_best.period_inverted_lag}}; } size_t RefinePitchPeriod48kHz( rtc::ArrayView pitch_buf, rtc::ArrayView inv_lags) { // Compute the auto-correlation terms only for neighbors of the given pitch // candidates (similar to what is done in ComputePitchAutoCorrelation(), but // for a few lag values). std::array auto_corr; auto_corr.fill(0.f); // Zeros become ignored lags in FindBestPitchPeriods(). auto is_neighbor = [](size_t i, size_t j) { return ((i > j) ? (i - j) : (j - i)) <= 2; }; for (size_t inv_lag = 0; inv_lag < auto_corr.size(); ++inv_lag) { if (is_neighbor(inv_lag, inv_lags[0]) || is_neighbor(inv_lag, inv_lags[1])) auto_corr[inv_lag] = ComputeAutoCorrelationCoeff(pitch_buf, inv_lag, kMaxPitch24kHz); } // Find best pitch at 24 kHz. const auto pitch_candidates_inv_lags = FindBestPitchPeriods( {auto_corr.data(), auto_corr.size()}, {pitch_buf.data(), pitch_buf.size()}, kMaxPitch24kHz); const auto inv_lag = pitch_candidates_inv_lags[0]; // Refine the best. // Pseudo-interpolation. return PitchPseudoInterpolationInvLagAutoCorr(inv_lag, auto_corr); } PitchInfo CheckLowerPitchPeriodsAndComputePitchGain( rtc::ArrayView pitch_buf, int initial_pitch_period_48kHz, PitchInfo prev_pitch_48kHz) { RTC_DCHECK_LE(kMinPitch48kHz, initial_pitch_period_48kHz); RTC_DCHECK_LE(initial_pitch_period_48kHz, kMaxPitch48kHz); // Stores information for a refined pitch candidate. struct RefinedPitchCandidate { RefinedPitchCandidate() {} RefinedPitchCandidate(int period_24kHz, float gain, float xy, float yy) : period_24kHz(period_24kHz), gain(gain), xy(xy), yy(yy) {} int period_24kHz; // Pitch strength information. float gain; // Additional pitch strength information used for the final estimation of // pitch gain. float xy; // Cross-correlation. float yy; // Auto-correlation. }; // Initialize. std::array yy_values; ComputeSlidingFrameSquareEnergies(pitch_buf, {yy_values.data(), yy_values.size()}); const float xx = yy_values[0]; // Helper lambdas. const auto pitch_gain = [](float xy, float yy, float xx) { RTC_DCHECK_LE(0.f, xx * yy); return xy / std::sqrt(1.f + xx * yy); }; // Initial pitch candidate gain. RefinedPitchCandidate best_pitch; best_pitch.period_24kHz = std::min(initial_pitch_period_48kHz / 2, static_cast(kMaxPitch24kHz - 1)); best_pitch.xy = ComputeAutoCorrelationCoeff( pitch_buf, GetInvertedLag(best_pitch.period_24kHz), kMaxPitch24kHz); best_pitch.yy = yy_values[best_pitch.period_24kHz]; best_pitch.gain = pitch_gain(best_pitch.xy, best_pitch.yy, xx); // Store the initial pitch period information. const size_t initial_pitch_period = best_pitch.period_24kHz; const float initial_pitch_gain = best_pitch.gain; // Given the initial pitch estimation, check lower periods (i.e., harmonics). const auto alternative_period = [](int period, int k, int n) -> int { RTC_DCHECK_GT(k, 0); return (2 * n * period + k) / (2 * k); // Same as round(n*period/k). }; for (int k = 2; k < static_cast(kSubHarmonicMultipliers.size() + 2); ++k) { int candidate_pitch_period = alternative_period(initial_pitch_period, k, 1); if (static_cast(candidate_pitch_period) < kMinPitch24kHz) { break; } // When looking at |candidate_pitch_period|, we also look at one of its // sub-harmonics. |kSubHarmonicMultipliers| is used to know where to look. // |k| == 2 is a special case since |candidate_pitch_secondary_period| might // be greater than the maximum pitch period. int candidate_pitch_secondary_period = alternative_period( initial_pitch_period, k, kSubHarmonicMultipliers[k - 2]); RTC_DCHECK_GT(candidate_pitch_secondary_period, 0); if (k == 2 && candidate_pitch_secondary_period > static_cast(kMaxPitch24kHz)) { candidate_pitch_secondary_period = initial_pitch_period; } RTC_DCHECK_NE(candidate_pitch_period, candidate_pitch_secondary_period) << "The lower pitch period and the additional sub-harmonic must not " "coincide."; // Compute an auto-correlation score for the primary pitch candidate // |candidate_pitch_period| by also looking at its possible sub-harmonic // |candidate_pitch_secondary_period|. float xy_primary_period = ComputeAutoCorrelationCoeff( pitch_buf, GetInvertedLag(candidate_pitch_period), kMaxPitch24kHz); float xy_secondary_period = ComputeAutoCorrelationCoeff( pitch_buf, GetInvertedLag(candidate_pitch_secondary_period), kMaxPitch24kHz); float xy = 0.5f * (xy_primary_period + xy_secondary_period); float yy = 0.5f * (yy_values[candidate_pitch_period] + yy_values[candidate_pitch_secondary_period]); float candidate_pitch_gain = pitch_gain(xy, yy, xx); // Maybe update best period. float threshold = ComputePitchGainThreshold( candidate_pitch_period, k, initial_pitch_period, initial_pitch_gain, prev_pitch_48kHz.period / 2, prev_pitch_48kHz.gain); if (candidate_pitch_gain > threshold) { best_pitch = {candidate_pitch_period, candidate_pitch_gain, xy, yy}; } } // Final pitch gain and period. best_pitch.xy = std::max(0.f, best_pitch.xy); RTC_DCHECK_LE(0.f, best_pitch.yy); float final_pitch_gain = (best_pitch.yy <= best_pitch.xy) ? 1.f : best_pitch.xy / (best_pitch.yy + 1.f); final_pitch_gain = std::min(best_pitch.gain, final_pitch_gain); int final_pitch_period_48kHz = std::max( kMinPitch48kHz, PitchPseudoInterpolationLagPitchBuf(best_pitch.period_24kHz, pitch_buf)); return {final_pitch_period_48kHz, final_pitch_gain}; } } // namespace rnn_vad } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h0000664000175000017500000000622014475643423032125 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_SEARCH_INTERNAL_H_ #define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_SEARCH_INTERNAL_H_ #include #include #include "api/array_view.h" #include "modules/audio_processing/agc2/rnn_vad/common.h" #include "modules/audio_processing/agc2/rnn_vad/pitch_info.h" namespace webrtc { namespace rnn_vad { // Performs 2x decimation without any anti-aliasing filter. void Decimate2x(rtc::ArrayView src, rtc::ArrayView dst); // Computes a gain threshold for a candidate pitch period given the initial and // the previous pitch period and gain estimates and the pitch period ratio used // to derive the candidate pitch period from the initial period. float ComputePitchGainThreshold(int candidate_pitch_period, int pitch_period_ratio, int initial_pitch_period, float initial_pitch_gain, int prev_pitch_period, float prev_pitch_gain); // Computes the sum of squared samples for every sliding frame in the pitch // buffer. |yy_values| indexes are lags. // // The pitch buffer is structured as depicted below: // |.........|...........| // a b // The part on the left, named "a" contains the oldest samples, whereas "b" the // most recent ones. The size of "a" corresponds to the maximum pitch period, // that of "b" to the frame size (e.g., 16 ms and 20 ms respectively). void ComputeSlidingFrameSquareEnergies( rtc::ArrayView pitch_buf, rtc::ArrayView yy_values); // Given the auto-correlation coefficients stored according to // ComputePitchAutoCorrelation() (i.e., using inverted lags), returns the best // and the second best pitch periods. std::array FindBestPitchPeriods( rtc::ArrayView auto_corr, rtc::ArrayView pitch_buf, size_t max_pitch_period); // Refines the pitch period estimation given the pitch buffer |pitch_buf| and // the initial pitch period estimation |inv_lags|. Returns an inverted lag at // 48 kHz. size_t RefinePitchPeriod48kHz( rtc::ArrayView pitch_buf, rtc::ArrayView inv_lags); // Refines the pitch period estimation and compute the pitch gain. Returns the // refined pitch estimation data at 48 kHz. PitchInfo CheckLowerPitchPeriodsAndComputePitchGain( rtc::ArrayView pitch_buf, int initial_pitch_period_48kHz, PitchInfo prev_pitch_48kHz); } // namespace rnn_vad } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_SEARCH_INTERNAL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/ring_buffer.h0000664000175000017500000000415614475643423030073 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_RING_BUFFER_H_ #define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_RING_BUFFER_H_ #include #include #include #include "api/array_view.h" namespace webrtc { namespace rnn_vad { // Ring buffer for N arrays of type T each one with size S. template class RingBuffer { static_assert(S > 0, ""); static_assert(N > 0, ""); static_assert(std::is_arithmetic::value, "Integral or floating point required."); public: RingBuffer() : tail_(0) {} RingBuffer(const RingBuffer&) = delete; RingBuffer& operator=(const RingBuffer&) = delete; ~RingBuffer() = default; // Set the ring buffer values to zero. void Reset() { buffer_.fill(0); } // Replace the least recently pushed array in the buffer with |new_values|. void Push(rtc::ArrayView new_values) { std::memcpy(buffer_.data() + S * tail_, new_values.data(), S * sizeof(T)); tail_ += 1; if (tail_ == N) tail_ = 0; } // Return an array view onto the array with a given delay. A view on the last // and least recently push array is returned when |delay| is 0 and N - 1 // respectively. rtc::ArrayView GetArrayView(size_t delay) const { const int delay_int = static_cast(delay); RTC_DCHECK_LE(0, delay_int); RTC_DCHECK_LT(delay_int, N); int offset = tail_ - 1 - delay_int; if (offset < 0) offset += N; return {buffer_.data() + S * offset, S}; } private: int tail_; // Index of the least recently pushed sub-array. std::array buffer_{}; }; } // namespace rnn_vad } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_RING_BUFFER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/rnn.cc0000664000175000017500000003752014475643423026537 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/rnn_vad/rnn.h" // Defines WEBRTC_ARCH_X86_FAMILY, used below. #include "rtc_base/system/arch.h" #if defined(WEBRTC_HAS_NEON) #include #endif #if defined(WEBRTC_ARCH_X86_FAMILY) #include #endif #include #include #include #include #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "third_party/rnnoise/src/rnn_activations.h" #include "third_party/rnnoise/src/rnn_vad_weights.h" namespace webrtc { namespace rnn_vad { namespace { using rnnoise::kWeightsScale; using rnnoise::kInputLayerInputSize; static_assert(kFeatureVectorSize == kInputLayerInputSize, ""); using rnnoise::kInputDenseBias; using rnnoise::kInputDenseWeights; using rnnoise::kInputLayerOutputSize; static_assert(kInputLayerOutputSize <= kFullyConnectedLayersMaxUnits, "Increase kFullyConnectedLayersMaxUnits."); using rnnoise::kHiddenGruBias; using rnnoise::kHiddenGruRecurrentWeights; using rnnoise::kHiddenGruWeights; using rnnoise::kHiddenLayerOutputSize; static_assert(kHiddenLayerOutputSize <= kRecurrentLayersMaxUnits, "Increase kRecurrentLayersMaxUnits."); using rnnoise::kOutputDenseBias; using rnnoise::kOutputDenseWeights; using rnnoise::kOutputLayerOutputSize; static_assert(kOutputLayerOutputSize <= kFullyConnectedLayersMaxUnits, "Increase kFullyConnectedLayersMaxUnits."); using rnnoise::SigmoidApproximated; using rnnoise::TansigApproximated; inline float RectifiedLinearUnit(float x) { return x < 0.f ? 0.f : x; } std::vector GetScaledParams(rtc::ArrayView params) { std::vector scaled_params(params.size()); std::transform(params.begin(), params.end(), scaled_params.begin(), [](int8_t x) -> float { return rnnoise::kWeightsScale * static_cast(x); }); return scaled_params; } // TODO(bugs.chromium.org/10480): Hard-code optimized layout and remove this // function to improve setup time. // Casts and scales |weights| and re-arranges the layout. std::vector GetPreprocessedFcWeights( rtc::ArrayView weights, size_t output_size) { if (output_size == 1) { return GetScaledParams(weights); } // Transpose, scale and cast. const size_t input_size = rtc::CheckedDivExact(weights.size(), output_size); std::vector w(weights.size()); for (size_t o = 0; o < output_size; ++o) { for (size_t i = 0; i < input_size; ++i) { w[o * input_size + i] = rnnoise::kWeightsScale * static_cast(weights[i * output_size + o]); } } return w; } constexpr size_t kNumGruGates = 3; // Update, reset, output. // TODO(bugs.chromium.org/10480): Hard-coded optimized layout and remove this // function to improve setup time. // Casts and scales |tensor_src| for a GRU layer and re-arranges the layout. // It works both for weights, recurrent weights and bias. std::vector GetPreprocessedGruTensor( rtc::ArrayView tensor_src, size_t output_size) { // Transpose, cast and scale. // |n| is the size of the first dimension of the 3-dim tensor |weights|. const size_t n = rtc::CheckedDivExact(tensor_src.size(), output_size * kNumGruGates); const size_t stride_src = kNumGruGates * output_size; const size_t stride_dst = n * output_size; std::vector tensor_dst(tensor_src.size()); for (size_t g = 0; g < kNumGruGates; ++g) { for (size_t o = 0; o < output_size; ++o) { for (size_t i = 0; i < n; ++i) { tensor_dst[g * stride_dst + o * n + i] = rnnoise::kWeightsScale * static_cast( tensor_src[i * stride_src + g * output_size + o]); } } } return tensor_dst; } void ComputeGruUpdateResetGates(size_t input_size, size_t output_size, rtc::ArrayView weights, rtc::ArrayView recurrent_weights, rtc::ArrayView bias, rtc::ArrayView input, rtc::ArrayView state, rtc::ArrayView gate) { for (size_t o = 0; o < output_size; ++o) { gate[o] = bias[o]; for (size_t i = 0; i < input_size; ++i) { gate[o] += input[i] * weights[o * input_size + i]; } for (size_t s = 0; s < output_size; ++s) { gate[o] += state[s] * recurrent_weights[o * output_size + s]; } gate[o] = SigmoidApproximated(gate[o]); } } void ComputeGruOutputGate(size_t input_size, size_t output_size, rtc::ArrayView weights, rtc::ArrayView recurrent_weights, rtc::ArrayView bias, rtc::ArrayView input, rtc::ArrayView state, rtc::ArrayView reset, rtc::ArrayView gate) { for (size_t o = 0; o < output_size; ++o) { gate[o] = bias[o]; for (size_t i = 0; i < input_size; ++i) { gate[o] += input[i] * weights[o * input_size + i]; } for (size_t s = 0; s < output_size; ++s) { gate[o] += state[s] * recurrent_weights[o * output_size + s] * reset[s]; } gate[o] = RectifiedLinearUnit(gate[o]); } } // Gated recurrent unit (GRU) layer un-optimized implementation. void ComputeGruLayerOutput(size_t input_size, size_t output_size, rtc::ArrayView input, rtc::ArrayView weights, rtc::ArrayView recurrent_weights, rtc::ArrayView bias, rtc::ArrayView state) { RTC_DCHECK_EQ(input_size, input.size()); // Stride and offset used to read parameter arrays. const size_t stride_in = input_size * output_size; const size_t stride_out = output_size * output_size; // Update gate. std::array update; ComputeGruUpdateResetGates( input_size, output_size, weights.subview(0, stride_in), recurrent_weights.subview(0, stride_out), bias.subview(0, output_size), input, state, update); // Reset gate. std::array reset; ComputeGruUpdateResetGates( input_size, output_size, weights.subview(stride_in, stride_in), recurrent_weights.subview(stride_out, stride_out), bias.subview(output_size, output_size), input, state, reset); // Output gate. std::array output; ComputeGruOutputGate( input_size, output_size, weights.subview(2 * stride_in, stride_in), recurrent_weights.subview(2 * stride_out, stride_out), bias.subview(2 * output_size, output_size), input, state, reset, output); // Update output through the update gates and update the state. for (size_t o = 0; o < output_size; ++o) { output[o] = update[o] * state[o] + (1.f - update[o]) * output[o]; state[o] = output[o]; } } // Fully connected layer un-optimized implementation. void ComputeFullyConnectedLayerOutput( size_t input_size, size_t output_size, rtc::ArrayView input, rtc::ArrayView bias, rtc::ArrayView weights, rtc::FunctionView activation_function, rtc::ArrayView output) { RTC_DCHECK_EQ(input.size(), input_size); RTC_DCHECK_EQ(bias.size(), output_size); RTC_DCHECK_EQ(weights.size(), input_size * output_size); for (size_t o = 0; o < output_size; ++o) { output[o] = bias[o]; // TODO(bugs.chromium.org/9076): Benchmark how different layouts for // |weights_| change the performance across different platforms. for (size_t i = 0; i < input_size; ++i) { output[o] += input[i] * weights[o * input_size + i]; } output[o] = activation_function(output[o]); } } #if defined(WEBRTC_ARCH_X86_FAMILY) // Fully connected layer SSE2 implementation. void ComputeFullyConnectedLayerOutputSse2( size_t input_size, size_t output_size, rtc::ArrayView input, rtc::ArrayView bias, rtc::ArrayView weights, rtc::FunctionView activation_function, rtc::ArrayView output) { RTC_DCHECK_EQ(input.size(), input_size); RTC_DCHECK_EQ(bias.size(), output_size); RTC_DCHECK_EQ(weights.size(), input_size * output_size); const size_t input_size_by_4 = input_size >> 2; const size_t offset = input_size & ~3; __m128 sum_wx_128; const float* v = reinterpret_cast(&sum_wx_128); for (size_t o = 0; o < output_size; ++o) { // Perform 128 bit vector operations. sum_wx_128 = _mm_set1_ps(0); const float* x_p = input.data(); const float* w_p = weights.data() + o * input_size; for (size_t i = 0; i < input_size_by_4; ++i, x_p += 4, w_p += 4) { sum_wx_128 = _mm_add_ps(sum_wx_128, _mm_mul_ps(_mm_loadu_ps(x_p), _mm_loadu_ps(w_p))); } // Perform non-vector operations for any remaining items, sum up bias term // and results from the vectorized code, and apply the activation function. output[o] = activation_function( std::inner_product(input.begin() + offset, input.end(), weights.begin() + o * input_size + offset, bias[o] + v[0] + v[1] + v[2] + v[3])); } } #endif } // namespace FullyConnectedLayer::FullyConnectedLayer( const size_t input_size, const size_t output_size, const rtc::ArrayView bias, const rtc::ArrayView weights, rtc::FunctionView activation_function, Optimization optimization) : input_size_(input_size), output_size_(output_size), bias_(GetScaledParams(bias)), weights_(GetPreprocessedFcWeights(weights, output_size)), activation_function_(activation_function), optimization_(optimization) { RTC_DCHECK_LE(output_size_, kFullyConnectedLayersMaxUnits) << "Static over-allocation of fully-connected layers output vectors is " "not sufficient."; RTC_DCHECK_EQ(output_size_, bias_.size()) << "Mismatching output size and bias terms array size."; RTC_DCHECK_EQ(input_size_ * output_size_, weights_.size()) << "Mismatching input-output size and weight coefficients array size."; } FullyConnectedLayer::~FullyConnectedLayer() = default; rtc::ArrayView FullyConnectedLayer::GetOutput() const { return rtc::ArrayView(output_.data(), output_size_); } void FullyConnectedLayer::ComputeOutput(rtc::ArrayView input) { switch (optimization_) { #if defined(WEBRTC_ARCH_X86_FAMILY) case Optimization::kSse2: ComputeFullyConnectedLayerOutputSse2(input_size_, output_size_, input, bias_, weights_, activation_function_, output_); break; #endif #if defined(WEBRTC_HAS_NEON) case Optimization::kNeon: // TODO(bugs.chromium.org/10480): Handle Optimization::kNeon. ComputeFullyConnectedLayerOutput(input_size_, output_size_, input, bias_, weights_, activation_function_, output_); break; #endif default: ComputeFullyConnectedLayerOutput(input_size_, output_size_, input, bias_, weights_, activation_function_, output_); } } GatedRecurrentLayer::GatedRecurrentLayer( const size_t input_size, const size_t output_size, const rtc::ArrayView bias, const rtc::ArrayView weights, const rtc::ArrayView recurrent_weights, Optimization optimization) : input_size_(input_size), output_size_(output_size), bias_(GetPreprocessedGruTensor(bias, output_size)), weights_(GetPreprocessedGruTensor(weights, output_size)), recurrent_weights_( GetPreprocessedGruTensor(recurrent_weights, output_size)), optimization_(optimization) { RTC_DCHECK_LE(output_size_, kRecurrentLayersMaxUnits) << "Static over-allocation of recurrent layers state vectors is not " "sufficient."; RTC_DCHECK_EQ(kNumGruGates * output_size_, bias_.size()) << "Mismatching output size and bias terms array size."; RTC_DCHECK_EQ(kNumGruGates * input_size_ * output_size_, weights_.size()) << "Mismatching input-output size and weight coefficients array size."; RTC_DCHECK_EQ(kNumGruGates * output_size_ * output_size_, recurrent_weights_.size()) << "Mismatching input-output size and recurrent weight coefficients array" " size."; Reset(); } GatedRecurrentLayer::~GatedRecurrentLayer() = default; rtc::ArrayView GatedRecurrentLayer::GetOutput() const { return rtc::ArrayView(state_.data(), output_size_); } void GatedRecurrentLayer::Reset() { state_.fill(0.f); } void GatedRecurrentLayer::ComputeOutput(rtc::ArrayView input) { switch (optimization_) { #if defined(WEBRTC_ARCH_X86_FAMILY) case Optimization::kSse2: // TODO(bugs.chromium.org/10480): Handle Optimization::kSse2. ComputeGruLayerOutput(input_size_, output_size_, input, weights_, recurrent_weights_, bias_, state_); break; #endif #if defined(WEBRTC_HAS_NEON) case Optimization::kNeon: // TODO(bugs.chromium.org/10480): Handle Optimization::kNeon. ComputeGruLayerOutput(input_size_, output_size_, input, weights_, recurrent_weights_, bias_, state_); break; #endif default: ComputeGruLayerOutput(input_size_, output_size_, input, weights_, recurrent_weights_, bias_, state_); } } RnnBasedVad::RnnBasedVad() : input_layer_(kInputLayerInputSize, kInputLayerOutputSize, kInputDenseBias, kInputDenseWeights, TansigApproximated, DetectOptimization()), hidden_layer_(kInputLayerOutputSize, kHiddenLayerOutputSize, kHiddenGruBias, kHiddenGruWeights, kHiddenGruRecurrentWeights, DetectOptimization()), output_layer_(kHiddenLayerOutputSize, kOutputLayerOutputSize, kOutputDenseBias, kOutputDenseWeights, SigmoidApproximated, DetectOptimization()) { // Input-output chaining size checks. RTC_DCHECK_EQ(input_layer_.output_size(), hidden_layer_.input_size()) << "The input and the hidden layers sizes do not match."; RTC_DCHECK_EQ(hidden_layer_.output_size(), output_layer_.input_size()) << "The hidden and the output layers sizes do not match."; } RnnBasedVad::~RnnBasedVad() = default; void RnnBasedVad::Reset() { hidden_layer_.Reset(); } float RnnBasedVad::ComputeVadProbability( rtc::ArrayView feature_vector, bool is_silence) { if (is_silence) { Reset(); return 0.f; } input_layer_.ComputeOutput(feature_vector); hidden_layer_.ComputeOutput(input_layer_.GetOutput()); output_layer_.ComputeOutput(hidden_layer_.GetOutput()); const auto vad_output = output_layer_.GetOutput(); return vad_output[0]; } } // namespace rnn_vad } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/rnn.h0000664000175000017500000001125214475643423026373 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_RNN_H_ #define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_RNN_H_ #include #include #include #include #include "api/array_view.h" #include "api/function_view.h" #include "modules/audio_processing/agc2/rnn_vad/common.h" #include "rtc_base/system/arch.h" namespace webrtc { namespace rnn_vad { // Maximum number of units for a fully-connected layer. This value is used to // over-allocate space for fully-connected layers output vectors (implemented as // std::array). The value should equal the number of units of the largest // fully-connected layer. constexpr size_t kFullyConnectedLayersMaxUnits = 24; // Maximum number of units for a recurrent layer. This value is used to // over-allocate space for recurrent layers state vectors (implemented as // std::array). The value should equal the number of units of the largest // recurrent layer. constexpr size_t kRecurrentLayersMaxUnits = 24; // Fully-connected layer. class FullyConnectedLayer { public: FullyConnectedLayer(size_t input_size, size_t output_size, rtc::ArrayView bias, rtc::ArrayView weights, rtc::FunctionView activation_function, Optimization optimization); FullyConnectedLayer(const FullyConnectedLayer&) = delete; FullyConnectedLayer& operator=(const FullyConnectedLayer&) = delete; ~FullyConnectedLayer(); size_t input_size() const { return input_size_; } size_t output_size() const { return output_size_; } Optimization optimization() const { return optimization_; } rtc::ArrayView GetOutput() const; // Computes the fully-connected layer output. void ComputeOutput(rtc::ArrayView input); private: const size_t input_size_; const size_t output_size_; const std::vector bias_; const std::vector weights_; rtc::FunctionView activation_function_; // The output vector of a recurrent layer has length equal to |output_size_|. // However, for efficiency, over-allocation is used. std::array output_; const Optimization optimization_; }; // Recurrent layer with gated recurrent units (GRUs) with sigmoid and ReLU as // activation functions for the update/reset and output gates respectively. class GatedRecurrentLayer { public: GatedRecurrentLayer(size_t input_size, size_t output_size, rtc::ArrayView bias, rtc::ArrayView weights, rtc::ArrayView recurrent_weights, Optimization optimization); GatedRecurrentLayer(const GatedRecurrentLayer&) = delete; GatedRecurrentLayer& operator=(const GatedRecurrentLayer&) = delete; ~GatedRecurrentLayer(); size_t input_size() const { return input_size_; } size_t output_size() const { return output_size_; } Optimization optimization() const { return optimization_; } rtc::ArrayView GetOutput() const; void Reset(); // Computes the recurrent layer output and updates the status. void ComputeOutput(rtc::ArrayView input); private: const size_t input_size_; const size_t output_size_; const std::vector bias_; const std::vector weights_; const std::vector recurrent_weights_; // The state vector of a recurrent layer has length equal to |output_size_|. // However, to avoid dynamic allocation, over-allocation is used. std::array state_; const Optimization optimization_; }; // Recurrent network based VAD. class RnnBasedVad { public: RnnBasedVad(); RnnBasedVad(const RnnBasedVad&) = delete; RnnBasedVad& operator=(const RnnBasedVad&) = delete; ~RnnBasedVad(); void Reset(); // Compute and returns the probability of voice (range: [0.0, 1.0]). float ComputeVadProbability( rtc::ArrayView feature_vector, bool is_silence); private: FullyConnectedLayer input_layer_; GatedRecurrentLayer hidden_layer_; FullyConnectedLayer output_layer_; }; } // namespace rnn_vad } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_RNN_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/sequence_buffer.h0000664000175000017500000000555714475643423030752 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SEQUENCE_BUFFER_H_ #define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SEQUENCE_BUFFER_H_ #include #include #include #include #include "api/array_view.h" #include "rtc_base/checks.h" namespace webrtc { namespace rnn_vad { // Linear buffer implementation to (i) push fixed size chunks of sequential data // and (ii) view contiguous parts of the buffer. The buffer and the pushed // chunks have size S and N respectively. For instance, when S = 2N the first // half of the sequence buffer is replaced with its second half, and the new N // values are written at the end of the buffer. // The class also provides a view on the most recent M values, where 0 < M <= S // and by default M = N. template class SequenceBuffer { static_assert(N <= S, "The new chunk size cannot be larger than the sequence buffer " "size."); static_assert(std::is_arithmetic::value, "Integral or floating point required."); public: SequenceBuffer() : buffer_(S) { RTC_DCHECK_EQ(S, buffer_.size()); Reset(); } SequenceBuffer(const SequenceBuffer&) = delete; SequenceBuffer& operator=(const SequenceBuffer&) = delete; ~SequenceBuffer() = default; size_t size() const { return S; } size_t chunks_size() const { return N; } // Sets the sequence buffer values to zero. void Reset() { std::fill(buffer_.begin(), buffer_.end(), 0); } // Returns a view on the whole buffer. rtc::ArrayView GetBufferView() const { return {buffer_.data(), S}; } // Returns a view on the M most recent values of the buffer. rtc::ArrayView GetMostRecentValuesView() const { static_assert(M <= S, "The number of most recent values cannot be larger than the " "sequence buffer size."); return {buffer_.data() + S - M, M}; } // Shifts left the buffer by N items and add new N items at the end. void Push(rtc::ArrayView new_values) { // Make space for the new values. if (S > N) std::memmove(buffer_.data(), buffer_.data() + N, (S - N) * sizeof(T)); // Copy the new values at the end of the buffer. std::memcpy(buffer_.data() + S - N, new_values.data(), N * sizeof(T)); } private: std::vector buffer_; }; } // namespace rnn_vad } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SEQUENCE_BUFFER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features.cc0000664000175000017500000002122714475643423031452 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/rnn_vad/spectral_features.h" #include #include #include #include #include "rtc_base/checks.h" namespace webrtc { namespace rnn_vad { namespace { constexpr float kSilenceThreshold = 0.04f; // Computes the new cepstral difference stats and pushes them into the passed // symmetric matrix buffer. void UpdateCepstralDifferenceStats( rtc::ArrayView new_cepstral_coeffs, const RingBuffer& ring_buf, SymmetricMatrixBuffer* sym_matrix_buf) { RTC_DCHECK(sym_matrix_buf); // Compute the new cepstral distance stats. std::array distances; for (size_t i = 0; i < kCepstralCoeffsHistorySize - 1; ++i) { const size_t delay = i + 1; auto old_cepstral_coeffs = ring_buf.GetArrayView(delay); distances[i] = 0.f; for (size_t k = 0; k < kNumBands; ++k) { const float c = new_cepstral_coeffs[k] - old_cepstral_coeffs[k]; distances[i] += c * c; } } // Push the new spectral distance stats into the symmetric matrix buffer. sym_matrix_buf->Push(distances); } // Computes the first half of the Vorbis window. std::array ComputeScaledHalfVorbisWindow( float scaling = 1.f) { constexpr size_t kHalfSize = kFrameSize20ms24kHz / 2; std::array half_window{}; for (size_t i = 0; i < kHalfSize; ++i) { half_window[i] = scaling * std::sin(0.5 * kPi * std::sin(0.5 * kPi * (i + 0.5) / kHalfSize) * std::sin(0.5 * kPi * (i + 0.5) / kHalfSize)); } return half_window; } // Computes the forward FFT on a 20 ms frame to which a given window function is // applied. The Fourier coefficient corresponding to the Nyquist frequency is // set to zero (it is never used and this allows to simplify the code). void ComputeWindowedForwardFft( rtc::ArrayView frame, const std::array& half_window, Pffft::FloatBuffer* fft_input_buffer, Pffft::FloatBuffer* fft_output_buffer, Pffft* fft) { RTC_DCHECK_EQ(frame.size(), 2 * half_window.size()); // Apply windowing. auto in = fft_input_buffer->GetView(); for (size_t i = 0, j = kFrameSize20ms24kHz - 1; i < half_window.size(); ++i, --j) { in[i] = frame[i] * half_window[i]; in[j] = frame[j] * half_window[i]; } fft->ForwardTransform(*fft_input_buffer, fft_output_buffer, /*ordered=*/true); // Set the Nyquist frequency coefficient to zero. auto out = fft_output_buffer->GetView(); out[1] = 0.f; } } // namespace SpectralFeaturesExtractor::SpectralFeaturesExtractor() : half_window_(ComputeScaledHalfVorbisWindow( 1.f / static_cast(kFrameSize20ms24kHz))), fft_(kFrameSize20ms24kHz, Pffft::FftType::kReal), fft_buffer_(fft_.CreateBuffer()), reference_frame_fft_(fft_.CreateBuffer()), lagged_frame_fft_(fft_.CreateBuffer()), dct_table_(ComputeDctTable()) {} SpectralFeaturesExtractor::~SpectralFeaturesExtractor() = default; void SpectralFeaturesExtractor::Reset() { cepstral_coeffs_ring_buf_.Reset(); cepstral_diffs_buf_.Reset(); } bool SpectralFeaturesExtractor::CheckSilenceComputeFeatures( rtc::ArrayView reference_frame, rtc::ArrayView lagged_frame, rtc::ArrayView higher_bands_cepstrum, rtc::ArrayView average, rtc::ArrayView first_derivative, rtc::ArrayView second_derivative, rtc::ArrayView bands_cross_corr, float* variability) { // Compute the Opus band energies for the reference frame. ComputeWindowedForwardFft(reference_frame, half_window_, fft_buffer_.get(), reference_frame_fft_.get(), &fft_); spectral_correlator_.ComputeAutoCorrelation( reference_frame_fft_->GetConstView(), reference_frame_bands_energy_); // Check if the reference frame has silence. const float tot_energy = std::accumulate(reference_frame_bands_energy_.begin(), reference_frame_bands_energy_.end(), 0.f); if (tot_energy < kSilenceThreshold) { return true; } // Compute the Opus band energies for the lagged frame. ComputeWindowedForwardFft(lagged_frame, half_window_, fft_buffer_.get(), lagged_frame_fft_.get(), &fft_); spectral_correlator_.ComputeAutoCorrelation(lagged_frame_fft_->GetConstView(), lagged_frame_bands_energy_); // Log of the band energies for the reference frame. std::array log_bands_energy; ComputeSmoothedLogMagnitudeSpectrum(reference_frame_bands_energy_, log_bands_energy); // Reference frame cepstrum. std::array cepstrum; ComputeDct(log_bands_energy, dct_table_, cepstrum); // Ad-hoc correction terms for the first two cepstral coefficients. cepstrum[0] -= 12.f; cepstrum[1] -= 4.f; // Update the ring buffer and the cepstral difference stats. cepstral_coeffs_ring_buf_.Push(cepstrum); UpdateCepstralDifferenceStats(cepstrum, cepstral_coeffs_ring_buf_, &cepstral_diffs_buf_); // Write the higher bands cepstral coefficients. RTC_DCHECK_EQ(cepstrum.size() - kNumLowerBands, higher_bands_cepstrum.size()); std::copy(cepstrum.begin() + kNumLowerBands, cepstrum.end(), higher_bands_cepstrum.begin()); // Compute and write remaining features. ComputeAvgAndDerivatives(average, first_derivative, second_derivative); ComputeNormalizedCepstralCorrelation(bands_cross_corr); RTC_DCHECK(variability); *variability = ComputeVariability(); return false; } void SpectralFeaturesExtractor::ComputeAvgAndDerivatives( rtc::ArrayView average, rtc::ArrayView first_derivative, rtc::ArrayView second_derivative) const { auto curr = cepstral_coeffs_ring_buf_.GetArrayView(0); auto prev1 = cepstral_coeffs_ring_buf_.GetArrayView(1); auto prev2 = cepstral_coeffs_ring_buf_.GetArrayView(2); RTC_DCHECK_EQ(average.size(), first_derivative.size()); RTC_DCHECK_EQ(first_derivative.size(), second_derivative.size()); RTC_DCHECK_LE(average.size(), curr.size()); for (size_t i = 0; i < average.size(); ++i) { // Average, kernel: [1, 1, 1]. average[i] = curr[i] + prev1[i] + prev2[i]; // First derivative, kernel: [1, 0, - 1]. first_derivative[i] = curr[i] - prev2[i]; // Second derivative, Laplacian kernel: [1, -2, 1]. second_derivative[i] = curr[i] - 2 * prev1[i] + prev2[i]; } } void SpectralFeaturesExtractor::ComputeNormalizedCepstralCorrelation( rtc::ArrayView bands_cross_corr) { spectral_correlator_.ComputeCrossCorrelation( reference_frame_fft_->GetConstView(), lagged_frame_fft_->GetConstView(), bands_cross_corr_); // Normalize. for (size_t i = 0; i < bands_cross_corr_.size(); ++i) { bands_cross_corr_[i] = bands_cross_corr_[i] / std::sqrt(0.001f + reference_frame_bands_energy_[i] * lagged_frame_bands_energy_[i]); } // Cepstrum. ComputeDct(bands_cross_corr_, dct_table_, bands_cross_corr); // Ad-hoc correction terms for the first two cepstral coefficients. bands_cross_corr[0] -= 1.3f; bands_cross_corr[1] -= 0.9f; } float SpectralFeaturesExtractor::ComputeVariability() const { // Compute cepstral variability score. float variability = 0.f; for (size_t delay1 = 0; delay1 < kCepstralCoeffsHistorySize; ++delay1) { float min_dist = std::numeric_limits::max(); for (size_t delay2 = 0; delay2 < kCepstralCoeffsHistorySize; ++delay2) { if (delay1 == delay2) // The distance would be 0. continue; min_dist = std::min(min_dist, cepstral_diffs_buf_.GetValue(delay1, delay2)); } variability += min_dist; } // Normalize (based on training set stats). // TODO(bugs.webrtc.org/10480): Isolate normalization from feature extraction. return variability / kCepstralCoeffsHistorySize - 2.1f; } } // namespace rnn_vad } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features.h0000664000175000017500000000637714475643423031325 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SPECTRAL_FEATURES_H_ #define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SPECTRAL_FEATURES_H_ #include #include #include #include #include "api/array_view.h" #include "modules/audio_processing/agc2/rnn_vad/common.h" #include "modules/audio_processing/agc2/rnn_vad/ring_buffer.h" #include "modules/audio_processing/agc2/rnn_vad/spectral_features_internal.h" #include "modules/audio_processing/agc2/rnn_vad/symmetric_matrix_buffer.h" #include "modules/audio_processing/utility/pffft_wrapper.h" namespace webrtc { namespace rnn_vad { // Class to compute spectral features. class SpectralFeaturesExtractor { public: SpectralFeaturesExtractor(); SpectralFeaturesExtractor(const SpectralFeaturesExtractor&) = delete; SpectralFeaturesExtractor& operator=(const SpectralFeaturesExtractor&) = delete; ~SpectralFeaturesExtractor(); // Resets the internal state of the feature extractor. void Reset(); // Analyzes a pair of reference and lagged frames from the pitch buffer, // detects silence and computes features. If silence is detected, the output // is neither computed nor written. bool CheckSilenceComputeFeatures( rtc::ArrayView reference_frame, rtc::ArrayView lagged_frame, rtc::ArrayView higher_bands_cepstrum, rtc::ArrayView average, rtc::ArrayView first_derivative, rtc::ArrayView second_derivative, rtc::ArrayView bands_cross_corr, float* variability); private: void ComputeAvgAndDerivatives( rtc::ArrayView average, rtc::ArrayView first_derivative, rtc::ArrayView second_derivative) const; void ComputeNormalizedCepstralCorrelation( rtc::ArrayView bands_cross_corr); float ComputeVariability() const; const std::array half_window_; Pffft fft_; std::unique_ptr fft_buffer_; std::unique_ptr reference_frame_fft_; std::unique_ptr lagged_frame_fft_; SpectralCorrelator spectral_correlator_; std::array reference_frame_bands_energy_; std::array lagged_frame_bands_energy_; std::array bands_cross_corr_; const std::array dct_table_; RingBuffer cepstral_coeffs_ring_buf_; SymmetricMatrixBuffer cepstral_diffs_buf_; }; } // namespace rnn_vad } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SPECTRAL_FEATURES_H_ ././@PaxHeader0000000000000000000000000000020600000000000010213 xustar00112 path=webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.cc 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.0000664000175000017500000001770514475643423033046 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/rnn_vad/spectral_features_internal.h" #include #include #include #include "rtc_base/checks.h" namespace webrtc { namespace rnn_vad { namespace { // Weights for each FFT coefficient for each Opus band (Nyquist frequency // excluded). The size of each band is specified in // |kOpusScaleNumBins24kHz20ms|. constexpr std::array kOpusBandWeights24kHz20ms = {{ 0.f, 0.25f, 0.5f, 0.75f, // Band 0 0.f, 0.25f, 0.5f, 0.75f, // Band 1 0.f, 0.25f, 0.5f, 0.75f, // Band 2 0.f, 0.25f, 0.5f, 0.75f, // Band 3 0.f, 0.25f, 0.5f, 0.75f, // Band 4 0.f, 0.25f, 0.5f, 0.75f, // Band 5 0.f, 0.25f, 0.5f, 0.75f, // Band 6 0.f, 0.25f, 0.5f, 0.75f, // Band 7 0.f, 0.125f, 0.25f, 0.375f, 0.5f, 0.625f, 0.75f, 0.875f, // Band 8 0.f, 0.125f, 0.25f, 0.375f, 0.5f, 0.625f, 0.75f, 0.875f, // Band 9 0.f, 0.125f, 0.25f, 0.375f, 0.5f, 0.625f, 0.75f, 0.875f, // Band 10 0.f, 0.125f, 0.25f, 0.375f, 0.5f, 0.625f, 0.75f, 0.875f, // Band 11 0.f, 0.0625f, 0.125f, 0.1875f, 0.25f, 0.3125f, 0.375f, 0.4375f, 0.5f, 0.5625f, 0.625f, 0.6875f, 0.75f, 0.8125f, 0.875f, 0.9375f, // Band 12 0.f, 0.0625f, 0.125f, 0.1875f, 0.25f, 0.3125f, 0.375f, 0.4375f, 0.5f, 0.5625f, 0.625f, 0.6875f, 0.75f, 0.8125f, 0.875f, 0.9375f, // Band 13 0.f, 0.0625f, 0.125f, 0.1875f, 0.25f, 0.3125f, 0.375f, 0.4375f, 0.5f, 0.5625f, 0.625f, 0.6875f, 0.75f, 0.8125f, 0.875f, 0.9375f, // Band 14 0.f, 0.0416667f, 0.0833333f, 0.125f, 0.166667f, 0.208333f, 0.25f, 0.291667f, 0.333333f, 0.375f, 0.416667f, 0.458333f, 0.5f, 0.541667f, 0.583333f, 0.625f, 0.666667f, 0.708333f, 0.75f, 0.791667f, 0.833333f, 0.875f, 0.916667f, 0.958333f, // Band 15 0.f, 0.0416667f, 0.0833333f, 0.125f, 0.166667f, 0.208333f, 0.25f, 0.291667f, 0.333333f, 0.375f, 0.416667f, 0.458333f, 0.5f, 0.541667f, 0.583333f, 0.625f, 0.666667f, 0.708333f, 0.75f, 0.791667f, 0.833333f, 0.875f, 0.916667f, 0.958333f, // Band 16 0.f, 0.03125f, 0.0625f, 0.09375f, 0.125f, 0.15625f, 0.1875f, 0.21875f, 0.25f, 0.28125f, 0.3125f, 0.34375f, 0.375f, 0.40625f, 0.4375f, 0.46875f, 0.5f, 0.53125f, 0.5625f, 0.59375f, 0.625f, 0.65625f, 0.6875f, 0.71875f, 0.75f, 0.78125f, 0.8125f, 0.84375f, 0.875f, 0.90625f, 0.9375f, 0.96875f, // Band 17 0.f, 0.0208333f, 0.0416667f, 0.0625f, 0.0833333f, 0.104167f, 0.125f, 0.145833f, 0.166667f, 0.1875f, 0.208333f, 0.229167f, 0.25f, 0.270833f, 0.291667f, 0.3125f, 0.333333f, 0.354167f, 0.375f, 0.395833f, 0.416667f, 0.4375f, 0.458333f, 0.479167f, 0.5f, 0.520833f, 0.541667f, 0.5625f, 0.583333f, 0.604167f, 0.625f, 0.645833f, 0.666667f, 0.6875f, 0.708333f, 0.729167f, 0.75f, 0.770833f, 0.791667f, 0.8125f, 0.833333f, 0.854167f, 0.875f, 0.895833f, 0.916667f, 0.9375f, 0.958333f, 0.979167f // Band 18 }}; } // namespace SpectralCorrelator::SpectralCorrelator() : weights_(kOpusBandWeights24kHz20ms.begin(), kOpusBandWeights24kHz20ms.end()) {} SpectralCorrelator::~SpectralCorrelator() = default; void SpectralCorrelator::ComputeAutoCorrelation( rtc::ArrayView x, rtc::ArrayView auto_corr) const { ComputeCrossCorrelation(x, x, auto_corr); } void SpectralCorrelator::ComputeCrossCorrelation( rtc::ArrayView x, rtc::ArrayView y, rtc::ArrayView cross_corr) const { RTC_DCHECK_EQ(x.size(), kFrameSize20ms24kHz); RTC_DCHECK_EQ(x.size(), y.size()); RTC_DCHECK_EQ(x[1], 0.f) << "The Nyquist coefficient must be zeroed."; RTC_DCHECK_EQ(y[1], 0.f) << "The Nyquist coefficient must be zeroed."; constexpr auto kOpusScaleNumBins24kHz20ms = GetOpusScaleNumBins24kHz20ms(); size_t k = 0; // Next Fourier coefficient index. cross_corr[0] = 0.f; for (size_t i = 0; i < kOpusBands24kHz - 1; ++i) { cross_corr[i + 1] = 0.f; for (int j = 0; j < kOpusScaleNumBins24kHz20ms[i]; ++j) { // Band size. const float v = x[2 * k] * y[2 * k] + x[2 * k + 1] * y[2 * k + 1]; const float tmp = weights_[k] * v; cross_corr[i] += v - tmp; cross_corr[i + 1] += tmp; k++; } } cross_corr[0] *= 2.f; // The first band only gets half contribution. RTC_DCHECK_EQ(k, kFrameSize20ms24kHz / 2); // Nyquist coefficient never used. } void ComputeSmoothedLogMagnitudeSpectrum( rtc::ArrayView bands_energy, rtc::ArrayView log_bands_energy) { RTC_DCHECK_LE(bands_energy.size(), kNumBands); constexpr float kOneByHundred = 1e-2f; constexpr float kLogOneByHundred = -2.f; // Init. float log_max = kLogOneByHundred; float follow = kLogOneByHundred; const auto smooth = [&log_max, &follow](float x) { x = std::max(log_max - 7.f, std::max(follow - 1.5f, x)); log_max = std::max(log_max, x); follow = std::max(follow - 1.5f, x); return x; }; // Smoothing over the bands for which the band energy is defined. for (size_t i = 0; i < bands_energy.size(); ++i) { log_bands_energy[i] = smooth(std::log10(kOneByHundred + bands_energy[i])); } // Smoothing over the remaining bands (zero energy). for (size_t i = bands_energy.size(); i < kNumBands; ++i) { log_bands_energy[i] = smooth(kLogOneByHundred); } } std::array ComputeDctTable() { std::array dct_table; const double k = std::sqrt(0.5); for (size_t i = 0; i < kNumBands; ++i) { for (size_t j = 0; j < kNumBands; ++j) dct_table[i * kNumBands + j] = std::cos((i + 0.5) * j * kPi / kNumBands); dct_table[i * kNumBands] *= k; } return dct_table; } void ComputeDct(rtc::ArrayView in, rtc::ArrayView dct_table, rtc::ArrayView out) { // DCT scaling factor - i.e., sqrt(2 / kNumBands). constexpr float kDctScalingFactor = 0.301511345f; constexpr float kDctScalingFactorError = kDctScalingFactor * kDctScalingFactor - 2.f / static_cast(kNumBands); static_assert( (kDctScalingFactorError >= 0.f && kDctScalingFactorError < 1e-1f) || (kDctScalingFactorError < 0.f && kDctScalingFactorError > -1e-1f), "kNumBands changed and kDctScalingFactor has not been updated."); RTC_DCHECK_NE(in.data(), out.data()) << "In-place DCT is not supported."; RTC_DCHECK_LE(in.size(), kNumBands); RTC_DCHECK_LE(1, out.size()); RTC_DCHECK_LE(out.size(), in.size()); for (size_t i = 0; i < out.size(); ++i) { out[i] = 0.f; for (size_t j = 0; j < in.size(); ++j) { out[i] += in[j] * dct_table[j * kNumBands + i]; } // TODO(bugs.webrtc.org/10480): Scaling factor in the DCT table. out[i] *= kDctScalingFactor; } } } // namespace rnn_vad } // namespace webrtc ././@PaxHeader0000000000000000000000000000020500000000000010212 xustar00111 path=webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.h 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.0000664000175000017500000001015314475643423033034 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SPECTRAL_FEATURES_INTERNAL_H_ #define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SPECTRAL_FEATURES_INTERNAL_H_ #include #include #include #include "api/array_view.h" #include "modules/audio_processing/agc2/rnn_vad/common.h" namespace webrtc { namespace rnn_vad { // At a sample rate of 24 kHz, the last 3 Opus bands are beyond the Nyquist // frequency. However, band #19 gets the contributions from band #18 because // of the symmetric triangular filter with peak response at 12 kHz. constexpr size_t kOpusBands24kHz = 20; static_assert(kOpusBands24kHz < kNumBands, "The number of bands at 24 kHz must be less than those defined " "in the Opus scale at 48 kHz."); // Number of FFT frequency bins covered by each band in the Opus scale at a // sample rate of 24 kHz for 20 ms frames. // Declared here for unit testing. constexpr std::array GetOpusScaleNumBins24kHz20ms() { return {4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 16, 16, 16, 24, 24, 32, 48}; } // TODO(bugs.webrtc.org/10480): Move to a separate file. // Class to compute band-wise spectral features in the Opus perceptual scale // for 20 ms frames sampled at 24 kHz. The analysis methods apply triangular // filters with peak response at the each band boundary. class SpectralCorrelator { public: // Ctor. SpectralCorrelator(); SpectralCorrelator(const SpectralCorrelator&) = delete; SpectralCorrelator& operator=(const SpectralCorrelator&) = delete; ~SpectralCorrelator(); // Computes the band-wise spectral auto-correlations. // |x| must: // - have size equal to |kFrameSize20ms24kHz|; // - be encoded as vectors of interleaved real-complex FFT coefficients // where x[1] = y[1] = 0 (the Nyquist frequency coefficient is omitted). void ComputeAutoCorrelation( rtc::ArrayView x, rtc::ArrayView auto_corr) const; // Computes the band-wise spectral cross-correlations. // |x| and |y| must: // - have size equal to |kFrameSize20ms24kHz|; // - be encoded as vectors of interleaved real-complex FFT coefficients where // x[1] = y[1] = 0 (the Nyquist frequency coefficient is omitted). void ComputeCrossCorrelation( rtc::ArrayView x, rtc::ArrayView y, rtc::ArrayView cross_corr) const; private: const std::vector weights_; // Weights for each Fourier coefficient. }; // TODO(bugs.webrtc.org/10480): Move to anonymous namespace in // spectral_features.cc. Given a vector of Opus-bands energy coefficients, // computes the log magnitude spectrum applying smoothing both over time and // over frequency. Declared here for unit testing. void ComputeSmoothedLogMagnitudeSpectrum( rtc::ArrayView bands_energy, rtc::ArrayView log_bands_energy); // TODO(bugs.webrtc.org/10480): Move to anonymous namespace in // spectral_features.cc. Creates a DCT table for arrays having size equal to // |kNumBands|. Declared here for unit testing. std::array ComputeDctTable(); // TODO(bugs.webrtc.org/10480): Move to anonymous namespace in // spectral_features.cc. Computes DCT for |in| given a pre-computed DCT table. // In-place computation is not allowed and |out| can be smaller than |in| in // order to only compute the first DCT coefficients. Declared here for unit // testing. void ComputeDct(rtc::ArrayView in, rtc::ArrayView dct_table, rtc::ArrayView out); } // namespace rnn_vad } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SPECTRAL_FEATURES_INTERNAL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/symmetric_matrix_buffer.h0000664000175000017500000000752614475643423032540 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SYMMETRIC_MATRIX_BUFFER_H_ #define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SYMMETRIC_MATRIX_BUFFER_H_ #include #include #include #include #include "api/array_view.h" #include "rtc_base/checks.h" namespace webrtc { namespace rnn_vad { // Data structure to buffer the results of pair-wise comparisons between items // stored in a ring buffer. Every time that the oldest item is replaced in the // ring buffer, the new one is compared to the remaining items in the ring // buffer. The results of such comparisons need to be buffered and automatically // removed when one of the two corresponding items that have been compared is // removed from the ring buffer. It is assumed that the comparison is symmetric // and that comparing an item with itself is not needed. template class SymmetricMatrixBuffer { static_assert(S > 2, ""); public: SymmetricMatrixBuffer() = default; SymmetricMatrixBuffer(const SymmetricMatrixBuffer&) = delete; SymmetricMatrixBuffer& operator=(const SymmetricMatrixBuffer&) = delete; ~SymmetricMatrixBuffer() = default; // Sets the buffer values to zero. void Reset() { static_assert(std::is_arithmetic::value, "Integral or floating point required."); buf_.fill(0); } // Pushes the results from the comparison between the most recent item and // those that are still in the ring buffer. The first element in |values| must // correspond to the comparison between the most recent item and the second // most recent one in the ring buffer, whereas the last element in |values| // must correspond to the comparison between the most recent item and the // oldest one in the ring buffer. void Push(rtc::ArrayView values) { // Move the lower-right sub-matrix of size (S-2) x (S-2) one row up and one // column left. std::memmove(buf_.data(), buf_.data() + S, (buf_.size() - S) * sizeof(T)); // Copy new values in the last column in the right order. for (size_t i = 0; i < values.size(); ++i) { const size_t index = (S - 1 - i) * (S - 1) - 1; RTC_DCHECK_LE(static_cast(0), index); RTC_DCHECK_LT(index, buf_.size()); buf_[index] = values[i]; } } // Reads the value that corresponds to comparison of two items in the ring // buffer having delay |delay1| and |delay2|. The two arguments must not be // equal and both must be in {0, ..., S - 1}. T GetValue(size_t delay1, size_t delay2) const { int row = S - 1 - static_cast(delay1); int col = S - 1 - static_cast(delay2); RTC_DCHECK_NE(row, col) << "The diagonal cannot be accessed."; if (row > col) std::swap(row, col); // Swap to access the upper-right triangular part. RTC_DCHECK_LE(0, row); RTC_DCHECK_LT(row, S - 1) << "Not enforcing row < col and row != col."; RTC_DCHECK_LE(1, col) << "Not enforcing row < col and row != col."; RTC_DCHECK_LT(col, S); const int index = row * (S - 1) + (col - 1); RTC_DCHECK_LE(0, index); RTC_DCHECK_LT(index, buf_.size()); return buf_[index]; } private: // Encode an upper-right triangular matrix (excluding its diagonal) using a // square matrix. This allows to move the data in Push() with one single // operation. std::array buf_{}; }; } // namespace rnn_vad } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SYMMETRIC_MATRIX_BUFFER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/test_utils.cc0000664000175000017500000001003014475643423030124 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/rnn_vad/test_utils.h" #include #include "rtc_base/checks.h" #include "rtc_base/system/arch.h" #include "system_wrappers/include/cpu_features_wrapper.h" #include "test/gtest.h" #include "test/testsupport/file_utils.h" namespace webrtc { namespace rnn_vad { namespace test { namespace { using ReaderPairType = std::pair>, const size_t>; } // namespace using webrtc::test::ResourcePath; void ExpectEqualFloatArray(rtc::ArrayView expected, rtc::ArrayView computed) { ASSERT_EQ(expected.size(), computed.size()); for (size_t i = 0; i < expected.size(); ++i) { SCOPED_TRACE(i); EXPECT_FLOAT_EQ(expected[i], computed[i]); } } void ExpectNearAbsolute(rtc::ArrayView expected, rtc::ArrayView computed, float tolerance) { ASSERT_EQ(expected.size(), computed.size()); for (size_t i = 0; i < expected.size(); ++i) { SCOPED_TRACE(i); EXPECT_NEAR(expected[i], computed[i], tolerance); } } std::pair>, const size_t> CreatePcmSamplesReader(const size_t frame_length) { auto ptr = std::make_unique>( test::ResourcePath("audio_processing/agc2/rnn_vad/samples", "pcm"), frame_length); // The last incomplete frame is ignored. return {std::move(ptr), ptr->data_length() / frame_length}; } ReaderPairType CreatePitchBuffer24kHzReader() { constexpr size_t cols = 864; auto ptr = std::make_unique>( ResourcePath("audio_processing/agc2/rnn_vad/pitch_buf_24k", "dat"), cols); return {std::move(ptr), rtc::CheckedDivExact(ptr->data_length(), cols)}; } ReaderPairType CreateLpResidualAndPitchPeriodGainReader() { constexpr size_t num_lp_residual_coeffs = 864; auto ptr = std::make_unique>( ResourcePath("audio_processing/agc2/rnn_vad/pitch_lp_res", "dat"), num_lp_residual_coeffs); return {std::move(ptr), rtc::CheckedDivExact(ptr->data_length(), 2 + num_lp_residual_coeffs)}; } ReaderPairType CreateVadProbsReader() { auto ptr = std::make_unique>( test::ResourcePath("audio_processing/agc2/rnn_vad/vad_prob", "dat")); return {std::move(ptr), ptr->data_length()}; } PitchTestData::PitchTestData() { BinaryFileReader test_data_reader( ResourcePath("audio_processing/agc2/rnn_vad/pitch_search_int", "dat"), static_cast(1396)); test_data_reader.ReadChunk(test_data_); } PitchTestData::~PitchTestData() = default; rtc::ArrayView PitchTestData::GetPitchBufView() const { return {test_data_.data(), kBufSize24kHz}; } rtc::ArrayView PitchTestData::GetPitchBufSquareEnergiesView() const { return {test_data_.data() + kBufSize24kHz, kNumPitchBufSquareEnergies}; } rtc::ArrayView PitchTestData::GetPitchBufAutoCorrCoeffsView() const { return {test_data_.data() + kBufSize24kHz + kNumPitchBufSquareEnergies, kNumPitchBufAutoCorrCoeffs}; } bool IsOptimizationAvailable(Optimization optimization) { switch (optimization) { case Optimization::kSse2: #if defined(WEBRTC_ARCH_X86_FAMILY) return GetCPUInfo(kSSE2) != 0; #else return false; #endif case Optimization::kNeon: #if defined(WEBRTC_HAS_NEON) return true; #else return false; #endif case Optimization::kNone: return true; } } } // namespace test } // namespace rnn_vad } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/rnn_vad/test_utils.h0000664000175000017500000001350114475643423027774 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_TEST_UTILS_H_ #define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_TEST_UTILS_H_ #include #include #include #include #include #include #include #include #include #include "api/array_view.h" #include "modules/audio_processing/agc2/rnn_vad/common.h" #include "rtc_base/checks.h" namespace webrtc { namespace rnn_vad { namespace test { constexpr float kFloatMin = std::numeric_limits::min(); // Fails for every pair from two equally sized rtc::ArrayView views such // that the values in the pair do not match. void ExpectEqualFloatArray(rtc::ArrayView expected, rtc::ArrayView computed); // Fails for every pair from two equally sized rtc::ArrayView views such // that their absolute error is above a given threshold. void ExpectNearAbsolute(rtc::ArrayView expected, rtc::ArrayView computed, float tolerance); // Reader for binary files consisting of an arbitrary long sequence of elements // having type T. It is possible to read and cast to another type D at once. template class BinaryFileReader { public: explicit BinaryFileReader(const std::string& file_path, size_t chunk_size = 0) : is_(file_path, std::ios::binary | std::ios::ate), data_length_(is_.tellg() / sizeof(T)), chunk_size_(chunk_size) { RTC_CHECK(is_); SeekBeginning(); buf_.resize(chunk_size_); } BinaryFileReader(const BinaryFileReader&) = delete; BinaryFileReader& operator=(const BinaryFileReader&) = delete; ~BinaryFileReader() = default; size_t data_length() const { return data_length_; } bool ReadValue(D* dst) { if (std::is_same::value) { is_.read(reinterpret_cast(dst), sizeof(T)); } else { T v; is_.read(reinterpret_cast(&v), sizeof(T)); *dst = static_cast(v); } return is_.gcount() == sizeof(T); } // If |chunk_size| was specified in the ctor, it will check that the size of // |dst| equals |chunk_size|. bool ReadChunk(rtc::ArrayView dst) { RTC_DCHECK((chunk_size_ == 0) || (chunk_size_ == dst.size())); const std::streamsize bytes_to_read = dst.size() * sizeof(T); if (std::is_same::value) { is_.read(reinterpret_cast(dst.data()), bytes_to_read); } else { is_.read(reinterpret_cast(buf_.data()), bytes_to_read); std::transform(buf_.begin(), buf_.end(), dst.begin(), [](const T& v) -> D { return static_cast(v); }); } return is_.gcount() == bytes_to_read; } void SeekForward(size_t items) { is_.seekg(items * sizeof(T), is_.cur); } void SeekBeginning() { is_.seekg(0, is_.beg); } private: std::ifstream is_; const size_t data_length_; const size_t chunk_size_; std::vector buf_; }; // Writer for binary files. template class BinaryFileWriter { public: explicit BinaryFileWriter(const std::string& file_path) : os_(file_path, std::ios::binary) {} BinaryFileWriter(const BinaryFileWriter&) = delete; BinaryFileWriter& operator=(const BinaryFileWriter&) = delete; ~BinaryFileWriter() = default; static_assert(std::is_arithmetic::value, ""); void WriteChunk(rtc::ArrayView value) { const std::streamsize bytes_to_write = value.size() * sizeof(T); os_.write(reinterpret_cast(value.data()), bytes_to_write); } private: std::ofstream os_; }; // Factories for resource file readers. // The functions below return a pair where the first item is a reader unique // pointer and the second the number of chunks that can be read from the file. // Creates a reader for the PCM samples that casts from S16 to float and reads // chunks with length |frame_length|. std::pair>, const size_t> CreatePcmSamplesReader(const size_t frame_length); // Creates a reader for the pitch buffer content at 24 kHz. std::pair>, const size_t> CreatePitchBuffer24kHzReader(); // Creates a reader for the the LP residual coefficients and the pitch period // and gain values. std::pair>, const size_t> CreateLpResidualAndPitchPeriodGainReader(); // Creates a reader for the VAD probabilities. std::pair>, const size_t> CreateVadProbsReader(); constexpr size_t kNumPitchBufAutoCorrCoeffs = 147; constexpr size_t kNumPitchBufSquareEnergies = 385; constexpr size_t kPitchTestDataSize = kBufSize24kHz + kNumPitchBufSquareEnergies + kNumPitchBufAutoCorrCoeffs; // Class to retrieve a test pitch buffer content and the expected output for the // analysis steps. class PitchTestData { public: PitchTestData(); ~PitchTestData(); rtc::ArrayView GetPitchBufView() const; rtc::ArrayView GetPitchBufSquareEnergiesView() const; rtc::ArrayView GetPitchBufAutoCorrCoeffsView() const; private: std::array test_data_; }; // Returns true if the given optimization is available. bool IsOptimizationAvailable(Optimization optimization); } // namespace test } // namespace rnn_vad } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_TEST_UTILS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/saturation_protector.cc0000664000175000017500000000751114475643423030602 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/saturation_protector.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/numerics/safe_minmax.h" namespace webrtc { namespace { constexpr float kMinLevelDbfs = -90.f; // Min/max margins are based on speech crest-factor. constexpr float kMinMarginDb = 12.f; constexpr float kMaxMarginDb = 25.f; using saturation_protector_impl::RingBuffer; } // namespace bool RingBuffer::operator==(const RingBuffer& b) const { RTC_DCHECK_LE(size_, buffer_.size()); RTC_DCHECK_LE(b.size_, b.buffer_.size()); if (size_ != b.size_) { return false; } for (int i = 0, i0 = FrontIndex(), i1 = b.FrontIndex(); i < size_; ++i, ++i0, ++i1) { if (buffer_[i0 % buffer_.size()] != b.buffer_[i1 % b.buffer_.size()]) { return false; } } return true; } void RingBuffer::Reset() { next_ = 0; size_ = 0; } void RingBuffer::PushBack(float v) { RTC_DCHECK_GE(next_, 0); RTC_DCHECK_GE(size_, 0); RTC_DCHECK_LT(next_, buffer_.size()); RTC_DCHECK_LE(size_, buffer_.size()); buffer_[next_++] = v; if (rtc::SafeEq(next_, buffer_.size())) { next_ = 0; } if (rtc::SafeLt(size_, buffer_.size())) { size_++; } } absl::optional RingBuffer::Front() const { if (size_ == 0) { return absl::nullopt; } RTC_DCHECK_LT(FrontIndex(), buffer_.size()); return buffer_[FrontIndex()]; } bool SaturationProtectorState::operator==( const SaturationProtectorState& b) const { return margin_db == b.margin_db && peak_delay_buffer == b.peak_delay_buffer && max_peaks_dbfs == b.max_peaks_dbfs && time_since_push_ms == b.time_since_push_ms; } void ResetSaturationProtectorState(float initial_margin_db, SaturationProtectorState& state) { state.margin_db = initial_margin_db; state.peak_delay_buffer.Reset(); state.max_peaks_dbfs = kMinLevelDbfs; state.time_since_push_ms = 0; } void UpdateSaturationProtectorState(float speech_peak_dbfs, float speech_level_dbfs, SaturationProtectorState& state) { // Get the max peak over `kPeakEnveloperSuperFrameLengthMs` ms. state.max_peaks_dbfs = std::max(state.max_peaks_dbfs, speech_peak_dbfs); state.time_since_push_ms += kFrameDurationMs; if (rtc::SafeGt(state.time_since_push_ms, kPeakEnveloperSuperFrameLengthMs)) { // Push `max_peaks_dbfs` back into the ring buffer. state.peak_delay_buffer.PushBack(state.max_peaks_dbfs); // Reset. state.max_peaks_dbfs = kMinLevelDbfs; state.time_since_push_ms = 0; } // Update margin by comparing the estimated speech level and the delayed max // speech peak power. // TODO(alessiob): Check with aleloi@ why we use a delay and how to tune it. const float delayed_peak_dbfs = state.peak_delay_buffer.Front().value_or(state.max_peaks_dbfs); const float difference_db = delayed_peak_dbfs - speech_level_dbfs; if (difference_db > state.margin_db) { // Attack. state.margin_db = state.margin_db * kSaturationProtectorAttackConstant + difference_db * (1.f - kSaturationProtectorAttackConstant); } else { // Decay. state.margin_db = state.margin_db * kSaturationProtectorDecayConstant + difference_db * (1.f - kSaturationProtectorDecayConstant); } state.margin_db = rtc::SafeClamp(state.margin_db, kMinMarginDb, kMaxMarginDb); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/saturation_protector.h0000664000175000017500000000566514475643423030454 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_SATURATION_PROTECTOR_H_ #define MODULES_AUDIO_PROCESSING_AGC2_SATURATION_PROTECTOR_H_ #include #include "absl/types/optional.h" #include "modules/audio_processing/agc2/agc2_common.h" #include "rtc_base/numerics/safe_compare.h" namespace webrtc { namespace saturation_protector_impl { // Ring buffer which only supports (i) push back and (ii) read oldest item. class RingBuffer { public: bool operator==(const RingBuffer& b) const; inline bool operator!=(const RingBuffer& b) const { return !(*this == b); } // Maximum number of values that the buffer can contain. int Capacity() const { return buffer_.size(); } // Number of values in the buffer. int Size() const { return size_; } void Reset(); // Pushes back `v`. If the buffer is full, the oldest value is replaced. void PushBack(float v); // Returns the oldest item in the buffer. Returns an empty value if the // buffer is empty. absl::optional Front() const; private: inline int FrontIndex() const { return rtc::SafeEq(size_, buffer_.size()) ? next_ : 0; } // `buffer_` has `size_` elements (up to the size of `buffer_`) and `next_` is // the position where the next new value is written in `buffer_`. std::array buffer_; int next_ = 0; int size_ = 0; }; } // namespace saturation_protector_impl // Saturation protector state. Exposed publicly for check-pointing and restore // ops. struct SaturationProtectorState { bool operator==(const SaturationProtectorState& s) const; inline bool operator!=(const SaturationProtectorState& s) const { return !(*this == s); } float margin_db; // Recommended margin. saturation_protector_impl::RingBuffer peak_delay_buffer; float max_peaks_dbfs; int time_since_push_ms; // Time since the last ring buffer push operation. }; // Resets the saturation protector state. void ResetSaturationProtectorState(float initial_margin_db, SaturationProtectorState& state); // Updates `state` by analyzing the estimated speech level `speech_level_dbfs` // and the peak power `speech_peak_dbfs` for an observed frame which is // reliably classified as "speech". `state` must not be modified without calling // this function. void UpdateSaturationProtectorState(float speech_peak_dbfs, float speech_level_dbfs, SaturationProtectorState& state); } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_SATURATION_PROTECTOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/signal_classifier.cc0000664000175000017500000001330114475643423027763 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/signal_classifier.h" #include #include #include #include "api/array_view.h" #include "modules/audio_processing/agc2/down_sampler.h" #include "modules/audio_processing/agc2/noise_spectrum_estimator.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" #include "system_wrappers/include/cpu_features_wrapper.h" namespace webrtc { namespace { bool IsSse2Available() { #if defined(WEBRTC_ARCH_X86_FAMILY) return GetCPUInfo(kSSE2) != 0; #else return false; #endif } void RemoveDcLevel(rtc::ArrayView x) { RTC_DCHECK_LT(0, x.size()); float mean = std::accumulate(x.data(), x.data() + x.size(), 0.f); mean /= x.size(); for (float& v : x) { v -= mean; } } void PowerSpectrum(const OouraFft* ooura_fft, rtc::ArrayView x, rtc::ArrayView spectrum) { RTC_DCHECK_EQ(65, spectrum.size()); RTC_DCHECK_EQ(128, x.size()); float X[128]; std::copy(x.data(), x.data() + x.size(), X); ooura_fft->Fft(X); float* X_p = X; RTC_DCHECK_EQ(X_p, &X[0]); spectrum[0] = (*X_p) * (*X_p); ++X_p; RTC_DCHECK_EQ(X_p, &X[1]); spectrum[64] = (*X_p) * (*X_p); for (int k = 1; k < 64; ++k) { ++X_p; RTC_DCHECK_EQ(X_p, &X[2 * k]); spectrum[k] = (*X_p) * (*X_p); ++X_p; RTC_DCHECK_EQ(X_p, &X[2 * k + 1]); spectrum[k] += (*X_p) * (*X_p); } } webrtc::SignalClassifier::SignalType ClassifySignal( rtc::ArrayView signal_spectrum, rtc::ArrayView noise_spectrum, ApmDataDumper* data_dumper) { int num_stationary_bands = 0; int num_highly_nonstationary_bands = 0; // Detect stationary and highly nonstationary bands. for (size_t k = 1; k < 40; k++) { if (signal_spectrum[k] < 3 * noise_spectrum[k] && signal_spectrum[k] * 3 > noise_spectrum[k]) { ++num_stationary_bands; } else if (signal_spectrum[k] > 9 * noise_spectrum[k]) { ++num_highly_nonstationary_bands; } } data_dumper->DumpRaw("lc_num_stationary_bands", 1, &num_stationary_bands); data_dumper->DumpRaw("lc_num_highly_nonstationary_bands", 1, &num_highly_nonstationary_bands); // Use the detected number of bands to classify the overall signal // stationarity. if (num_stationary_bands > 15) { return SignalClassifier::SignalType::kStationary; } else { return SignalClassifier::SignalType::kNonStationary; } } } // namespace SignalClassifier::FrameExtender::FrameExtender(size_t frame_size, size_t extended_frame_size) : x_old_(extended_frame_size - frame_size, 0.f) {} SignalClassifier::FrameExtender::~FrameExtender() = default; void SignalClassifier::FrameExtender::ExtendFrame( rtc::ArrayView x, rtc::ArrayView x_extended) { RTC_DCHECK_EQ(x_old_.size() + x.size(), x_extended.size()); std::copy(x_old_.data(), x_old_.data() + x_old_.size(), x_extended.data()); std::copy(x.data(), x.data() + x.size(), x_extended.data() + x_old_.size()); std::copy(x_extended.data() + x_extended.size() - x_old_.size(), x_extended.data() + x_extended.size(), x_old_.data()); } SignalClassifier::SignalClassifier(ApmDataDumper* data_dumper) : data_dumper_(data_dumper), down_sampler_(data_dumper_), noise_spectrum_estimator_(data_dumper_), ooura_fft_(IsSse2Available()) { Initialize(48000); } SignalClassifier::~SignalClassifier() {} void SignalClassifier::Initialize(int sample_rate_hz) { down_sampler_.Initialize(sample_rate_hz); noise_spectrum_estimator_.Initialize(); frame_extender_.reset(new FrameExtender(80, 128)); sample_rate_hz_ = sample_rate_hz; initialization_frames_left_ = 2; consistent_classification_counter_ = 3; last_signal_type_ = SignalClassifier::SignalType::kNonStationary; } SignalClassifier::SignalType SignalClassifier::Analyze( rtc::ArrayView signal) { RTC_DCHECK_EQ(signal.size(), sample_rate_hz_ / 100); // Compute the signal power spectrum. float downsampled_frame[80]; down_sampler_.DownSample(signal, downsampled_frame); float extended_frame[128]; frame_extender_->ExtendFrame(downsampled_frame, extended_frame); RemoveDcLevel(extended_frame); float signal_spectrum[65]; PowerSpectrum(&ooura_fft_, extended_frame, signal_spectrum); // Classify the signal based on the estimate of the noise spectrum and the // signal spectrum estimate. const SignalType signal_type = ClassifySignal( signal_spectrum, noise_spectrum_estimator_.GetNoiseSpectrum(), data_dumper_); // Update the noise spectrum based on the signal spectrum. noise_spectrum_estimator_.Update(signal_spectrum, initialization_frames_left_ > 0); // Update the number of frames until a reliable signal spectrum is achieved. initialization_frames_left_ = std::max(0, initialization_frames_left_ - 1); if (last_signal_type_ == signal_type) { consistent_classification_counter_ = std::max(0, consistent_classification_counter_ - 1); } else { last_signal_type_ = signal_type; consistent_classification_counter_ = 3; } if (consistent_classification_counter_ > 0) { return SignalClassifier::SignalType::kNonStationary; } return signal_type; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/signal_classifier.h0000664000175000017500000000412014475643423027624 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_SIGNAL_CLASSIFIER_H_ #define MODULES_AUDIO_PROCESSING_AGC2_SIGNAL_CLASSIFIER_H_ #include #include #include "api/array_view.h" #include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h" #include "modules/audio_processing/agc2/down_sampler.h" #include "modules/audio_processing/agc2/noise_spectrum_estimator.h" namespace webrtc { class ApmDataDumper; class AudioBuffer; class SignalClassifier { public: enum class SignalType { kNonStationary, kStationary }; explicit SignalClassifier(ApmDataDumper* data_dumper); SignalClassifier() = delete; SignalClassifier(const SignalClassifier&) = delete; SignalClassifier& operator=(const SignalClassifier&) = delete; ~SignalClassifier(); void Initialize(int sample_rate_hz); SignalType Analyze(rtc::ArrayView signal); private: class FrameExtender { public: FrameExtender(size_t frame_size, size_t extended_frame_size); FrameExtender() = delete; FrameExtender(const FrameExtender&) = delete; FrameExtender& operator=(const FrameExtender&) = delete; ~FrameExtender(); void ExtendFrame(rtc::ArrayView x, rtc::ArrayView x_extended); private: std::vector x_old_; }; ApmDataDumper* const data_dumper_; DownSampler down_sampler_; std::unique_ptr frame_extender_; NoiseSpectrumEstimator noise_spectrum_estimator_; int sample_rate_hz_; int initialization_frames_left_; int consistent_classification_counter_; SignalType last_signal_type_; const OouraFft ooura_fft_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_SIGNAL_CLASSIFIER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/vad_with_level.cc0000664000175000017500000000760614475643423027311 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/vad_with_level.h" #include #include #include #include "api/array_view.h" #include "common_audio/include/audio_util.h" #include "common_audio/resampler/include/push_resampler.h" #include "modules/audio_processing/agc2/agc2_common.h" #include "modules/audio_processing/agc2/rnn_vad/common.h" #include "modules/audio_processing/agc2/rnn_vad/features_extraction.h" #include "modules/audio_processing/agc2/rnn_vad/rnn.h" #include "rtc_base/checks.h" namespace webrtc { namespace { using VoiceActivityDetector = VadLevelAnalyzer::VoiceActivityDetector; // Default VAD that combines a resampler and the RNN VAD. // Computes the speech probability on the first channel. class Vad : public VoiceActivityDetector { public: Vad() = default; Vad(const Vad&) = delete; Vad& operator=(const Vad&) = delete; ~Vad() = default; float ComputeProbability(AudioFrameView frame) override { // The source number of channels is 1, because we always use the 1st // channel. resampler_.InitializeIfNeeded( /*sample_rate_hz=*/static_cast(frame.samples_per_channel() * 100), rnn_vad::kSampleRate24kHz, /*num_channels=*/1); std::array work_frame; // Feed the 1st channel to the resampler. resampler_.Resample(frame.channel(0).data(), frame.samples_per_channel(), work_frame.data(), rnn_vad::kFrameSize10ms24kHz); std::array feature_vector; const bool is_silence = features_extractor_.CheckSilenceComputeFeatures( work_frame, feature_vector); return rnn_vad_.ComputeVadProbability(feature_vector, is_silence); } private: PushResampler resampler_; rnn_vad::FeaturesExtractor features_extractor_; rnn_vad::RnnBasedVad rnn_vad_; }; // Returns an updated version of `p_old` by using instant decay and the given // `attack` on a new VAD probability value `p_new`. float SmoothedVadProbability(float p_old, float p_new, float attack) { RTC_DCHECK_GT(attack, 0.f); RTC_DCHECK_LE(attack, 1.f); if (p_new < p_old || attack == 1.f) { // Instant decay (or no smoothing). return p_new; } else { // Attack phase. return attack * p_new + (1.f - attack) * p_old; } } } // namespace VadLevelAnalyzer::VadLevelAnalyzer() : VadLevelAnalyzer(kDefaultSmoothedVadProbabilityAttack, std::make_unique()) {} VadLevelAnalyzer::VadLevelAnalyzer(float vad_probability_attack) : VadLevelAnalyzer(vad_probability_attack, std::make_unique()) {} VadLevelAnalyzer::VadLevelAnalyzer(float vad_probability_attack, std::unique_ptr vad) : vad_(std::move(vad)), vad_probability_attack_(vad_probability_attack) { RTC_DCHECK(vad_); } VadLevelAnalyzer::~VadLevelAnalyzer() = default; VadLevelAnalyzer::Result VadLevelAnalyzer::AnalyzeFrame( AudioFrameView frame) { // Compute levels. float peak = 0.f; float rms = 0.f; for (const auto& x : frame.channel(0)) { peak = std::max(std::fabs(x), peak); rms += x * x; } // Compute smoothed speech probability. vad_probability_ = SmoothedVadProbability( /*p_old=*/vad_probability_, /*p_new=*/vad_->ComputeProbability(frame), vad_probability_attack_); return {vad_probability_, FloatS16ToDbfs(std::sqrt(rms / frame.samples_per_channel())), FloatS16ToDbfs(peak)}; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/vad_with_level.h0000664000175000017500000000361714475643423027151 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_VAD_WITH_LEVEL_H_ #define MODULES_AUDIO_PROCESSING_AGC2_VAD_WITH_LEVEL_H_ #include #include "modules/audio_processing/include/audio_frame_view.h" namespace webrtc { // Class to analyze voice activity and audio levels. class VadLevelAnalyzer { public: struct Result { float speech_probability; // Range: [0, 1]. float rms_dbfs; // Root mean square power (dBFS). float peak_dbfs; // Peak power (dBFS). }; // Voice Activity Detector (VAD) interface. class VoiceActivityDetector { public: virtual ~VoiceActivityDetector() = default; // Analyzes an audio frame and returns the speech probability. virtual float ComputeProbability(AudioFrameView frame) = 0; }; // Ctor. Uses the default VAD. VadLevelAnalyzer(); explicit VadLevelAnalyzer(float vad_probability_attack); // Ctor. Uses a custom `vad`. VadLevelAnalyzer(float vad_probability_attack, std::unique_ptr vad); VadLevelAnalyzer(const VadLevelAnalyzer&) = delete; VadLevelAnalyzer& operator=(const VadLevelAnalyzer&) = delete; ~VadLevelAnalyzer(); // Computes the speech probability and the level for `frame`. Result AnalyzeFrame(AudioFrameView frame); private: std::unique_ptr vad_; const float vad_probability_attack_; float vad_probability_ = 0.f; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_VAD_WITH_LEVEL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/vector_float_frame.cc0000664000175000017500000000237614475643423030155 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/vector_float_frame.h" namespace webrtc { namespace { std::vector ConstructChannelPointers( std::vector>* x) { std::vector channel_ptrs; for (auto& v : *x) { channel_ptrs.push_back(v.data()); } return channel_ptrs; } } // namespace VectorFloatFrame::VectorFloatFrame(int num_channels, int samples_per_channel, float start_value) : channels_(num_channels, std::vector(samples_per_channel, start_value)), channel_ptrs_(ConstructChannelPointers(&channels_)), float_frame_view_(channel_ptrs_.data(), channels_.size(), samples_per_channel) {} VectorFloatFrame::~VectorFloatFrame() = default; } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/agc2/vector_float_frame.h0000664000175000017500000000243014475643423030006 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC2_VECTOR_FLOAT_FRAME_H_ #define MODULES_AUDIO_PROCESSING_AGC2_VECTOR_FLOAT_FRAME_H_ #include #include "modules/audio_processing/include/audio_frame_view.h" namespace webrtc { // A construct consisting of a multi-channel audio frame, and a FloatFrame view // of it. class VectorFloatFrame { public: VectorFloatFrame(int num_channels, int samples_per_channel, float start_value); const AudioFrameView& float_frame_view() { return float_frame_view_; } AudioFrameView float_frame_view() const { return float_frame_view_; } ~VectorFloatFrame(); private: std::vector> channels_; std::vector channel_ptrs_; AudioFrameView float_frame_view_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC2_VECTOR_FLOAT_FRAME_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/audio_buffer.cc0000664000175000017500000003532614475643423026133 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/audio_buffer.h" #include #include #include "common_audio/channel_buffer.h" #include "common_audio/include/audio_util.h" #include "common_audio/resampler/push_sinc_resampler.h" #include "modules/audio_processing/splitting_filter.h" #include "rtc_base/checks.h" namespace webrtc { namespace { constexpr size_t kSamplesPer32kHzChannel = 320; constexpr size_t kSamplesPer48kHzChannel = 480; constexpr size_t kMaxSamplesPerChannel = AudioBuffer::kMaxSampleRate / 100; size_t NumBandsFromFramesPerChannel(size_t num_frames) { if (num_frames == kSamplesPer32kHzChannel) { return 2; } if (num_frames == kSamplesPer48kHzChannel) { return 3; } return 1; } } // namespace AudioBuffer::AudioBuffer(size_t input_rate, size_t input_num_channels, size_t buffer_rate, size_t buffer_num_channels, size_t output_rate, size_t output_num_channels) : AudioBuffer(static_cast(input_rate) / 100, input_num_channels, static_cast(buffer_rate) / 100, buffer_num_channels, static_cast(output_rate) / 100) {} AudioBuffer::AudioBuffer(size_t input_num_frames, size_t input_num_channels, size_t buffer_num_frames, size_t buffer_num_channels, size_t output_num_frames) : input_num_frames_(input_num_frames), input_num_channels_(input_num_channels), buffer_num_frames_(buffer_num_frames), buffer_num_channels_(buffer_num_channels), output_num_frames_(output_num_frames), output_num_channels_(0), num_channels_(buffer_num_channels), num_bands_(NumBandsFromFramesPerChannel(buffer_num_frames_)), num_split_frames_(rtc::CheckedDivExact(buffer_num_frames_, num_bands_)), data_( new ChannelBuffer(buffer_num_frames_, buffer_num_channels_)) { RTC_DCHECK_GT(input_num_frames_, 0); RTC_DCHECK_GT(buffer_num_frames_, 0); RTC_DCHECK_GT(output_num_frames_, 0); RTC_DCHECK_GT(input_num_channels_, 0); RTC_DCHECK_GT(buffer_num_channels_, 0); RTC_DCHECK_LE(buffer_num_channels_, input_num_channels_); const bool input_resampling_needed = input_num_frames_ != buffer_num_frames_; const bool output_resampling_needed = output_num_frames_ != buffer_num_frames_; if (input_resampling_needed) { for (size_t i = 0; i < buffer_num_channels_; ++i) { input_resamplers_.push_back(std::unique_ptr( new PushSincResampler(input_num_frames_, buffer_num_frames_))); } } if (output_resampling_needed) { for (size_t i = 0; i < buffer_num_channels_; ++i) { output_resamplers_.push_back(std::unique_ptr( new PushSincResampler(buffer_num_frames_, output_num_frames_))); } } if (num_bands_ > 1) { split_data_.reset(new ChannelBuffer( buffer_num_frames_, buffer_num_channels_, num_bands_)); splitting_filter_.reset(new SplittingFilter( buffer_num_channels_, num_bands_, buffer_num_frames_)); } } AudioBuffer::~AudioBuffer() {} void AudioBuffer::set_downmixing_to_specific_channel(size_t channel) { downmix_by_averaging_ = false; RTC_DCHECK_GT(input_num_channels_, channel); channel_for_downmixing_ = std::min(channel, input_num_channels_ - 1); } void AudioBuffer::set_downmixing_by_averaging() { downmix_by_averaging_ = true; } void AudioBuffer::CopyFrom(const float* const* stacked_data, const StreamConfig& stream_config) { RTC_DCHECK_EQ(stream_config.num_frames(), input_num_frames_); RTC_DCHECK_EQ(stream_config.num_channels(), input_num_channels_); RestoreNumChannels(); const bool downmix_needed = input_num_channels_ > 1 && num_channels_ == 1; const bool resampling_needed = input_num_frames_ != buffer_num_frames_; if (downmix_needed) { RTC_DCHECK_GE(kMaxSamplesPerChannel, input_num_frames_); std::array downmix; if (downmix_by_averaging_) { const float kOneByNumChannels = 1.f / input_num_channels_; for (size_t i = 0; i < input_num_frames_; ++i) { float value = stacked_data[0][i]; for (size_t j = 1; j < input_num_channels_; ++j) { value += stacked_data[j][i]; } downmix[i] = value * kOneByNumChannels; } } const float* downmixed_data = downmix_by_averaging_ ? downmix.data() : stacked_data[channel_for_downmixing_]; if (resampling_needed) { input_resamplers_[0]->Resample(downmixed_data, input_num_frames_, data_->channels()[0], buffer_num_frames_); } const float* data_to_convert = resampling_needed ? data_->channels()[0] : downmixed_data; FloatToFloatS16(data_to_convert, buffer_num_frames_, data_->channels()[0]); } else { if (resampling_needed) { for (size_t i = 0; i < num_channels_; ++i) { input_resamplers_[i]->Resample(stacked_data[i], input_num_frames_, data_->channels()[i], buffer_num_frames_); FloatToFloatS16(data_->channels()[i], buffer_num_frames_, data_->channels()[i]); } } else { for (size_t i = 0; i < num_channels_; ++i) { FloatToFloatS16(stacked_data[i], buffer_num_frames_, data_->channels()[i]); } } } } void AudioBuffer::CopyTo(const StreamConfig& stream_config, float* const* stacked_data) { RTC_DCHECK_EQ(stream_config.num_frames(), output_num_frames_); const bool resampling_needed = output_num_frames_ != buffer_num_frames_; if (resampling_needed) { for (size_t i = 0; i < num_channels_; ++i) { FloatS16ToFloat(data_->channels()[i], buffer_num_frames_, data_->channels()[i]); output_resamplers_[i]->Resample(data_->channels()[i], buffer_num_frames_, stacked_data[i], output_num_frames_); } } else { for (size_t i = 0; i < num_channels_; ++i) { FloatS16ToFloat(data_->channels()[i], buffer_num_frames_, stacked_data[i]); } } for (size_t i = num_channels_; i < stream_config.num_channels(); ++i) { memcpy(stacked_data[i], stacked_data[0], output_num_frames_ * sizeof(**stacked_data)); } } void AudioBuffer::CopyTo(AudioBuffer* buffer) const { RTC_DCHECK_EQ(buffer->num_frames(), output_num_frames_); const bool resampling_needed = output_num_frames_ != buffer_num_frames_; if (resampling_needed) { for (size_t i = 0; i < num_channels_; ++i) { output_resamplers_[i]->Resample(data_->channels()[i], buffer_num_frames_, buffer->channels()[i], buffer->num_frames()); } } else { for (size_t i = 0; i < num_channels_; ++i) { memcpy(buffer->channels()[i], data_->channels()[i], buffer_num_frames_ * sizeof(**buffer->channels())); } } for (size_t i = num_channels_; i < buffer->num_channels(); ++i) { memcpy(buffer->channels()[i], buffer->channels()[0], output_num_frames_ * sizeof(**buffer->channels())); } } void AudioBuffer::RestoreNumChannels() { num_channels_ = buffer_num_channels_; data_->set_num_channels(buffer_num_channels_); if (split_data_.get()) { split_data_->set_num_channels(buffer_num_channels_); } } void AudioBuffer::set_num_channels(size_t num_channels) { RTC_DCHECK_GE(buffer_num_channels_, num_channels); num_channels_ = num_channels; data_->set_num_channels(num_channels); if (split_data_.get()) { split_data_->set_num_channels(num_channels); } } // The resampler is only for supporting 48kHz to 16kHz in the reverse stream. void AudioBuffer::CopyFrom(const int16_t* const interleaved_data, const StreamConfig& stream_config) { RTC_DCHECK_EQ(stream_config.num_channels(), input_num_channels_); RTC_DCHECK_EQ(stream_config.num_frames(), input_num_frames_); RestoreNumChannels(); const bool resampling_required = input_num_frames_ != buffer_num_frames_; const int16_t* interleaved = interleaved_data; if (num_channels_ == 1) { if (input_num_channels_ == 1) { if (resampling_required) { std::array float_buffer; S16ToFloatS16(interleaved, input_num_frames_, float_buffer.data()); input_resamplers_[0]->Resample(float_buffer.data(), input_num_frames_, data_->channels()[0], buffer_num_frames_); } else { S16ToFloatS16(interleaved, input_num_frames_, data_->channels()[0]); } } else { std::array float_buffer; float* downmixed_data = resampling_required ? float_buffer.data() : data_->channels()[0]; if (downmix_by_averaging_) { for (size_t j = 0, k = 0; j < input_num_frames_; ++j) { int32_t sum = 0; for (size_t i = 0; i < input_num_channels_; ++i, ++k) { sum += interleaved[k]; } downmixed_data[j] = sum / static_cast(input_num_channels_); } } else { for (size_t j = 0, k = channel_for_downmixing_; j < input_num_frames_; ++j, k += input_num_channels_) { downmixed_data[j] = interleaved[k]; } } if (resampling_required) { input_resamplers_[0]->Resample(downmixed_data, input_num_frames_, data_->channels()[0], buffer_num_frames_); } } } else { auto deinterleave_channel = [](size_t channel, size_t num_channels, size_t samples_per_channel, const int16_t* x, float* y) { for (size_t j = 0, k = channel; j < samples_per_channel; ++j, k += num_channels) { y[j] = x[k]; } }; if (resampling_required) { std::array float_buffer; for (size_t i = 0; i < num_channels_; ++i) { deinterleave_channel(i, num_channels_, input_num_frames_, interleaved, float_buffer.data()); input_resamplers_[i]->Resample(float_buffer.data(), input_num_frames_, data_->channels()[i], buffer_num_frames_); } } else { for (size_t i = 0; i < num_channels_; ++i) { deinterleave_channel(i, num_channels_, input_num_frames_, interleaved, data_->channels()[i]); } } } } void AudioBuffer::CopyTo(const StreamConfig& stream_config, int16_t* const interleaved_data) { const size_t config_num_channels = stream_config.num_channels(); RTC_DCHECK(config_num_channels == num_channels_ || num_channels_ == 1); RTC_DCHECK_EQ(stream_config.num_frames(), output_num_frames_); const bool resampling_required = buffer_num_frames_ != output_num_frames_; int16_t* interleaved = interleaved_data; if (num_channels_ == 1) { std::array float_buffer; if (resampling_required) { output_resamplers_[0]->Resample(data_->channels()[0], buffer_num_frames_, float_buffer.data(), output_num_frames_); } const float* deinterleaved = resampling_required ? float_buffer.data() : data_->channels()[0]; if (config_num_channels == 1) { for (size_t j = 0; j < output_num_frames_; ++j) { interleaved[j] = FloatS16ToS16(deinterleaved[j]); } } else { for (size_t i = 0, k = 0; i < output_num_frames_; ++i) { float tmp = FloatS16ToS16(deinterleaved[i]); for (size_t j = 0; j < config_num_channels; ++j, ++k) { interleaved[k] = tmp; } } } } else { auto interleave_channel = [](size_t channel, size_t num_channels, size_t samples_per_channel, const float* x, int16_t* y) { for (size_t k = 0, j = channel; k < samples_per_channel; ++k, j += num_channels) { y[j] = FloatS16ToS16(x[k]); } }; if (resampling_required) { for (size_t i = 0; i < num_channels_; ++i) { std::array float_buffer; output_resamplers_[i]->Resample(data_->channels()[i], buffer_num_frames_, float_buffer.data(), output_num_frames_); interleave_channel(i, config_num_channels, output_num_frames_, float_buffer.data(), interleaved); } } else { for (size_t i = 0; i < num_channels_; ++i) { interleave_channel(i, config_num_channels, output_num_frames_, data_->channels()[i], interleaved); } } for (size_t i = num_channels_; i < config_num_channels; ++i) { for (size_t j = 0, k = i, n = num_channels_; j < output_num_frames_; ++j, k += config_num_channels, n += config_num_channels) { interleaved[k] = interleaved[n]; } } } } void AudioBuffer::SplitIntoFrequencyBands() { splitting_filter_->Analysis(data_.get(), split_data_.get()); } void AudioBuffer::MergeFrequencyBands() { splitting_filter_->Synthesis(split_data_.get(), data_.get()); } void AudioBuffer::ExportSplitChannelData( size_t channel, int16_t* const* split_band_data) const { for (size_t k = 0; k < num_bands(); ++k) { const float* band_data = split_bands_const(channel)[k]; RTC_DCHECK(split_band_data[k]); RTC_DCHECK(band_data); for (size_t i = 0; i < num_frames_per_band(); ++i) { split_band_data[k][i] = FloatS16ToS16(band_data[i]); } } } void AudioBuffer::ImportSplitChannelData( size_t channel, const int16_t* const* split_band_data) { for (size_t k = 0; k < num_bands(); ++k) { float* band_data = split_bands(channel)[k]; RTC_DCHECK(split_band_data[k]); RTC_DCHECK(band_data); for (size_t i = 0; i < num_frames_per_band(); ++i) { band_data[i] = split_band_data[k][i]; } } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/audio_buffer.h0000664000175000017500000001427114475643423025771 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AUDIO_BUFFER_H_ #define MODULES_AUDIO_PROCESSING_AUDIO_BUFFER_H_ #include #include #include #include #include "common_audio/channel_buffer.h" #include "modules/audio_processing/include/audio_processing.h" namespace webrtc { class PushSincResampler; class SplittingFilter; enum Band { kBand0To8kHz = 0, kBand8To16kHz = 1, kBand16To24kHz = 2 }; // Stores any audio data in a way that allows the audio processing module to // operate on it in a controlled manner. class AudioBuffer { public: static const int kSplitBandSize = 160; static const size_t kMaxSampleRate = 384000; AudioBuffer(size_t input_rate, size_t input_num_channels, size_t buffer_rate, size_t buffer_num_channels, size_t output_rate, size_t output_num_channels); // The constructor below will be deprecated. AudioBuffer(size_t input_num_frames, size_t input_num_channels, size_t buffer_num_frames, size_t buffer_num_channels, size_t output_num_frames); virtual ~AudioBuffer(); AudioBuffer(const AudioBuffer&) = delete; AudioBuffer& operator=(const AudioBuffer&) = delete; // Specify that downmixing should be done by selecting a single channel. void set_downmixing_to_specific_channel(size_t channel); // Specify that downmixing should be done by averaging all channels,. void set_downmixing_by_averaging(); // Set the number of channels in the buffer. The specified number of channels // cannot be larger than the specified buffer_num_channels. The number is also // reset at each call to CopyFrom or InterleaveFrom. void set_num_channels(size_t num_channels); size_t num_channels() const { return num_channels_; } size_t num_frames() const { return buffer_num_frames_; } size_t num_frames_per_band() const { return num_split_frames_; } size_t num_bands() const { return num_bands_; } // Returns pointer arrays to the full-band channels. // Usage: // channels()[channel][sample]. // Where: // 0 <= channel < |buffer_num_channels_| // 0 <= sample < |buffer_num_frames_| float* const* channels() { return data_->channels(); } const float* const* channels_const() const { return data_->channels(); } // Returns pointer arrays to the bands for a specific channel. // Usage: // split_bands(channel)[band][sample]. // Where: // 0 <= channel < |buffer_num_channels_| // 0 <= band < |num_bands_| // 0 <= sample < |num_split_frames_| const float* const* split_bands_const(size_t channel) const { return split_data_.get() ? split_data_->bands(channel) : data_->bands(channel); } float* const* split_bands(size_t channel) { return split_data_.get() ? split_data_->bands(channel) : data_->bands(channel); } // Returns a pointer array to the channels for a specific band. // Usage: // split_channels(band)[channel][sample]. // Where: // 0 <= band < |num_bands_| // 0 <= channel < |buffer_num_channels_| // 0 <= sample < |num_split_frames_| const float* const* split_channels_const(Band band) const { if (split_data_.get()) { return split_data_->channels(band); } else { return band == kBand0To8kHz ? data_->channels() : nullptr; } } // Copies data into the buffer. void CopyFrom(const int16_t* const interleaved_data, const StreamConfig& stream_config); void CopyFrom(const float* const* stacked_data, const StreamConfig& stream_config); // Copies data from the buffer. void CopyTo(const StreamConfig& stream_config, int16_t* const interleaved_data); void CopyTo(const StreamConfig& stream_config, float* const* stacked_data); void CopyTo(AudioBuffer* buffer) const; // Splits the buffer data into frequency bands. void SplitIntoFrequencyBands(); // Recombines the frequency bands into a full-band signal. void MergeFrequencyBands(); // Copies the split bands data into the integer two-dimensional array. void ExportSplitChannelData(size_t channel, int16_t* const* split_band_data) const; // Copies the data in the integer two-dimensional array into the split_bands // data. void ImportSplitChannelData(size_t channel, const int16_t* const* split_band_data); static const size_t kMaxSplitFrameLength = 160; static const size_t kMaxNumBands = 3; // Deprecated methods, will be removed soon. float* const* channels_f() { return channels(); } const float* const* channels_const_f() const { return channels_const(); } const float* const* split_bands_const_f(size_t channel) const { return split_bands_const(channel); } float* const* split_bands_f(size_t channel) { return split_bands(channel); } const float* const* split_channels_const_f(Band band) const { return split_channels_const(band); } private: FRIEND_TEST_ALL_PREFIXES(AudioBufferTest, SetNumChannelsSetsChannelBuffersNumChannels); void RestoreNumChannels(); const size_t input_num_frames_; const size_t input_num_channels_; const size_t buffer_num_frames_; const size_t buffer_num_channels_; const size_t output_num_frames_; const size_t output_num_channels_; size_t num_channels_; size_t num_bands_; size_t num_split_frames_; std::unique_ptr> data_; std::unique_ptr> split_data_; std::unique_ptr splitting_filter_; std::vector> input_resamplers_; std::vector> output_resamplers_; bool downmix_by_averaging_ = true; size_t channel_for_downmixing_ = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AUDIO_BUFFER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/audio_processing_builder_impl.cc0000664000175000017500000000260314475643423031555 0ustar00arunarun/* * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/include/audio_processing.h" #include #include "modules/audio_processing/audio_processing_impl.h" #include "rtc_base/ref_counted_object.h" namespace webrtc { AudioProcessingBuilder::AudioProcessingBuilder() = default; AudioProcessingBuilder::~AudioProcessingBuilder() = default; AudioProcessing* AudioProcessingBuilder::Create() { webrtc::Config config; return Create(config); } AudioProcessing* AudioProcessingBuilder::Create(const webrtc::Config& config) { #ifdef WEBRTC_EXCLUDE_AUDIO_PROCESSING_MODULE // Implementation returning a null pointer for using when the APM is excluded // from the build.. return nullptr; #else // Standard implementation. return new rtc::RefCountedObject( config, std::move(capture_post_processing_), std::move(render_pre_processing_), std::move(echo_control_factory_), std::move(echo_detector_), std::move(capture_analyzer_)); #endif } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/audio_processing_impl.cc0000664000175000017500000023152414475643423030055 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/audio_processing_impl.h" #include #include #include #include #include #include #include "absl/types/optional.h" #include "api/array_view.h" #include "api/audio/audio_frame.h" #include "common_audio/audio_converter.h" #include "common_audio/include/audio_util.h" #include "modules/audio_processing/aec_dump/aec_dump_factory.h" #include "modules/audio_processing/agc2/gain_applier.h" #include "modules/audio_processing/audio_buffer.h" #include "modules/audio_processing/common.h" #include "modules/audio_processing/include/audio_frame_view.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "modules/audio_processing/optionally_built_submodule_creators.h" #include "rtc_base/atomic_ops.h" #include "rtc_base/checks.h" #include "rtc_base/constructor_magic.h" #include "rtc_base/logging.h" #include "rtc_base/ref_counted_object.h" #include "rtc_base/time_utils.h" #include "rtc_base/trace_event.h" #include "system_wrappers/include/field_trial.h" #include "system_wrappers/include/metrics.h" #define RETURN_ON_ERR(expr) \ do { \ int err = (expr); \ if (err != kNoError) { \ return err; \ } \ } while (0) namespace webrtc { constexpr int kRuntimeSettingQueueSize = 100; namespace { static bool LayoutHasKeyboard(AudioProcessing::ChannelLayout layout) { switch (layout) { case AudioProcessing::kMono: case AudioProcessing::kStereo: return false; case AudioProcessing::kMonoAndKeyboard: case AudioProcessing::kStereoAndKeyboard: return true; } RTC_NOTREACHED(); return false; } bool SampleRateSupportsMultiBand(int sample_rate_hz) { return sample_rate_hz == AudioProcessing::kSampleRate32kHz || sample_rate_hz == AudioProcessing::kSampleRate48kHz; } // Checks whether the high-pass filter should be done in the full-band. bool EnforceSplitBandHpf() { return field_trial::IsEnabled("WebRTC-FullBandHpfKillSwitch"); } // Checks whether AEC3 should be allowed to decide what the default // configuration should be based on the render and capture channel configuration // at hand. bool UseSetupSpecificDefaultAec3Congfig() { return !field_trial::IsEnabled( "WebRTC-Aec3SetupSpecificDefaultConfigDefaultsKillSwitch"); } // Identify the native processing rate that best handles a sample rate. int SuitableProcessRate(int minimum_rate, int max_splitting_rate, bool band_splitting_required) { const int uppermost_native_rate = band_splitting_required ? max_splitting_rate : 48000; for (auto rate : {16000, 32000, 48000}) { if (rate >= uppermost_native_rate) { return uppermost_native_rate; } if (rate >= minimum_rate) { return rate; } } RTC_NOTREACHED(); return uppermost_native_rate; } GainControl::Mode Agc1ConfigModeToInterfaceMode( AudioProcessing::Config::GainController1::Mode mode) { using Agc1Config = AudioProcessing::Config::GainController1; switch (mode) { case Agc1Config::kAdaptiveAnalog: return GainControl::kAdaptiveAnalog; case Agc1Config::kAdaptiveDigital: return GainControl::kAdaptiveDigital; case Agc1Config::kFixedDigital: return GainControl::kFixedDigital; } } // Maximum lengths that frame of samples being passed from the render side to // the capture side can have (does not apply to AEC3). static const size_t kMaxAllowedValuesOfSamplesPerBand = 160; static const size_t kMaxAllowedValuesOfSamplesPerFrame = 480; // Maximum number of frames to buffer in the render queue. // TODO(peah): Decrease this once we properly handle hugely unbalanced // reverse and forward call numbers. static const size_t kMaxNumFramesToBuffer = 100; } // namespace // Throughout webrtc, it's assumed that success is represented by zero. static_assert(AudioProcessing::kNoError == 0, "kNoError must be zero"); AudioProcessingImpl::SubmoduleStates::SubmoduleStates( bool capture_post_processor_enabled, bool render_pre_processor_enabled, bool capture_analyzer_enabled) : capture_post_processor_enabled_(capture_post_processor_enabled), render_pre_processor_enabled_(render_pre_processor_enabled), capture_analyzer_enabled_(capture_analyzer_enabled) {} bool AudioProcessingImpl::SubmoduleStates::Update( bool high_pass_filter_enabled, bool mobile_echo_controller_enabled, bool residual_echo_detector_enabled, bool noise_suppressor_enabled, bool adaptive_gain_controller_enabled, bool gain_controller2_enabled, bool pre_amplifier_enabled, bool echo_controller_enabled, bool voice_detector_enabled, bool transient_suppressor_enabled) { bool changed = false; changed |= (high_pass_filter_enabled != high_pass_filter_enabled_); changed |= (mobile_echo_controller_enabled != mobile_echo_controller_enabled_); changed |= (residual_echo_detector_enabled != residual_echo_detector_enabled_); changed |= (noise_suppressor_enabled != noise_suppressor_enabled_); changed |= (adaptive_gain_controller_enabled != adaptive_gain_controller_enabled_); changed |= (gain_controller2_enabled != gain_controller2_enabled_); changed |= (pre_amplifier_enabled_ != pre_amplifier_enabled); changed |= (echo_controller_enabled != echo_controller_enabled_); changed |= (voice_detector_enabled != voice_detector_enabled_); changed |= (transient_suppressor_enabled != transient_suppressor_enabled_); if (changed) { high_pass_filter_enabled_ = high_pass_filter_enabled; mobile_echo_controller_enabled_ = mobile_echo_controller_enabled; residual_echo_detector_enabled_ = residual_echo_detector_enabled; noise_suppressor_enabled_ = noise_suppressor_enabled; adaptive_gain_controller_enabled_ = adaptive_gain_controller_enabled; gain_controller2_enabled_ = gain_controller2_enabled; pre_amplifier_enabled_ = pre_amplifier_enabled; echo_controller_enabled_ = echo_controller_enabled; voice_detector_enabled_ = voice_detector_enabled; transient_suppressor_enabled_ = transient_suppressor_enabled; } changed |= first_update_; first_update_ = false; return changed; } bool AudioProcessingImpl::SubmoduleStates::CaptureMultiBandSubModulesActive() const { return CaptureMultiBandProcessingPresent() || voice_detector_enabled_; } bool AudioProcessingImpl::SubmoduleStates::CaptureMultiBandProcessingPresent() const { // If echo controller is present, assume it performs active processing. return CaptureMultiBandProcessingActive(/*ec_processing_active=*/true); } bool AudioProcessingImpl::SubmoduleStates::CaptureMultiBandProcessingActive( bool ec_processing_active) const { return high_pass_filter_enabled_ || mobile_echo_controller_enabled_ || noise_suppressor_enabled_ || adaptive_gain_controller_enabled_ || (echo_controller_enabled_ && ec_processing_active); } bool AudioProcessingImpl::SubmoduleStates::CaptureFullBandProcessingActive() const { return gain_controller2_enabled_ || capture_post_processor_enabled_ || pre_amplifier_enabled_; } bool AudioProcessingImpl::SubmoduleStates::CaptureAnalyzerActive() const { return capture_analyzer_enabled_; } bool AudioProcessingImpl::SubmoduleStates::RenderMultiBandSubModulesActive() const { return RenderMultiBandProcessingActive() || mobile_echo_controller_enabled_ || adaptive_gain_controller_enabled_ || echo_controller_enabled_; } bool AudioProcessingImpl::SubmoduleStates::RenderFullBandProcessingActive() const { return render_pre_processor_enabled_; } bool AudioProcessingImpl::SubmoduleStates::RenderMultiBandProcessingActive() const { return false; } bool AudioProcessingImpl::SubmoduleStates::HighPassFilteringRequired() const { return high_pass_filter_enabled_ || mobile_echo_controller_enabled_ || noise_suppressor_enabled_; } AudioProcessingImpl::AudioProcessingImpl(const webrtc::Config& config) : AudioProcessingImpl(config, /*capture_post_processor=*/nullptr, /*render_pre_processor=*/nullptr, /*echo_control_factory=*/nullptr, /*echo_detector=*/nullptr, /*capture_analyzer=*/nullptr) {} int AudioProcessingImpl::instance_count_ = 0; AudioProcessingImpl::AudioProcessingImpl( const webrtc::Config& config, std::unique_ptr capture_post_processor, std::unique_ptr render_pre_processor, std::unique_ptr echo_control_factory, rtc::scoped_refptr echo_detector, std::unique_ptr capture_analyzer) : data_dumper_( new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), use_setup_specific_default_aec3_config_( UseSetupSpecificDefaultAec3Congfig()), capture_runtime_settings_(kRuntimeSettingQueueSize), render_runtime_settings_(kRuntimeSettingQueueSize), capture_runtime_settings_enqueuer_(&capture_runtime_settings_), render_runtime_settings_enqueuer_(&render_runtime_settings_), echo_control_factory_(std::move(echo_control_factory)), submodule_states_(!!capture_post_processor, !!render_pre_processor, !!capture_analyzer), submodules_(std::move(capture_post_processor), std::move(render_pre_processor), std::move(echo_detector), std::move(capture_analyzer)), constants_(!field_trial::IsEnabled( "WebRTC-ApmExperimentalMultiChannelRenderKillSwitch"), !field_trial::IsEnabled( "WebRTC-ApmExperimentalMultiChannelCaptureKillSwitch"), EnforceSplitBandHpf()), capture_nonlocked_() { RTC_LOG(LS_INFO) << "Injected APM submodules:" "\nEcho control factory: " << !!echo_control_factory_ << "\nEcho detector: " << !!submodules_.echo_detector << "\nCapture analyzer: " << !!submodules_.capture_analyzer << "\nCapture post processor: " << !!submodules_.capture_post_processor << "\nRender pre processor: " << !!submodules_.render_pre_processor; // Mark Echo Controller enabled if a factory is injected. capture_nonlocked_.echo_controller_enabled = static_cast(echo_control_factory_); // If no echo detector is injected, use the ResidualEchoDetector. if (!submodules_.echo_detector) { submodules_.echo_detector = new rtc::RefCountedObject(); } #if !(defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)) // TODO(webrtc:5298): Remove once the use of ExperimentalNs has been // deprecated. config_.transient_suppression.enabled = config.Get().enabled; // TODO(webrtc:5298): Remove once the use of ExperimentalAgc has been // deprecated. config_.gain_controller1.analog_gain_controller.enabled = config.Get().enabled; config_.gain_controller1.analog_gain_controller.startup_min_volume = config.Get().startup_min_volume; config_.gain_controller1.analog_gain_controller.clipped_level_min = config.Get().clipped_level_min; config_.gain_controller1.analog_gain_controller.enable_agc2_level_estimator = config.Get().enabled_agc2_level_estimator; config_.gain_controller1.analog_gain_controller.enable_digital_adaptive = !config.Get().digital_adaptive_disabled; #endif Initialize(); } AudioProcessingImpl::~AudioProcessingImpl() = default; int AudioProcessingImpl::Initialize() { // Run in a single-threaded manner during initialization. MutexLock lock_render(&mutex_render_); MutexLock lock_capture(&mutex_capture_); InitializeLocked(); return kNoError; } int AudioProcessingImpl::Initialize(int capture_input_sample_rate_hz, int capture_output_sample_rate_hz, int render_input_sample_rate_hz, ChannelLayout capture_input_layout, ChannelLayout capture_output_layout, ChannelLayout render_input_layout) { const ProcessingConfig processing_config = { {{capture_input_sample_rate_hz, ChannelsFromLayout(capture_input_layout), LayoutHasKeyboard(capture_input_layout)}, {capture_output_sample_rate_hz, ChannelsFromLayout(capture_output_layout), LayoutHasKeyboard(capture_output_layout)}, {render_input_sample_rate_hz, ChannelsFromLayout(render_input_layout), LayoutHasKeyboard(render_input_layout)}, {render_input_sample_rate_hz, ChannelsFromLayout(render_input_layout), LayoutHasKeyboard(render_input_layout)}}}; return Initialize(processing_config); } int AudioProcessingImpl::Initialize(const ProcessingConfig& processing_config) { // Run in a single-threaded manner during initialization. MutexLock lock_render(&mutex_render_); MutexLock lock_capture(&mutex_capture_); return InitializeLocked(processing_config); } int AudioProcessingImpl::MaybeInitializeRender( const ProcessingConfig& processing_config) { // Called from both threads. Thread check is therefore not possible. if (processing_config == formats_.api_format) { return kNoError; } MutexLock lock_capture(&mutex_capture_); return InitializeLocked(processing_config); } void AudioProcessingImpl::InitializeLocked() { UpdateActiveSubmoduleStates(); const int render_audiobuffer_sample_rate_hz = formats_.api_format.reverse_output_stream().num_frames() == 0 ? formats_.render_processing_format.sample_rate_hz() : formats_.api_format.reverse_output_stream().sample_rate_hz(); if (formats_.api_format.reverse_input_stream().num_channels() > 0) { render_.render_audio.reset(new AudioBuffer( formats_.api_format.reverse_input_stream().sample_rate_hz(), formats_.api_format.reverse_input_stream().num_channels(), formats_.render_processing_format.sample_rate_hz(), formats_.render_processing_format.num_channels(), render_audiobuffer_sample_rate_hz, formats_.render_processing_format.num_channels())); if (formats_.api_format.reverse_input_stream() != formats_.api_format.reverse_output_stream()) { render_.render_converter = AudioConverter::Create( formats_.api_format.reverse_input_stream().num_channels(), formats_.api_format.reverse_input_stream().num_frames(), formats_.api_format.reverse_output_stream().num_channels(), formats_.api_format.reverse_output_stream().num_frames()); } else { render_.render_converter.reset(nullptr); } } else { render_.render_audio.reset(nullptr); render_.render_converter.reset(nullptr); } capture_.capture_audio.reset(new AudioBuffer( formats_.api_format.input_stream().sample_rate_hz(), formats_.api_format.input_stream().num_channels(), capture_nonlocked_.capture_processing_format.sample_rate_hz(), formats_.api_format.output_stream().num_channels(), formats_.api_format.output_stream().sample_rate_hz(), formats_.api_format.output_stream().num_channels())); if (capture_nonlocked_.capture_processing_format.sample_rate_hz() < formats_.api_format.output_stream().sample_rate_hz() && formats_.api_format.output_stream().sample_rate_hz() == 48000) { capture_.capture_fullband_audio.reset( new AudioBuffer(formats_.api_format.input_stream().sample_rate_hz(), formats_.api_format.input_stream().num_channels(), formats_.api_format.output_stream().sample_rate_hz(), formats_.api_format.output_stream().num_channels(), formats_.api_format.output_stream().sample_rate_hz(), formats_.api_format.output_stream().num_channels())); } else { capture_.capture_fullband_audio.reset(); } AllocateRenderQueue(); InitializeGainController1(); InitializeTransientSuppressor(); InitializeHighPassFilter(true); InitializeVoiceDetector(); InitializeResidualEchoDetector(); InitializeEchoController(); InitializeGainController2(); InitializeNoiseSuppressor(); InitializeAnalyzer(); InitializePostProcessor(); InitializePreProcessor(); if (aec_dump_) { aec_dump_->WriteInitMessage(formats_.api_format, rtc::TimeUTCMillis()); } } int AudioProcessingImpl::InitializeLocked(const ProcessingConfig& config) { UpdateActiveSubmoduleStates(); for (const auto& stream : config.streams) { if (stream.num_channels() > 0 && stream.sample_rate_hz() <= 0) { return kBadSampleRateError; } } const size_t num_in_channels = config.input_stream().num_channels(); const size_t num_out_channels = config.output_stream().num_channels(); // Need at least one input channel. // Need either one output channel or as many outputs as there are inputs. if (num_in_channels == 0 || !(num_out_channels == 1 || num_out_channels == num_in_channels)) { return kBadNumberChannelsError; } formats_.api_format = config; // Choose maximum rate to use for the split filtering. RTC_DCHECK(config_.pipeline.maximum_internal_processing_rate == 48000 || config_.pipeline.maximum_internal_processing_rate == 32000); int max_splitting_rate = 48000; if (config_.pipeline.maximum_internal_processing_rate == 32000) { max_splitting_rate = config_.pipeline.maximum_internal_processing_rate; } int capture_processing_rate = SuitableProcessRate( std::min(formats_.api_format.input_stream().sample_rate_hz(), formats_.api_format.output_stream().sample_rate_hz()), max_splitting_rate, submodule_states_.CaptureMultiBandSubModulesActive() || submodule_states_.RenderMultiBandSubModulesActive()); RTC_DCHECK_NE(8000, capture_processing_rate); capture_nonlocked_.capture_processing_format = StreamConfig(capture_processing_rate); int render_processing_rate; if (!capture_nonlocked_.echo_controller_enabled) { render_processing_rate = SuitableProcessRate( std::min(formats_.api_format.reverse_input_stream().sample_rate_hz(), formats_.api_format.reverse_output_stream().sample_rate_hz()), max_splitting_rate, submodule_states_.CaptureMultiBandSubModulesActive() || submodule_states_.RenderMultiBandSubModulesActive()); } else { render_processing_rate = capture_processing_rate; } // If the forward sample rate is 8 kHz, the render stream is also processed // at this rate. if (capture_nonlocked_.capture_processing_format.sample_rate_hz() == kSampleRate8kHz) { render_processing_rate = kSampleRate8kHz; } else { render_processing_rate = std::max(render_processing_rate, static_cast(kSampleRate16kHz)); } RTC_DCHECK_NE(8000, render_processing_rate); if (submodule_states_.RenderMultiBandSubModulesActive()) { // By default, downmix the render stream to mono for analysis. This has been // demonstrated to work well for AEC in most practical scenarios. const bool multi_channel_render = config_.pipeline.multi_channel_render && constants_.multi_channel_render_support; int render_processing_num_channels = multi_channel_render ? formats_.api_format.reverse_input_stream().num_channels() : 1; formats_.render_processing_format = StreamConfig(render_processing_rate, render_processing_num_channels); } else { formats_.render_processing_format = StreamConfig( formats_.api_format.reverse_input_stream().sample_rate_hz(), formats_.api_format.reverse_input_stream().num_channels()); } if (capture_nonlocked_.capture_processing_format.sample_rate_hz() == kSampleRate32kHz || capture_nonlocked_.capture_processing_format.sample_rate_hz() == kSampleRate48kHz) { capture_nonlocked_.split_rate = kSampleRate16kHz; } else { capture_nonlocked_.split_rate = capture_nonlocked_.capture_processing_format.sample_rate_hz(); } InitializeLocked(); return kNoError; } void AudioProcessingImpl::ApplyConfig(const AudioProcessing::Config& config) { RTC_LOG(LS_INFO) << "AudioProcessing::ApplyConfig: " << config.ToString(); // Run in a single-threaded manner when applying the settings. MutexLock lock_render(&mutex_render_); MutexLock lock_capture(&mutex_capture_); const bool pipeline_config_changed = config_.pipeline.multi_channel_render != config.pipeline.multi_channel_render || config_.pipeline.multi_channel_capture != config.pipeline.multi_channel_capture || config_.pipeline.maximum_internal_processing_rate != config.pipeline.maximum_internal_processing_rate; const bool aec_config_changed = config_.echo_canceller.enabled != config.echo_canceller.enabled || config_.echo_canceller.mobile_mode != config.echo_canceller.mobile_mode; const bool agc1_config_changed = config_.gain_controller1.enabled != config.gain_controller1.enabled || config_.gain_controller1.mode != config.gain_controller1.mode || config_.gain_controller1.target_level_dbfs != config.gain_controller1.target_level_dbfs || config_.gain_controller1.compression_gain_db != config.gain_controller1.compression_gain_db || config_.gain_controller1.enable_limiter != config.gain_controller1.enable_limiter || config_.gain_controller1.analog_level_minimum != config.gain_controller1.analog_level_minimum || config_.gain_controller1.analog_level_maximum != config.gain_controller1.analog_level_maximum || config_.gain_controller1.analog_gain_controller.enabled != config.gain_controller1.analog_gain_controller.enabled || config_.gain_controller1.analog_gain_controller.startup_min_volume != config.gain_controller1.analog_gain_controller.startup_min_volume || config_.gain_controller1.analog_gain_controller.clipped_level_min != config.gain_controller1.analog_gain_controller.clipped_level_min || config_.gain_controller1.analog_gain_controller .enable_agc2_level_estimator != config.gain_controller1.analog_gain_controller .enable_agc2_level_estimator || config_.gain_controller1.analog_gain_controller.enable_digital_adaptive != config.gain_controller1.analog_gain_controller .enable_digital_adaptive; const bool agc2_config_changed = config_.gain_controller2.enabled != config.gain_controller2.enabled; const bool voice_detection_config_changed = config_.voice_detection.enabled != config.voice_detection.enabled; const bool ns_config_changed = config_.noise_suppression.enabled != config.noise_suppression.enabled || config_.noise_suppression.level != config.noise_suppression.level; const bool ts_config_changed = config_.transient_suppression.enabled != config.transient_suppression.enabled; const bool pre_amplifier_config_changed = config_.pre_amplifier.enabled != config.pre_amplifier.enabled || config_.pre_amplifier.fixed_gain_factor != config.pre_amplifier.fixed_gain_factor; config_ = config; if (aec_config_changed) { InitializeEchoController(); } if (ns_config_changed) { InitializeNoiseSuppressor(); } if (ts_config_changed) { InitializeTransientSuppressor(); } InitializeHighPassFilter(false); if (agc1_config_changed) { InitializeGainController1(); } const bool config_ok = GainController2::Validate(config_.gain_controller2); if (!config_ok) { RTC_LOG(LS_ERROR) << "AudioProcessing module config error\n" "Gain Controller 2: " << GainController2::ToString(config_.gain_controller2) << "\nReverting to default parameter set"; config_.gain_controller2 = AudioProcessing::Config::GainController2(); } if (agc2_config_changed) { InitializeGainController2(); } if (pre_amplifier_config_changed) { InitializePreAmplifier(); } if (config_.level_estimation.enabled && !submodules_.output_level_estimator) { submodules_.output_level_estimator = std::make_unique(); } if (voice_detection_config_changed) { InitializeVoiceDetector(); } // Reinitialization must happen after all submodule configuration to avoid // additional reinitializations on the next capture / render processing call. if (pipeline_config_changed) { InitializeLocked(formats_.api_format); } } void AudioProcessingImpl::OverrideSubmoduleCreationForTesting( const ApmSubmoduleCreationOverrides& overrides) { MutexLock lock(&mutex_capture_); submodule_creation_overrides_ = overrides; } int AudioProcessingImpl::proc_sample_rate_hz() const { // Used as callback from submodules, hence locking is not allowed. return capture_nonlocked_.capture_processing_format.sample_rate_hz(); } int AudioProcessingImpl::proc_fullband_sample_rate_hz() const { return capture_.capture_fullband_audio ? capture_.capture_fullband_audio->num_frames() * 100 : capture_nonlocked_.capture_processing_format.sample_rate_hz(); } int AudioProcessingImpl::proc_split_sample_rate_hz() const { // Used as callback from submodules, hence locking is not allowed. return capture_nonlocked_.split_rate; } size_t AudioProcessingImpl::num_reverse_channels() const { // Used as callback from submodules, hence locking is not allowed. return formats_.render_processing_format.num_channels(); } size_t AudioProcessingImpl::num_input_channels() const { // Used as callback from submodules, hence locking is not allowed. return formats_.api_format.input_stream().num_channels(); } size_t AudioProcessingImpl::num_proc_channels() const { // Used as callback from submodules, hence locking is not allowed. const bool multi_channel_capture = config_.pipeline.multi_channel_capture && constants_.multi_channel_capture_support; if (capture_nonlocked_.echo_controller_enabled && !multi_channel_capture) { return 1; } return num_output_channels(); } size_t AudioProcessingImpl::num_output_channels() const { // Used as callback from submodules, hence locking is not allowed. return formats_.api_format.output_stream().num_channels(); } void AudioProcessingImpl::set_output_will_be_muted(bool muted) { MutexLock lock(&mutex_capture_); capture_.output_will_be_muted = muted; if (submodules_.agc_manager.get()) { submodules_.agc_manager->SetCaptureMuted(capture_.output_will_be_muted); } } void AudioProcessingImpl::SetRuntimeSetting(RuntimeSetting setting) { switch (setting.type()) { case RuntimeSetting::Type::kCustomRenderProcessingRuntimeSetting: case RuntimeSetting::Type::kPlayoutAudioDeviceChange: render_runtime_settings_enqueuer_.Enqueue(setting); return; case RuntimeSetting::Type::kCapturePreGain: case RuntimeSetting::Type::kCaptureCompressionGain: case RuntimeSetting::Type::kCaptureFixedPostGain: case RuntimeSetting::Type::kCaptureOutputUsed: capture_runtime_settings_enqueuer_.Enqueue(setting); return; case RuntimeSetting::Type::kPlayoutVolumeChange: capture_runtime_settings_enqueuer_.Enqueue(setting); render_runtime_settings_enqueuer_.Enqueue(setting); return; case RuntimeSetting::Type::kNotSpecified: RTC_NOTREACHED(); return; } // The language allows the enum to have a non-enumerator // value. Check that this doesn't happen. RTC_NOTREACHED(); } AudioProcessingImpl::RuntimeSettingEnqueuer::RuntimeSettingEnqueuer( SwapQueue* runtime_settings) : runtime_settings_(*runtime_settings) { RTC_DCHECK(runtime_settings); } AudioProcessingImpl::RuntimeSettingEnqueuer::~RuntimeSettingEnqueuer() = default; void AudioProcessingImpl::RuntimeSettingEnqueuer::Enqueue( RuntimeSetting setting) { size_t remaining_attempts = 10; while (!runtime_settings_.Insert(&setting) && remaining_attempts-- > 0) { RuntimeSetting setting_to_discard; if (runtime_settings_.Remove(&setting_to_discard)) RTC_LOG(LS_ERROR) << "The runtime settings queue is full. Oldest setting discarded."; } if (remaining_attempts == 0) RTC_LOG(LS_ERROR) << "Cannot enqueue a new runtime setting."; } int AudioProcessingImpl::MaybeInitializeCapture( const StreamConfig& input_config, const StreamConfig& output_config) { ProcessingConfig processing_config; bool reinitialization_required = false; { // Acquire the capture lock in order to access api_format. The lock is // released immediately, as we may need to acquire the render lock as part // of the conditional reinitialization. MutexLock lock_capture(&mutex_capture_); processing_config = formats_.api_format; reinitialization_required = UpdateActiveSubmoduleStates(); } if (processing_config.input_stream() != input_config) { processing_config.input_stream() = input_config; reinitialization_required = true; } if (processing_config.output_stream() != output_config) { processing_config.output_stream() = output_config; reinitialization_required = true; } if (reinitialization_required) { MutexLock lock_render(&mutex_render_); MutexLock lock_capture(&mutex_capture_); RETURN_ON_ERR(InitializeLocked(processing_config)); } return kNoError; } int AudioProcessingImpl::ProcessStream(const float* const* src, const StreamConfig& input_config, const StreamConfig& output_config, float* const* dest) { TRACE_EVENT0("webrtc", "AudioProcessing::ProcessStream_StreamConfig"); if (!src || !dest) { return kNullPointerError; } RETURN_ON_ERR(MaybeInitializeCapture(input_config, output_config)); MutexLock lock_capture(&mutex_capture_); if (aec_dump_) { RecordUnprocessedCaptureStream(src); } capture_.keyboard_info.Extract(src, formats_.api_format.input_stream()); capture_.capture_audio->CopyFrom(src, formats_.api_format.input_stream()); if (capture_.capture_fullband_audio) { capture_.capture_fullband_audio->CopyFrom( src, formats_.api_format.input_stream()); } RETURN_ON_ERR(ProcessCaptureStreamLocked()); if (capture_.capture_fullband_audio) { capture_.capture_fullband_audio->CopyTo(formats_.api_format.output_stream(), dest); } else { capture_.capture_audio->CopyTo(formats_.api_format.output_stream(), dest); } if (aec_dump_) { RecordProcessedCaptureStream(dest); } return kNoError; } void AudioProcessingImpl::HandleCaptureRuntimeSettings() { RuntimeSetting setting; while (capture_runtime_settings_.Remove(&setting)) { if (aec_dump_) { aec_dump_->WriteRuntimeSetting(setting); } switch (setting.type()) { case RuntimeSetting::Type::kCapturePreGain: if (config_.pre_amplifier.enabled) { float value; setting.GetFloat(&value); config_.pre_amplifier.fixed_gain_factor = value; submodules_.pre_amplifier->SetGainFactor(value); } // TODO(bugs.chromium.org/9138): Log setting handling by Aec Dump. break; case RuntimeSetting::Type::kCaptureCompressionGain: { if (!submodules_.agc_manager) { float value; setting.GetFloat(&value); int int_value = static_cast(value + .5f); config_.gain_controller1.compression_gain_db = int_value; if (submodules_.gain_control) { int error = submodules_.gain_control->set_compression_gain_db(int_value); RTC_DCHECK_EQ(kNoError, error); } } break; } case RuntimeSetting::Type::kCaptureFixedPostGain: { if (submodules_.gain_controller2) { float value; setting.GetFloat(&value); config_.gain_controller2.fixed_digital.gain_db = value; submodules_.gain_controller2->ApplyConfig(config_.gain_controller2); } break; } case RuntimeSetting::Type::kPlayoutVolumeChange: { int value; setting.GetInt(&value); capture_.playout_volume = value; break; } case RuntimeSetting::Type::kPlayoutAudioDeviceChange: RTC_NOTREACHED(); break; case RuntimeSetting::Type::kCustomRenderProcessingRuntimeSetting: RTC_NOTREACHED(); break; case RuntimeSetting::Type::kNotSpecified: RTC_NOTREACHED(); break; case RuntimeSetting::Type::kCaptureOutputUsed: // TODO(b/154437967): Add support for reducing complexity when it is // known that the capture output will not be used. break; } } } void AudioProcessingImpl::HandleRenderRuntimeSettings() { RuntimeSetting setting; while (render_runtime_settings_.Remove(&setting)) { if (aec_dump_) { aec_dump_->WriteRuntimeSetting(setting); } switch (setting.type()) { case RuntimeSetting::Type::kPlayoutAudioDeviceChange: // fall-through case RuntimeSetting::Type::kPlayoutVolumeChange: // fall-through case RuntimeSetting::Type::kCustomRenderProcessingRuntimeSetting: if (submodules_.render_pre_processor) { submodules_.render_pre_processor->SetRuntimeSetting(setting); } break; case RuntimeSetting::Type::kCapturePreGain: // fall-through case RuntimeSetting::Type::kCaptureCompressionGain: // fall-through case RuntimeSetting::Type::kCaptureFixedPostGain: // fall-through case RuntimeSetting::Type::kCaptureOutputUsed: // fall-through case RuntimeSetting::Type::kNotSpecified: RTC_NOTREACHED(); break; } } } void AudioProcessingImpl::QueueBandedRenderAudio(AudioBuffer* audio) { RTC_DCHECK_GE(160, audio->num_frames_per_band()); if (submodules_.echo_control_mobile) { EchoControlMobileImpl::PackRenderAudioBuffer(audio, num_output_channels(), num_reverse_channels(), &aecm_render_queue_buffer_); RTC_DCHECK(aecm_render_signal_queue_); // Insert the samples into the queue. if (!aecm_render_signal_queue_->Insert(&aecm_render_queue_buffer_)) { // The data queue is full and needs to be emptied. EmptyQueuedRenderAudio(); // Retry the insert (should always work). bool result = aecm_render_signal_queue_->Insert(&aecm_render_queue_buffer_); RTC_DCHECK(result); } } if (!submodules_.agc_manager && submodules_.gain_control) { GainControlImpl::PackRenderAudioBuffer(*audio, &agc_render_queue_buffer_); // Insert the samples into the queue. if (!agc_render_signal_queue_->Insert(&agc_render_queue_buffer_)) { // The data queue is full and needs to be emptied. EmptyQueuedRenderAudio(); // Retry the insert (should always work). bool result = agc_render_signal_queue_->Insert(&agc_render_queue_buffer_); RTC_DCHECK(result); } } } void AudioProcessingImpl::QueueNonbandedRenderAudio(AudioBuffer* audio) { ResidualEchoDetector::PackRenderAudioBuffer(audio, &red_render_queue_buffer_); // Insert the samples into the queue. if (!red_render_signal_queue_->Insert(&red_render_queue_buffer_)) { // The data queue is full and needs to be emptied. EmptyQueuedRenderAudio(); // Retry the insert (should always work). bool result = red_render_signal_queue_->Insert(&red_render_queue_buffer_); RTC_DCHECK(result); } } void AudioProcessingImpl::AllocateRenderQueue() { const size_t new_agc_render_queue_element_max_size = std::max(static_cast(1), kMaxAllowedValuesOfSamplesPerBand); const size_t new_red_render_queue_element_max_size = std::max(static_cast(1), kMaxAllowedValuesOfSamplesPerFrame); // Reallocate the queues if the queue item sizes are too small to fit the // data to put in the queues. if (agc_render_queue_element_max_size_ < new_agc_render_queue_element_max_size) { agc_render_queue_element_max_size_ = new_agc_render_queue_element_max_size; std::vector template_queue_element( agc_render_queue_element_max_size_); agc_render_signal_queue_.reset( new SwapQueue, RenderQueueItemVerifier>( kMaxNumFramesToBuffer, template_queue_element, RenderQueueItemVerifier( agc_render_queue_element_max_size_))); agc_render_queue_buffer_.resize(agc_render_queue_element_max_size_); agc_capture_queue_buffer_.resize(agc_render_queue_element_max_size_); } else { agc_render_signal_queue_->Clear(); } if (red_render_queue_element_max_size_ < new_red_render_queue_element_max_size) { red_render_queue_element_max_size_ = new_red_render_queue_element_max_size; std::vector template_queue_element( red_render_queue_element_max_size_); red_render_signal_queue_.reset( new SwapQueue, RenderQueueItemVerifier>( kMaxNumFramesToBuffer, template_queue_element, RenderQueueItemVerifier( red_render_queue_element_max_size_))); red_render_queue_buffer_.resize(red_render_queue_element_max_size_); red_capture_queue_buffer_.resize(red_render_queue_element_max_size_); } else { red_render_signal_queue_->Clear(); } } void AudioProcessingImpl::EmptyQueuedRenderAudio() { MutexLock lock_capture(&mutex_capture_); EmptyQueuedRenderAudioLocked(); } void AudioProcessingImpl::EmptyQueuedRenderAudioLocked() { if (submodules_.echo_control_mobile) { RTC_DCHECK(aecm_render_signal_queue_); while (aecm_render_signal_queue_->Remove(&aecm_capture_queue_buffer_)) { submodules_.echo_control_mobile->ProcessRenderAudio( aecm_capture_queue_buffer_); } } if (submodules_.gain_control) { while (agc_render_signal_queue_->Remove(&agc_capture_queue_buffer_)) { submodules_.gain_control->ProcessRenderAudio(agc_capture_queue_buffer_); } } while (red_render_signal_queue_->Remove(&red_capture_queue_buffer_)) { RTC_DCHECK(submodules_.echo_detector); submodules_.echo_detector->AnalyzeRenderAudio(red_capture_queue_buffer_); } } int AudioProcessingImpl::ProcessStream(const int16_t* const src, const StreamConfig& input_config, const StreamConfig& output_config, int16_t* const dest) { TRACE_EVENT0("webrtc", "AudioProcessing::ProcessStream_AudioFrame"); RETURN_ON_ERR(MaybeInitializeCapture(input_config, output_config)); MutexLock lock_capture(&mutex_capture_); if (aec_dump_) { RecordUnprocessedCaptureStream(src, input_config); } capture_.capture_audio->CopyFrom(src, input_config); if (capture_.capture_fullband_audio) { capture_.capture_fullband_audio->CopyFrom(src, input_config); } RETURN_ON_ERR(ProcessCaptureStreamLocked()); if (submodule_states_.CaptureMultiBandProcessingPresent() || submodule_states_.CaptureFullBandProcessingActive()) { if (capture_.capture_fullband_audio) { capture_.capture_fullband_audio->CopyTo(output_config, dest); } else { capture_.capture_audio->CopyTo(output_config, dest); } } if (aec_dump_) { RecordProcessedCaptureStream(dest, output_config); } return kNoError; } int AudioProcessingImpl::ProcessCaptureStreamLocked() { EmptyQueuedRenderAudioLocked(); HandleCaptureRuntimeSettings(); // Ensure that not both the AEC and AECM are active at the same time. // TODO(peah): Simplify once the public API Enable functions for these // are moved to APM. RTC_DCHECK_LE( !!submodules_.echo_controller + !!submodules_.echo_control_mobile, 1); AudioBuffer* capture_buffer = capture_.capture_audio.get(); // For brevity. AudioBuffer* linear_aec_buffer = capture_.linear_aec_output.get(); if (submodules_.high_pass_filter && config_.high_pass_filter.apply_in_full_band && !constants_.enforce_split_band_hpf) { submodules_.high_pass_filter->Process(capture_buffer, /*use_split_band_data=*/false); } if (submodules_.pre_amplifier) { submodules_.pre_amplifier->ApplyGain(AudioFrameView( capture_buffer->channels(), capture_buffer->num_channels(), capture_buffer->num_frames())); } capture_input_rms_.Analyze(rtc::ArrayView( capture_buffer->channels_const()[0], capture_nonlocked_.capture_processing_format.num_frames())); const bool log_rms = ++capture_rms_interval_counter_ >= 1000; if (log_rms) { capture_rms_interval_counter_ = 0; RmsLevel::Levels levels = capture_input_rms_.AverageAndPeak(); RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.ApmCaptureInputLevelAverageRms", levels.average, 1, RmsLevel::kMinLevelDb, 64); RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.ApmCaptureInputLevelPeakRms", levels.peak, 1, RmsLevel::kMinLevelDb, 64); } if (submodules_.echo_controller) { // Detect and flag any change in the analog gain. int analog_mic_level = recommended_stream_analog_level_locked(); capture_.echo_path_gain_change = capture_.prev_analog_mic_level != analog_mic_level && capture_.prev_analog_mic_level != -1; capture_.prev_analog_mic_level = analog_mic_level; // Detect and flag any change in the pre-amplifier gain. if (submodules_.pre_amplifier) { float pre_amp_gain = submodules_.pre_amplifier->GetGainFactor(); capture_.echo_path_gain_change = capture_.echo_path_gain_change || (capture_.prev_pre_amp_gain != pre_amp_gain && capture_.prev_pre_amp_gain >= 0.f); capture_.prev_pre_amp_gain = pre_amp_gain; } // Detect volume change. capture_.echo_path_gain_change = capture_.echo_path_gain_change || (capture_.prev_playout_volume != capture_.playout_volume && capture_.prev_playout_volume >= 0); capture_.prev_playout_volume = capture_.playout_volume; submodules_.echo_controller->AnalyzeCapture(capture_buffer); } if (submodules_.agc_manager) { submodules_.agc_manager->AnalyzePreProcess(capture_buffer); } if (submodule_states_.CaptureMultiBandSubModulesActive() && SampleRateSupportsMultiBand( capture_nonlocked_.capture_processing_format.sample_rate_hz())) { capture_buffer->SplitIntoFrequencyBands(); } const bool multi_channel_capture = config_.pipeline.multi_channel_capture && constants_.multi_channel_capture_support; if (submodules_.echo_controller && !multi_channel_capture) { // Force down-mixing of the number of channels after the detection of // capture signal saturation. // TODO(peah): Look into ensuring that this kind of tampering with the // AudioBuffer functionality should not be needed. capture_buffer->set_num_channels(1); } if (submodules_.high_pass_filter && (!config_.high_pass_filter.apply_in_full_band || constants_.enforce_split_band_hpf)) { submodules_.high_pass_filter->Process(capture_buffer, /*use_split_band_data=*/true); } if (submodules_.gain_control) { RETURN_ON_ERR( submodules_.gain_control->AnalyzeCaptureAudio(*capture_buffer)); } if ((!config_.noise_suppression.analyze_linear_aec_output_when_available || !linear_aec_buffer || submodules_.echo_control_mobile) && submodules_.noise_suppressor) { submodules_.noise_suppressor->Analyze(*capture_buffer); } if (submodules_.echo_control_mobile) { // Ensure that the stream delay was set before the call to the // AECM ProcessCaptureAudio function. if (!capture_.was_stream_delay_set) { return AudioProcessing::kStreamParameterNotSetError; } if (submodules_.noise_suppressor) { submodules_.noise_suppressor->Process(capture_buffer); } RETURN_ON_ERR(submodules_.echo_control_mobile->ProcessCaptureAudio( capture_buffer, stream_delay_ms())); } else { if (submodules_.echo_controller) { data_dumper_->DumpRaw("stream_delay", stream_delay_ms()); if (capture_.was_stream_delay_set) { submodules_.echo_controller->SetAudioBufferDelay(stream_delay_ms()); } submodules_.echo_controller->ProcessCapture( capture_buffer, linear_aec_buffer, capture_.echo_path_gain_change); } if (config_.noise_suppression.analyze_linear_aec_output_when_available && linear_aec_buffer && submodules_.noise_suppressor) { submodules_.noise_suppressor->Analyze(*linear_aec_buffer); } if (submodules_.noise_suppressor) { submodules_.noise_suppressor->Process(capture_buffer); } } if (config_.voice_detection.enabled) { capture_.stats.voice_detected = submodules_.voice_detector->ProcessCaptureAudio(capture_buffer); } else { capture_.stats.voice_detected = absl::nullopt; } if (submodules_.agc_manager) { submodules_.agc_manager->Process(capture_buffer); absl::optional new_digital_gain = submodules_.agc_manager->GetDigitalComressionGain(); if (new_digital_gain && submodules_.gain_control) { submodules_.gain_control->set_compression_gain_db(*new_digital_gain); } } if (submodules_.gain_control) { // TODO(peah): Add reporting from AEC3 whether there is echo. RETURN_ON_ERR(submodules_.gain_control->ProcessCaptureAudio( capture_buffer, /*stream_has_echo*/ false)); } if (submodule_states_.CaptureMultiBandProcessingPresent() && SampleRateSupportsMultiBand( capture_nonlocked_.capture_processing_format.sample_rate_hz())) { capture_buffer->MergeFrequencyBands(); } if (capture_.capture_fullband_audio) { const auto& ec = submodules_.echo_controller; bool ec_active = ec ? ec->ActiveProcessing() : false; // Only update the fullband buffer if the multiband processing has changed // the signal. Keep the original signal otherwise. if (submodule_states_.CaptureMultiBandProcessingActive(ec_active)) { capture_buffer->CopyTo(capture_.capture_fullband_audio.get()); } capture_buffer = capture_.capture_fullband_audio.get(); } if (config_.residual_echo_detector.enabled) { RTC_DCHECK(submodules_.echo_detector); submodules_.echo_detector->AnalyzeCaptureAudio(rtc::ArrayView( capture_buffer->channels()[0], capture_buffer->num_frames())); } // TODO(aluebs): Investigate if the transient suppression placement should be // before or after the AGC. if (submodules_.transient_suppressor) { float voice_probability = submodules_.agc_manager.get() ? submodules_.agc_manager->voice_probability() : 1.f; submodules_.transient_suppressor->Suppress( capture_buffer->channels()[0], capture_buffer->num_frames(), capture_buffer->num_channels(), capture_buffer->split_bands_const(0)[kBand0To8kHz], capture_buffer->num_frames_per_band(), capture_.keyboard_info.keyboard_data, capture_.keyboard_info.num_keyboard_frames, voice_probability, capture_.key_pressed); } // Experimental APM sub-module that analyzes |capture_buffer|. if (submodules_.capture_analyzer) { submodules_.capture_analyzer->Analyze(capture_buffer); } if (submodules_.gain_controller2) { submodules_.gain_controller2->NotifyAnalogLevel( recommended_stream_analog_level_locked()); submodules_.gain_controller2->Process(capture_buffer); } if (submodules_.capture_post_processor) { submodules_.capture_post_processor->Process(capture_buffer); } // The level estimator operates on the recombined data. if (config_.level_estimation.enabled) { submodules_.output_level_estimator->ProcessStream(*capture_buffer); capture_.stats.output_rms_dbfs = submodules_.output_level_estimator->RMS(); } else { capture_.stats.output_rms_dbfs = absl::nullopt; } capture_output_rms_.Analyze(rtc::ArrayView( capture_buffer->channels_const()[0], capture_nonlocked_.capture_processing_format.num_frames())); if (log_rms) { RmsLevel::Levels levels = capture_output_rms_.AverageAndPeak(); RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.ApmCaptureOutputLevelAverageRms", levels.average, 1, RmsLevel::kMinLevelDb, 64); RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.ApmCaptureOutputLevelPeakRms", levels.peak, 1, RmsLevel::kMinLevelDb, 64); } if (submodules_.agc_manager) { int level = recommended_stream_analog_level_locked(); data_dumper_->DumpRaw("experimental_gain_control_stream_analog_level", 1, &level); } // Compute echo-related stats. if (submodules_.echo_controller) { auto ec_metrics = submodules_.echo_controller->GetMetrics(); capture_.stats.echo_return_loss = ec_metrics.echo_return_loss; capture_.stats.echo_return_loss_enhancement = ec_metrics.echo_return_loss_enhancement; capture_.stats.delay_ms = ec_metrics.delay_ms; } if (config_.residual_echo_detector.enabled) { RTC_DCHECK(submodules_.echo_detector); auto ed_metrics = submodules_.echo_detector->GetMetrics(); capture_.stats.residual_echo_likelihood = ed_metrics.echo_likelihood; capture_.stats.residual_echo_likelihood_recent_max = ed_metrics.echo_likelihood_recent_max; } // Pass stats for reporting. stats_reporter_.UpdateStatistics(capture_.stats); capture_.was_stream_delay_set = false; return kNoError; } int AudioProcessingImpl::AnalyzeReverseStream( const float* const* data, const StreamConfig& reverse_config) { TRACE_EVENT0("webrtc", "AudioProcessing::AnalyzeReverseStream_StreamConfig"); MutexLock lock(&mutex_render_); return AnalyzeReverseStreamLocked(data, reverse_config, reverse_config); } int AudioProcessingImpl::ProcessReverseStream(const float* const* src, const StreamConfig& input_config, const StreamConfig& output_config, float* const* dest) { TRACE_EVENT0("webrtc", "AudioProcessing::ProcessReverseStream_StreamConfig"); MutexLock lock(&mutex_render_); RETURN_ON_ERR(AnalyzeReverseStreamLocked(src, input_config, output_config)); if (submodule_states_.RenderMultiBandProcessingActive() || submodule_states_.RenderFullBandProcessingActive()) { render_.render_audio->CopyTo(formats_.api_format.reverse_output_stream(), dest); } else if (formats_.api_format.reverse_input_stream() != formats_.api_format.reverse_output_stream()) { render_.render_converter->Convert(src, input_config.num_samples(), dest, output_config.num_samples()); } else { CopyAudioIfNeeded(src, input_config.num_frames(), input_config.num_channels(), dest); } return kNoError; } int AudioProcessingImpl::AnalyzeReverseStreamLocked( const float* const* src, const StreamConfig& input_config, const StreamConfig& output_config) { if (src == nullptr) { return kNullPointerError; } if (input_config.num_channels() == 0) { return kBadNumberChannelsError; } ProcessingConfig processing_config = formats_.api_format; processing_config.reverse_input_stream() = input_config; processing_config.reverse_output_stream() = output_config; RETURN_ON_ERR(MaybeInitializeRender(processing_config)); RTC_DCHECK_EQ(input_config.num_frames(), formats_.api_format.reverse_input_stream().num_frames()); if (aec_dump_) { const size_t channel_size = formats_.api_format.reverse_input_stream().num_frames(); const size_t num_channels = formats_.api_format.reverse_input_stream().num_channels(); aec_dump_->WriteRenderStreamMessage( AudioFrameView(src, num_channels, channel_size)); } render_.render_audio->CopyFrom(src, formats_.api_format.reverse_input_stream()); return ProcessRenderStreamLocked(); } int AudioProcessingImpl::ProcessReverseStream(const int16_t* const src, const StreamConfig& input_config, const StreamConfig& output_config, int16_t* const dest) { TRACE_EVENT0("webrtc", "AudioProcessing::ProcessReverseStream_AudioFrame"); if (input_config.num_channels() <= 0) { return AudioProcessing::Error::kBadNumberChannelsError; } MutexLock lock(&mutex_render_); ProcessingConfig processing_config = formats_.api_format; processing_config.reverse_input_stream().set_sample_rate_hz( input_config.sample_rate_hz()); processing_config.reverse_input_stream().set_num_channels( input_config.num_channels()); processing_config.reverse_output_stream().set_sample_rate_hz( output_config.sample_rate_hz()); processing_config.reverse_output_stream().set_num_channels( output_config.num_channels()); RETURN_ON_ERR(MaybeInitializeRender(processing_config)); if (input_config.num_frames() != formats_.api_format.reverse_input_stream().num_frames()) { return kBadDataLengthError; } if (aec_dump_) { aec_dump_->WriteRenderStreamMessage(src, input_config.num_frames(), input_config.num_channels()); } render_.render_audio->CopyFrom(src, input_config); RETURN_ON_ERR(ProcessRenderStreamLocked()); if (submodule_states_.RenderMultiBandProcessingActive() || submodule_states_.RenderFullBandProcessingActive()) { render_.render_audio->CopyTo(output_config, dest); } return kNoError; } int AudioProcessingImpl::ProcessRenderStreamLocked() { AudioBuffer* render_buffer = render_.render_audio.get(); // For brevity. HandleRenderRuntimeSettings(); if (submodules_.render_pre_processor) { submodules_.render_pre_processor->Process(render_buffer); } QueueNonbandedRenderAudio(render_buffer); if (submodule_states_.RenderMultiBandSubModulesActive() && SampleRateSupportsMultiBand( formats_.render_processing_format.sample_rate_hz())) { render_buffer->SplitIntoFrequencyBands(); } if (submodule_states_.RenderMultiBandSubModulesActive()) { QueueBandedRenderAudio(render_buffer); } // TODO(peah): Perform the queuing inside QueueRenderAudiuo(). if (submodules_.echo_controller) { submodules_.echo_controller->AnalyzeRender(render_buffer); } if (submodule_states_.RenderMultiBandProcessingActive() && SampleRateSupportsMultiBand( formats_.render_processing_format.sample_rate_hz())) { render_buffer->MergeFrequencyBands(); } return kNoError; } int AudioProcessingImpl::set_stream_delay_ms(int delay) { MutexLock lock(&mutex_capture_); Error retval = kNoError; capture_.was_stream_delay_set = true; if (delay < 0) { delay = 0; retval = kBadStreamParameterWarning; } // TODO(ajm): the max is rather arbitrarily chosen; investigate. if (delay > 500) { delay = 500; retval = kBadStreamParameterWarning; } capture_nonlocked_.stream_delay_ms = delay; return retval; } bool AudioProcessingImpl::GetLinearAecOutput( rtc::ArrayView> linear_output) const { MutexLock lock(&mutex_capture_); AudioBuffer* linear_aec_buffer = capture_.linear_aec_output.get(); RTC_DCHECK(linear_aec_buffer); if (linear_aec_buffer) { RTC_DCHECK_EQ(1, linear_aec_buffer->num_bands()); RTC_DCHECK_EQ(linear_output.size(), linear_aec_buffer->num_channels()); for (size_t ch = 0; ch < linear_aec_buffer->num_channels(); ++ch) { RTC_DCHECK_EQ(linear_output[ch].size(), linear_aec_buffer->num_frames()); rtc::ArrayView channel_view = rtc::ArrayView(linear_aec_buffer->channels_const()[ch], linear_aec_buffer->num_frames()); std::copy(channel_view.begin(), channel_view.end(), linear_output[ch].begin()); } return true; } RTC_LOG(LS_ERROR) << "No linear AEC output available"; RTC_NOTREACHED(); return false; } int AudioProcessingImpl::stream_delay_ms() const { // Used as callback from submodules, hence locking is not allowed. return capture_nonlocked_.stream_delay_ms; } void AudioProcessingImpl::set_stream_key_pressed(bool key_pressed) { MutexLock lock(&mutex_capture_); capture_.key_pressed = key_pressed; } void AudioProcessingImpl::set_stream_analog_level(int level) { MutexLock lock_capture(&mutex_capture_); if (submodules_.agc_manager) { submodules_.agc_manager->set_stream_analog_level(level); data_dumper_->DumpRaw("experimental_gain_control_set_stream_analog_level", 1, &level); } else if (submodules_.gain_control) { int error = submodules_.gain_control->set_stream_analog_level(level); RTC_DCHECK_EQ(kNoError, error); } else { capture_.cached_stream_analog_level_ = level; } } int AudioProcessingImpl::recommended_stream_analog_level() const { MutexLock lock_capture(&mutex_capture_); return recommended_stream_analog_level_locked(); } int AudioProcessingImpl::recommended_stream_analog_level_locked() const { if (submodules_.agc_manager) { return submodules_.agc_manager->stream_analog_level(); } else if (submodules_.gain_control) { return submodules_.gain_control->stream_analog_level(); } else { return capture_.cached_stream_analog_level_; } } bool AudioProcessingImpl::CreateAndAttachAecDump(const std::string& file_name, int64_t max_log_size_bytes, rtc::TaskQueue* worker_queue) { std::unique_ptr aec_dump = AecDumpFactory::Create(file_name, max_log_size_bytes, worker_queue); if (!aec_dump) { return false; } AttachAecDump(std::move(aec_dump)); return true; } bool AudioProcessingImpl::CreateAndAttachAecDump(FILE* handle, int64_t max_log_size_bytes, rtc::TaskQueue* worker_queue) { std::unique_ptr aec_dump = AecDumpFactory::Create(handle, max_log_size_bytes, worker_queue); if (!aec_dump) { return false; } AttachAecDump(std::move(aec_dump)); return true; } void AudioProcessingImpl::AttachAecDump(std::unique_ptr aec_dump) { RTC_DCHECK(aec_dump); MutexLock lock_render(&mutex_render_); MutexLock lock_capture(&mutex_capture_); // The previously attached AecDump will be destroyed with the // 'aec_dump' parameter, which is after locks are released. aec_dump_.swap(aec_dump); WriteAecDumpConfigMessage(true); aec_dump_->WriteInitMessage(formats_.api_format, rtc::TimeUTCMillis()); } void AudioProcessingImpl::DetachAecDump() { // The d-tor of a task-queue based AecDump blocks until all pending // tasks are done. This construction avoids blocking while holding // the render and capture locks. std::unique_ptr aec_dump = nullptr; { MutexLock lock_render(&mutex_render_); MutexLock lock_capture(&mutex_capture_); aec_dump = std::move(aec_dump_); } } void AudioProcessingImpl::MutateConfig( rtc::FunctionView mutator) { MutexLock lock_render(&mutex_render_); MutexLock lock_capture(&mutex_capture_); mutator(&config_); ApplyConfig(config_); } AudioProcessing::Config AudioProcessingImpl::GetConfig() const { MutexLock lock_render(&mutex_render_); MutexLock lock_capture(&mutex_capture_); return config_; } bool AudioProcessingImpl::UpdateActiveSubmoduleStates() { return submodule_states_.Update( config_.high_pass_filter.enabled, !!submodules_.echo_control_mobile, config_.residual_echo_detector.enabled, !!submodules_.noise_suppressor, !!submodules_.gain_control, !!submodules_.gain_controller2, config_.pre_amplifier.enabled, capture_nonlocked_.echo_controller_enabled, config_.voice_detection.enabled, !!submodules_.transient_suppressor); } void AudioProcessingImpl::InitializeTransientSuppressor() { if (config_.transient_suppression.enabled) { // Attempt to create a transient suppressor, if one is not already created. if (!submodules_.transient_suppressor) { submodules_.transient_suppressor = CreateTransientSuppressor(submodule_creation_overrides_); } if (submodules_.transient_suppressor) { submodules_.transient_suppressor->Initialize( proc_fullband_sample_rate_hz(), capture_nonlocked_.split_rate, num_proc_channels()); } else { RTC_LOG(LS_WARNING) << "No transient suppressor created (probably disabled)"; } } else { submodules_.transient_suppressor.reset(); } } void AudioProcessingImpl::InitializeHighPassFilter(bool forced_reset) { bool high_pass_filter_needed_by_aec = config_.echo_canceller.enabled && config_.echo_canceller.enforce_high_pass_filtering && !config_.echo_canceller.mobile_mode; if (submodule_states_.HighPassFilteringRequired() || high_pass_filter_needed_by_aec) { bool use_full_band = config_.high_pass_filter.apply_in_full_band && !constants_.enforce_split_band_hpf; int rate = use_full_band ? proc_fullband_sample_rate_hz() : proc_split_sample_rate_hz(); size_t num_channels = use_full_band ? num_output_channels() : num_proc_channels(); if (!submodules_.high_pass_filter || rate != submodules_.high_pass_filter->sample_rate_hz() || forced_reset || num_channels != submodules_.high_pass_filter->num_channels()) { submodules_.high_pass_filter.reset( new HighPassFilter(rate, num_channels)); } } else { submodules_.high_pass_filter.reset(); } } void AudioProcessingImpl::InitializeVoiceDetector() { if (config_.voice_detection.enabled) { submodules_.voice_detector = std::make_unique( proc_split_sample_rate_hz(), VoiceDetection::kVeryLowLikelihood); } else { submodules_.voice_detector.reset(); } } void AudioProcessingImpl::InitializeEchoController() { bool use_echo_controller = echo_control_factory_ || (config_.echo_canceller.enabled && !config_.echo_canceller.mobile_mode); if (use_echo_controller) { // Create and activate the echo controller. if (echo_control_factory_) { submodules_.echo_controller = echo_control_factory_->Create( proc_sample_rate_hz(), num_reverse_channels(), num_proc_channels()); RTC_DCHECK(submodules_.echo_controller); } else { EchoCanceller3Config config = use_setup_specific_default_aec3_config_ ? EchoCanceller3::CreateDefaultConfig(num_reverse_channels(), num_proc_channels()) : EchoCanceller3Config(); submodules_.echo_controller = std::make_unique( config, proc_sample_rate_hz(), num_reverse_channels(), num_proc_channels()); } // Setup the storage for returning the linear AEC output. if (config_.echo_canceller.export_linear_aec_output) { constexpr int kLinearOutputRateHz = 16000; capture_.linear_aec_output = std::make_unique( kLinearOutputRateHz, num_proc_channels(), kLinearOutputRateHz, num_proc_channels(), kLinearOutputRateHz, num_proc_channels()); } else { capture_.linear_aec_output.reset(); } capture_nonlocked_.echo_controller_enabled = true; submodules_.echo_control_mobile.reset(); aecm_render_signal_queue_.reset(); return; } submodules_.echo_controller.reset(); capture_nonlocked_.echo_controller_enabled = false; capture_.linear_aec_output.reset(); if (!config_.echo_canceller.enabled) { submodules_.echo_control_mobile.reset(); aecm_render_signal_queue_.reset(); return; } if (config_.echo_canceller.mobile_mode) { // Create and activate AECM. size_t max_element_size = std::max(static_cast(1), kMaxAllowedValuesOfSamplesPerBand * EchoControlMobileImpl::NumCancellersRequired( num_output_channels(), num_reverse_channels())); std::vector template_queue_element(max_element_size); aecm_render_signal_queue_.reset( new SwapQueue, RenderQueueItemVerifier>( kMaxNumFramesToBuffer, template_queue_element, RenderQueueItemVerifier(max_element_size))); aecm_render_queue_buffer_.resize(max_element_size); aecm_capture_queue_buffer_.resize(max_element_size); submodules_.echo_control_mobile.reset(new EchoControlMobileImpl()); submodules_.echo_control_mobile->Initialize(proc_split_sample_rate_hz(), num_reverse_channels(), num_output_channels()); return; } submodules_.echo_control_mobile.reset(); aecm_render_signal_queue_.reset(); } void AudioProcessingImpl::InitializeGainController1() { if (!config_.gain_controller1.enabled) { submodules_.agc_manager.reset(); submodules_.gain_control.reset(); return; } if (!submodules_.gain_control) { submodules_.gain_control.reset(new GainControlImpl()); } submodules_.gain_control->Initialize(num_proc_channels(), proc_sample_rate_hz()); if (!config_.gain_controller1.analog_gain_controller.enabled) { int error = submodules_.gain_control->set_mode( Agc1ConfigModeToInterfaceMode(config_.gain_controller1.mode)); RTC_DCHECK_EQ(kNoError, error); error = submodules_.gain_control->set_target_level_dbfs( config_.gain_controller1.target_level_dbfs); RTC_DCHECK_EQ(kNoError, error); error = submodules_.gain_control->set_compression_gain_db( config_.gain_controller1.compression_gain_db); RTC_DCHECK_EQ(kNoError, error); error = submodules_.gain_control->enable_limiter( config_.gain_controller1.enable_limiter); RTC_DCHECK_EQ(kNoError, error); error = submodules_.gain_control->set_analog_level_limits( config_.gain_controller1.analog_level_minimum, config_.gain_controller1.analog_level_maximum); RTC_DCHECK_EQ(kNoError, error); submodules_.agc_manager.reset(); return; } if (!submodules_.agc_manager.get() || submodules_.agc_manager->num_channels() != static_cast(num_proc_channels()) || submodules_.agc_manager->sample_rate_hz() != capture_nonlocked_.split_rate) { int stream_analog_level = -1; const bool re_creation = !!submodules_.agc_manager; if (re_creation) { stream_analog_level = submodules_.agc_manager->stream_analog_level(); } submodules_.agc_manager.reset(new AgcManagerDirect( num_proc_channels(), config_.gain_controller1.analog_gain_controller.startup_min_volume, config_.gain_controller1.analog_gain_controller.clipped_level_min, config_.gain_controller1.analog_gain_controller .enable_agc2_level_estimator, !config_.gain_controller1.analog_gain_controller .enable_digital_adaptive, capture_nonlocked_.split_rate)); if (re_creation) { submodules_.agc_manager->set_stream_analog_level(stream_analog_level); } } submodules_.agc_manager->Initialize(); submodules_.agc_manager->SetupDigitalGainControl( submodules_.gain_control.get()); submodules_.agc_manager->SetCaptureMuted(capture_.output_will_be_muted); } void AudioProcessingImpl::InitializeGainController2() { if (config_.gain_controller2.enabled) { if (!submodules_.gain_controller2) { // TODO(alessiob): Move the injected gain controller once injection is // implemented. submodules_.gain_controller2.reset(new GainController2()); } submodules_.gain_controller2->Initialize(proc_fullband_sample_rate_hz()); submodules_.gain_controller2->ApplyConfig(config_.gain_controller2); } else { submodules_.gain_controller2.reset(); } } void AudioProcessingImpl::InitializeNoiseSuppressor() { submodules_.noise_suppressor.reset(); if (config_.noise_suppression.enabled) { auto map_level = [](AudioProcessing::Config::NoiseSuppression::Level level) { using NoiseSuppresionConfig = AudioProcessing::Config::NoiseSuppression; switch (level) { case NoiseSuppresionConfig::kLow: return NsConfig::SuppressionLevel::k6dB; case NoiseSuppresionConfig::kModerate: return NsConfig::SuppressionLevel::k12dB; case NoiseSuppresionConfig::kHigh: return NsConfig::SuppressionLevel::k18dB; case NoiseSuppresionConfig::kVeryHigh: return NsConfig::SuppressionLevel::k21dB; default: RTC_NOTREACHED(); } }; NsConfig cfg; cfg.target_level = map_level(config_.noise_suppression.level); submodules_.noise_suppressor = std::make_unique( cfg, proc_sample_rate_hz(), num_proc_channels()); } } void AudioProcessingImpl::InitializePreAmplifier() { if (config_.pre_amplifier.enabled) { submodules_.pre_amplifier.reset( new GainApplier(true, config_.pre_amplifier.fixed_gain_factor)); } else { submodules_.pre_amplifier.reset(); } } void AudioProcessingImpl::InitializeResidualEchoDetector() { RTC_DCHECK(submodules_.echo_detector); submodules_.echo_detector->Initialize( proc_fullband_sample_rate_hz(), 1, formats_.render_processing_format.sample_rate_hz(), 1); } void AudioProcessingImpl::InitializeAnalyzer() { if (submodules_.capture_analyzer) { submodules_.capture_analyzer->Initialize(proc_fullband_sample_rate_hz(), num_proc_channels()); } } void AudioProcessingImpl::InitializePostProcessor() { if (submodules_.capture_post_processor) { submodules_.capture_post_processor->Initialize( proc_fullband_sample_rate_hz(), num_proc_channels()); } } void AudioProcessingImpl::InitializePreProcessor() { if (submodules_.render_pre_processor) { submodules_.render_pre_processor->Initialize( formats_.render_processing_format.sample_rate_hz(), formats_.render_processing_format.num_channels()); } } void AudioProcessingImpl::WriteAecDumpConfigMessage(bool forced) { if (!aec_dump_) { return; } std::string experiments_description = ""; // TODO(peah): Add semicolon-separated concatenations of experiment // descriptions for other submodules. if (config_.gain_controller1.analog_gain_controller.clipped_level_min != kClippedLevelMin) { experiments_description += "AgcClippingLevelExperiment;"; } if (!!submodules_.capture_post_processor) { experiments_description += "CapturePostProcessor;"; } if (!!submodules_.render_pre_processor) { experiments_description += "RenderPreProcessor;"; } if (capture_nonlocked_.echo_controller_enabled) { experiments_description += "EchoController;"; } if (config_.gain_controller2.enabled) { experiments_description += "GainController2;"; } InternalAPMConfig apm_config; apm_config.aec_enabled = config_.echo_canceller.enabled; apm_config.aec_delay_agnostic_enabled = false; apm_config.aec_extended_filter_enabled = false; apm_config.aec_suppression_level = 0; apm_config.aecm_enabled = !!submodules_.echo_control_mobile; apm_config.aecm_comfort_noise_enabled = submodules_.echo_control_mobile && submodules_.echo_control_mobile->is_comfort_noise_enabled(); apm_config.aecm_routing_mode = submodules_.echo_control_mobile ? static_cast(submodules_.echo_control_mobile->routing_mode()) : 0; apm_config.agc_enabled = !!submodules_.gain_control; apm_config.agc_mode = submodules_.gain_control ? static_cast(submodules_.gain_control->mode()) : GainControl::kAdaptiveAnalog; apm_config.agc_limiter_enabled = submodules_.gain_control ? submodules_.gain_control->is_limiter_enabled() : false; apm_config.noise_robust_agc_enabled = !!submodules_.agc_manager; apm_config.hpf_enabled = config_.high_pass_filter.enabled; apm_config.ns_enabled = config_.noise_suppression.enabled; apm_config.ns_level = static_cast(config_.noise_suppression.level); apm_config.transient_suppression_enabled = config_.transient_suppression.enabled; apm_config.experiments_description = experiments_description; apm_config.pre_amplifier_enabled = config_.pre_amplifier.enabled; apm_config.pre_amplifier_fixed_gain_factor = config_.pre_amplifier.fixed_gain_factor; if (!forced && apm_config == apm_config_for_aec_dump_) { return; } aec_dump_->WriteConfig(apm_config); apm_config_for_aec_dump_ = apm_config; } void AudioProcessingImpl::RecordUnprocessedCaptureStream( const float* const* src) { RTC_DCHECK(aec_dump_); WriteAecDumpConfigMessage(false); const size_t channel_size = formats_.api_format.input_stream().num_frames(); const size_t num_channels = formats_.api_format.input_stream().num_channels(); aec_dump_->AddCaptureStreamInput( AudioFrameView(src, num_channels, channel_size)); RecordAudioProcessingState(); } void AudioProcessingImpl::RecordUnprocessedCaptureStream( const int16_t* const data, const StreamConfig& config) { RTC_DCHECK(aec_dump_); WriteAecDumpConfigMessage(false); aec_dump_->AddCaptureStreamInput(data, config.num_channels(), config.num_frames()); RecordAudioProcessingState(); } void AudioProcessingImpl::RecordProcessedCaptureStream( const float* const* processed_capture_stream) { RTC_DCHECK(aec_dump_); const size_t channel_size = formats_.api_format.output_stream().num_frames(); const size_t num_channels = formats_.api_format.output_stream().num_channels(); aec_dump_->AddCaptureStreamOutput(AudioFrameView( processed_capture_stream, num_channels, channel_size)); aec_dump_->WriteCaptureStreamMessage(); } void AudioProcessingImpl::RecordProcessedCaptureStream( const int16_t* const data, const StreamConfig& config) { RTC_DCHECK(aec_dump_); aec_dump_->AddCaptureStreamOutput(data, config.num_channels(), config.num_frames()); aec_dump_->WriteCaptureStreamMessage(); } void AudioProcessingImpl::RecordAudioProcessingState() { RTC_DCHECK(aec_dump_); AecDump::AudioProcessingState audio_proc_state; audio_proc_state.delay = capture_nonlocked_.stream_delay_ms; audio_proc_state.drift = 0; audio_proc_state.level = recommended_stream_analog_level_locked(); audio_proc_state.keypress = capture_.key_pressed; aec_dump_->AddAudioProcessingState(audio_proc_state); } AudioProcessingImpl::ApmCaptureState::ApmCaptureState() : was_stream_delay_set(false), output_will_be_muted(false), key_pressed(false), capture_processing_format(kSampleRate16kHz), split_rate(kSampleRate16kHz), echo_path_gain_change(false), prev_analog_mic_level(-1), prev_pre_amp_gain(-1.f), playout_volume(-1), prev_playout_volume(-1) {} AudioProcessingImpl::ApmCaptureState::~ApmCaptureState() = default; void AudioProcessingImpl::ApmCaptureState::KeyboardInfo::Extract( const float* const* data, const StreamConfig& stream_config) { if (stream_config.has_keyboard()) { keyboard_data = data[stream_config.num_channels()]; } else { keyboard_data = NULL; } num_keyboard_frames = stream_config.num_frames(); } AudioProcessingImpl::ApmRenderState::ApmRenderState() = default; AudioProcessingImpl::ApmRenderState::~ApmRenderState() = default; AudioProcessingImpl::ApmStatsReporter::ApmStatsReporter() : stats_message_queue_(1) {} AudioProcessingImpl::ApmStatsReporter::~ApmStatsReporter() = default; AudioProcessingStats AudioProcessingImpl::ApmStatsReporter::GetStatistics() { MutexLock lock_stats(&mutex_stats_); bool new_stats_available = stats_message_queue_.Remove(&cached_stats_); // If the message queue is full, return the cached stats. static_cast(new_stats_available); return cached_stats_; } void AudioProcessingImpl::ApmStatsReporter::UpdateStatistics( const AudioProcessingStats& new_stats) { AudioProcessingStats stats_to_queue = new_stats; bool stats_message_passed = stats_message_queue_.Insert(&stats_to_queue); // If the message queue is full, discard the new stats. static_cast(stats_message_passed); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/audio_processing_impl.h0000664000175000017500000005533514475643423027723 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AUDIO_PROCESSING_IMPL_H_ #define MODULES_AUDIO_PROCESSING_AUDIO_PROCESSING_IMPL_H_ #include #include #include #include #include #include "api/function_view.h" #include "modules/audio_processing/aec3/echo_canceller3.h" #include "modules/audio_processing/agc/agc_manager_direct.h" #include "modules/audio_processing/agc/gain_control.h" #include "modules/audio_processing/audio_buffer.h" #include "modules/audio_processing/echo_control_mobile_impl.h" #include "modules/audio_processing/gain_control_impl.h" #include "modules/audio_processing/gain_controller2.h" #include "modules/audio_processing/high_pass_filter.h" #include "modules/audio_processing/include/aec_dump.h" #include "modules/audio_processing/include/audio_frame_proxies.h" #include "modules/audio_processing/include/audio_processing.h" #include "modules/audio_processing/include/audio_processing_statistics.h" #include "modules/audio_processing/level_estimator.h" #include "modules/audio_processing/ns/noise_suppressor.h" #include "modules/audio_processing/optionally_built_submodule_creators.h" #include "modules/audio_processing/render_queue_item_verifier.h" #include "modules/audio_processing/residual_echo_detector.h" #include "modules/audio_processing/rms_level.h" #include "modules/audio_processing/transient/transient_suppressor.h" #include "modules/audio_processing/voice_detection.h" #include "rtc_base/gtest_prod_util.h" #include "rtc_base/ignore_wundef.h" #include "rtc_base/swap_queue.h" #include "rtc_base/synchronization/mutex.h" #include "rtc_base/thread_annotations.h" namespace webrtc { class ApmDataDumper; class AudioConverter; class AudioProcessingImpl : public AudioProcessing { public: // Methods forcing APM to run in a single-threaded manner. // Acquires both the render and capture locks. explicit AudioProcessingImpl(const webrtc::Config& config); // AudioProcessingImpl takes ownership of capture post processor. AudioProcessingImpl(const webrtc::Config& config, std::unique_ptr capture_post_processor, std::unique_ptr render_pre_processor, std::unique_ptr echo_control_factory, rtc::scoped_refptr echo_detector, std::unique_ptr capture_analyzer); ~AudioProcessingImpl() override; int Initialize() override; int Initialize(int capture_input_sample_rate_hz, int capture_output_sample_rate_hz, int render_sample_rate_hz, ChannelLayout capture_input_layout, ChannelLayout capture_output_layout, ChannelLayout render_input_layout) override; int Initialize(const ProcessingConfig& processing_config) override; void ApplyConfig(const AudioProcessing::Config& config) override; bool CreateAndAttachAecDump(const std::string& file_name, int64_t max_log_size_bytes, rtc::TaskQueue* worker_queue) override; bool CreateAndAttachAecDump(FILE* handle, int64_t max_log_size_bytes, rtc::TaskQueue* worker_queue) override; // TODO(webrtc:5298) Deprecated variant. void AttachAecDump(std::unique_ptr aec_dump) override; void DetachAecDump() override; void SetRuntimeSetting(RuntimeSetting setting) override; // Capture-side exclusive methods possibly running APM in a // multi-threaded manner. Acquire the capture lock. int ProcessStream(const int16_t* const src, const StreamConfig& input_config, const StreamConfig& output_config, int16_t* const dest) override; int ProcessStream(const float* const* src, const StreamConfig& input_config, const StreamConfig& output_config, float* const* dest) override; bool GetLinearAecOutput( rtc::ArrayView> linear_output) const override; void set_output_will_be_muted(bool muted) override; int set_stream_delay_ms(int delay) override; void set_stream_key_pressed(bool key_pressed) override; void set_stream_analog_level(int level) override; int recommended_stream_analog_level() const RTC_LOCKS_EXCLUDED(mutex_capture_) override; // Render-side exclusive methods possibly running APM in a // multi-threaded manner. Acquire the render lock. int ProcessReverseStream(const int16_t* const src, const StreamConfig& input_config, const StreamConfig& output_config, int16_t* const dest) override; int AnalyzeReverseStream(const float* const* data, const StreamConfig& reverse_config) override; int ProcessReverseStream(const float* const* src, const StreamConfig& input_config, const StreamConfig& output_config, float* const* dest) override; // Methods only accessed from APM submodules or // from AudioProcessing tests in a single-threaded manner. // Hence there is no need for locks in these. int proc_sample_rate_hz() const override; int proc_split_sample_rate_hz() const override; size_t num_input_channels() const override; size_t num_proc_channels() const override; size_t num_output_channels() const override; size_t num_reverse_channels() const override; int stream_delay_ms() const override; AudioProcessingStats GetStatistics(bool has_remote_tracks) override { return GetStatistics(); } AudioProcessingStats GetStatistics() override { return stats_reporter_.GetStatistics(); } // TODO(peah): Remove MutateConfig once the new API allows that. void MutateConfig(rtc::FunctionView mutator); AudioProcessing::Config GetConfig() const override; protected: // Overridden in a mock. virtual void InitializeLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_, mutex_capture_); private: // TODO(peah): These friend classes should be removed as soon as the new // parameter setting scheme allows. FRIEND_TEST_ALL_PREFIXES(ApmConfiguration, DefaultBehavior); FRIEND_TEST_ALL_PREFIXES(ApmConfiguration, ValidConfigBehavior); FRIEND_TEST_ALL_PREFIXES(ApmConfiguration, InValidConfigBehavior); FRIEND_TEST_ALL_PREFIXES(ApmWithSubmodulesExcludedTest, ToggleTransientSuppressor); FRIEND_TEST_ALL_PREFIXES(ApmWithSubmodulesExcludedTest, ReinitializeTransientSuppressor); FRIEND_TEST_ALL_PREFIXES(ApmWithSubmodulesExcludedTest, BitexactWithDisabledModules); int recommended_stream_analog_level_locked() const RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); void OverrideSubmoduleCreationForTesting( const ApmSubmoduleCreationOverrides& overrides); // Class providing thread-safe message pipe functionality for // |runtime_settings_|. class RuntimeSettingEnqueuer { public: explicit RuntimeSettingEnqueuer( SwapQueue* runtime_settings); ~RuntimeSettingEnqueuer(); void Enqueue(RuntimeSetting setting); private: SwapQueue& runtime_settings_; }; std::unique_ptr data_dumper_; static int instance_count_; const bool use_setup_specific_default_aec3_config_; SwapQueue capture_runtime_settings_; SwapQueue render_runtime_settings_; RuntimeSettingEnqueuer capture_runtime_settings_enqueuer_; RuntimeSettingEnqueuer render_runtime_settings_enqueuer_; // EchoControl factory. std::unique_ptr echo_control_factory_; class SubmoduleStates { public: SubmoduleStates(bool capture_post_processor_enabled, bool render_pre_processor_enabled, bool capture_analyzer_enabled); // Updates the submodule state and returns true if it has changed. bool Update(bool high_pass_filter_enabled, bool mobile_echo_controller_enabled, bool residual_echo_detector_enabled, bool noise_suppressor_enabled, bool adaptive_gain_controller_enabled, bool gain_controller2_enabled, bool pre_amplifier_enabled, bool echo_controller_enabled, bool voice_detector_enabled, bool transient_suppressor_enabled); bool CaptureMultiBandSubModulesActive() const; bool CaptureMultiBandProcessingPresent() const; bool CaptureMultiBandProcessingActive(bool ec_processing_active) const; bool CaptureFullBandProcessingActive() const; bool CaptureAnalyzerActive() const; bool RenderMultiBandSubModulesActive() const; bool RenderFullBandProcessingActive() const; bool RenderMultiBandProcessingActive() const; bool HighPassFilteringRequired() const; private: const bool capture_post_processor_enabled_ = false; const bool render_pre_processor_enabled_ = false; const bool capture_analyzer_enabled_ = false; bool high_pass_filter_enabled_ = false; bool mobile_echo_controller_enabled_ = false; bool residual_echo_detector_enabled_ = false; bool noise_suppressor_enabled_ = false; bool adaptive_gain_controller_enabled_ = false; bool gain_controller2_enabled_ = false; bool pre_amplifier_enabled_ = false; bool echo_controller_enabled_ = false; bool voice_detector_enabled_ = false; bool transient_suppressor_enabled_ = false; bool first_update_ = true; }; // Methods for modifying the formats struct that is used by both // the render and capture threads. The check for whether modifications are // needed is done while holding a single lock only, thereby avoiding that the // capture thread blocks the render thread. // Called by render: Holds the render lock when reading the format struct and // acquires both locks if reinitialization is required. int MaybeInitializeRender(const ProcessingConfig& processing_config) RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_); // Called by capture: Holds the capture lock when reading the format struct // and acquires both locks if reinitialization is needed. int MaybeInitializeCapture(const StreamConfig& input_config, const StreamConfig& output_config); // Method for updating the state keeping track of the active submodules. // Returns a bool indicating whether the state has changed. bool UpdateActiveSubmoduleStates() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); // Methods requiring APM running in a single-threaded manner, requiring both // the render and capture lock to be acquired. int InitializeLocked(const ProcessingConfig& config) RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_, mutex_capture_); void InitializeResidualEchoDetector() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_, mutex_capture_); void InitializeEchoController() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_, mutex_capture_); // Initializations of capture-only submodules, requiring the capture lock // already acquired. void InitializeHighPassFilter(bool forced_reset) RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); void InitializeVoiceDetector() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); void InitializeGainController1() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); void InitializeTransientSuppressor() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); void InitializeGainController2() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); void InitializeNoiseSuppressor() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); void InitializePreAmplifier() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); void InitializePostProcessor() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); void InitializeAnalyzer() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); // Initializations of render-only submodules, requiring the render lock // already acquired. void InitializePreProcessor() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_); // Sample rate used for the fullband processing. int proc_fullband_sample_rate_hz() const RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); // Empties and handles the respective RuntimeSetting queues. void HandleCaptureRuntimeSettings() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); void HandleRenderRuntimeSettings() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_); void EmptyQueuedRenderAudio() RTC_LOCKS_EXCLUDED(mutex_capture_); void EmptyQueuedRenderAudioLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); void AllocateRenderQueue() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_, mutex_capture_); void QueueBandedRenderAudio(AudioBuffer* audio) RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_); void QueueNonbandedRenderAudio(AudioBuffer* audio) RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_); // Capture-side exclusive methods possibly running APM in a multi-threaded // manner that are called with the render lock already acquired. int ProcessCaptureStreamLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); // Render-side exclusive methods possibly running APM in a multi-threaded // manner that are called with the render lock already acquired. // TODO(ekm): Remove once all clients updated to new interface. int AnalyzeReverseStreamLocked(const float* const* src, const StreamConfig& input_config, const StreamConfig& output_config) RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_); int ProcessRenderStreamLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_); // Collects configuration settings from public and private // submodules to be saved as an audioproc::Config message on the // AecDump if it is attached. If not |forced|, only writes the current // config if it is different from the last saved one; if |forced|, // writes the config regardless of the last saved. void WriteAecDumpConfigMessage(bool forced) RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); // Notifies attached AecDump of current configuration and capture data. void RecordUnprocessedCaptureStream(const float* const* capture_stream) RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); void RecordUnprocessedCaptureStream(const int16_t* const data, const StreamConfig& config) RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); // Notifies attached AecDump of current configuration and // processed capture data and issues a capture stream recording // request. void RecordProcessedCaptureStream( const float* const* processed_capture_stream) RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); void RecordProcessedCaptureStream(const int16_t* const data, const StreamConfig& config) RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); // Notifies attached AecDump about current state (delay, drift, etc). void RecordAudioProcessingState() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_); // AecDump instance used for optionally logging APM config, input // and output to file in the AEC-dump format defined in debug.proto. std::unique_ptr aec_dump_; // Hold the last config written with AecDump for avoiding writing // the same config twice. InternalAPMConfig apm_config_for_aec_dump_ RTC_GUARDED_BY(mutex_capture_); // Critical sections. mutable Mutex mutex_render_ RTC_ACQUIRED_BEFORE(mutex_capture_); mutable Mutex mutex_capture_; // Struct containing the Config specifying the behavior of APM. AudioProcessing::Config config_; // Overrides for testing the exclusion of some submodules from the build. ApmSubmoduleCreationOverrides submodule_creation_overrides_ RTC_GUARDED_BY(mutex_capture_); // Class containing information about what submodules are active. SubmoduleStates submodule_states_; // Struct containing the pointers to the submodules. struct Submodules { Submodules(std::unique_ptr capture_post_processor, std::unique_ptr render_pre_processor, rtc::scoped_refptr echo_detector, std::unique_ptr capture_analyzer) : echo_detector(std::move(echo_detector)), capture_post_processor(std::move(capture_post_processor)), render_pre_processor(std::move(render_pre_processor)), capture_analyzer(std::move(capture_analyzer)) {} // Accessed internally from capture or during initialization. std::unique_ptr agc_manager; std::unique_ptr gain_control; std::unique_ptr gain_controller2; std::unique_ptr high_pass_filter; rtc::scoped_refptr echo_detector; std::unique_ptr echo_controller; std::unique_ptr echo_control_mobile; std::unique_ptr noise_suppressor; std::unique_ptr transient_suppressor; std::unique_ptr capture_post_processor; std::unique_ptr render_pre_processor; std::unique_ptr pre_amplifier; std::unique_ptr capture_analyzer; std::unique_ptr output_level_estimator; std::unique_ptr voice_detector; } submodules_; // State that is written to while holding both the render and capture locks // but can be read without any lock being held. // As this is only accessed internally of APM, and all internal methods in APM // either are holding the render or capture locks, this construct is safe as // it is not possible to read the variables while writing them. struct ApmFormatState { ApmFormatState() : // Format of processing streams at input/output call sites. api_format({{{kSampleRate16kHz, 1, false}, {kSampleRate16kHz, 1, false}, {kSampleRate16kHz, 1, false}, {kSampleRate16kHz, 1, false}}}), render_processing_format(kSampleRate16kHz, 1) {} ProcessingConfig api_format; StreamConfig render_processing_format; } formats_; // APM constants. const struct ApmConstants { ApmConstants(bool multi_channel_render_support, bool multi_channel_capture_support, bool enforce_split_band_hpf) : multi_channel_render_support(multi_channel_render_support), multi_channel_capture_support(multi_channel_capture_support), enforce_split_band_hpf(enforce_split_band_hpf) {} bool multi_channel_render_support; bool multi_channel_capture_support; bool enforce_split_band_hpf; } constants_; struct ApmCaptureState { ApmCaptureState(); ~ApmCaptureState(); bool was_stream_delay_set; bool output_will_be_muted; bool key_pressed; std::unique_ptr capture_audio; std::unique_ptr capture_fullband_audio; std::unique_ptr linear_aec_output; // Only the rate and samples fields of capture_processing_format_ are used // because the capture processing number of channels is mutable and is // tracked by the capture_audio_. StreamConfig capture_processing_format; int split_rate; bool echo_path_gain_change; int prev_analog_mic_level; float prev_pre_amp_gain; int playout_volume; int prev_playout_volume; AudioProcessingStats stats; struct KeyboardInfo { void Extract(const float* const* data, const StreamConfig& stream_config); size_t num_keyboard_frames = 0; const float* keyboard_data = nullptr; } keyboard_info; int cached_stream_analog_level_ = 0; } capture_ RTC_GUARDED_BY(mutex_capture_); struct ApmCaptureNonLockedState { ApmCaptureNonLockedState() : capture_processing_format(kSampleRate16kHz), split_rate(kSampleRate16kHz), stream_delay_ms(0) {} // Only the rate and samples fields of capture_processing_format_ are used // because the forward processing number of channels is mutable and is // tracked by the capture_audio_. StreamConfig capture_processing_format; int split_rate; int stream_delay_ms; bool echo_controller_enabled = false; } capture_nonlocked_; struct ApmRenderState { ApmRenderState(); ~ApmRenderState(); std::unique_ptr render_converter; std::unique_ptr render_audio; } render_ RTC_GUARDED_BY(mutex_render_); // Class for statistics reporting. The class is thread-safe and no lock is // needed when accessing it. class ApmStatsReporter { public: ApmStatsReporter(); ~ApmStatsReporter(); // Returns the most recently reported statistics. AudioProcessingStats GetStatistics(); // Update the cached statistics. void UpdateStatistics(const AudioProcessingStats& new_stats); private: Mutex mutex_stats_; AudioProcessingStats cached_stats_ RTC_GUARDED_BY(mutex_stats_); SwapQueue stats_message_queue_; } stats_reporter_; std::vector aecm_render_queue_buffer_ RTC_GUARDED_BY(mutex_render_); std::vector aecm_capture_queue_buffer_ RTC_GUARDED_BY(mutex_capture_); size_t agc_render_queue_element_max_size_ RTC_GUARDED_BY(mutex_render_) RTC_GUARDED_BY(mutex_capture_) = 0; std::vector agc_render_queue_buffer_ RTC_GUARDED_BY(mutex_render_); std::vector agc_capture_queue_buffer_ RTC_GUARDED_BY(mutex_capture_); size_t red_render_queue_element_max_size_ RTC_GUARDED_BY(mutex_render_) RTC_GUARDED_BY(mutex_capture_) = 0; std::vector red_render_queue_buffer_ RTC_GUARDED_BY(mutex_render_); std::vector red_capture_queue_buffer_ RTC_GUARDED_BY(mutex_capture_); RmsLevel capture_input_rms_ RTC_GUARDED_BY(mutex_capture_); RmsLevel capture_output_rms_ RTC_GUARDED_BY(mutex_capture_); int capture_rms_interval_counter_ RTC_GUARDED_BY(mutex_capture_) = 0; // Lock protection not needed. std::unique_ptr< SwapQueue, RenderQueueItemVerifier>> aecm_render_signal_queue_; std::unique_ptr< SwapQueue, RenderQueueItemVerifier>> agc_render_signal_queue_; std::unique_ptr, RenderQueueItemVerifier>> red_render_signal_queue_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AUDIO_PROCESSING_IMPL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/common.h0000664000175000017500000000176614475643423024634 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_COMMON_H_ #define MODULES_AUDIO_PROCESSING_COMMON_H_ #include "modules/audio_processing/include/audio_processing.h" #include "rtc_base/checks.h" namespace webrtc { static inline size_t ChannelsFromLayout(AudioProcessing::ChannelLayout layout) { switch (layout) { case AudioProcessing::kMono: case AudioProcessing::kMonoAndKeyboard: return 1; case AudioProcessing::kStereo: case AudioProcessing::kStereoAndKeyboard: return 2; } RTC_NOTREACHED(); return 0; } } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_COMMON_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/debug.proto0000664000175000017500000000674314475643423025346 0ustar00arunarunsyntax = "proto2"; option optimize_for = LITE_RUNTIME; package webrtc.audioproc; // Contains the format of input/output/reverse audio. An Init message is added // when any of the fields are changed. message Init { optional int32 sample_rate = 1; optional int32 device_sample_rate = 2 [deprecated=true]; optional int32 num_input_channels = 3; optional int32 num_output_channels = 4; optional int32 num_reverse_channels = 5; optional int32 reverse_sample_rate = 6; optional int32 output_sample_rate = 7; optional int32 reverse_output_sample_rate = 8; optional int32 num_reverse_output_channels = 9; optional int64 timestamp_ms = 10; } // May contain interleaved or deinterleaved data, but don't store both formats. message ReverseStream { // int16 interleaved data. optional bytes data = 1; // float deinterleaved data, where each repeated element points to a single // channel buffer of data. repeated bytes channel = 2; } // May contain interleaved or deinterleaved data, but don't store both formats. message Stream { // int16 interleaved data. optional bytes input_data = 1; optional bytes output_data = 2; optional int32 delay = 3; optional sint32 drift = 4; optional int32 level = 5; optional bool keypress = 6; // float deinterleaved data, where each repeated element points to a single // channel buffer of data. repeated bytes input_channel = 7; repeated bytes output_channel = 8; } // Contains the configurations of various APM component. A Config message is // added when any of the fields are changed. message Config { // Acoustic echo canceler. optional bool aec_enabled = 1; optional bool aec_delay_agnostic_enabled = 2; optional bool aec_drift_compensation_enabled = 3; optional bool aec_extended_filter_enabled = 4; optional int32 aec_suppression_level = 5; // Mobile AEC. optional bool aecm_enabled = 6; optional bool aecm_comfort_noise_enabled = 7 [deprecated = true]; optional int32 aecm_routing_mode = 8 [deprecated = true]; // Automatic gain controller. optional bool agc_enabled = 9; optional int32 agc_mode = 10; optional bool agc_limiter_enabled = 11; optional bool noise_robust_agc_enabled = 12; // High pass filter. optional bool hpf_enabled = 13; // Noise suppression. optional bool ns_enabled = 14; optional int32 ns_level = 15; // Transient suppression. optional bool transient_suppression_enabled = 16; // Semicolon-separated string containing experimental feature // descriptions. optional string experiments_description = 17; reserved 18; // Intelligibility enhancer enabled (deprecated). // Pre amplifier. optional bool pre_amplifier_enabled = 19; optional float pre_amplifier_fixed_gain_factor = 20; // Next field number 21. } message PlayoutAudioDeviceInfo { optional int32 id = 1; optional int32 max_volume = 2; } message RuntimeSetting { optional float capture_pre_gain = 1; optional float custom_render_processing_setting = 2; optional float capture_fixed_post_gain = 3; optional int32 playout_volume_change = 4; optional PlayoutAudioDeviceInfo playout_audio_device_change = 5; optional bool capture_output_used = 6; } message Event { enum Type { INIT = 0; REVERSE_STREAM = 1; STREAM = 2; CONFIG = 3; UNKNOWN_EVENT = 4; RUNTIME_SETTING = 5; } required Type type = 1; optional Init init = 2; optional ReverseStream reverse_stream = 3; optional Stream stream = 4; optional Config config = 5; optional RuntimeSetting runtime_setting = 6; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/echo_control_mobile_impl.cc0000664000175000017500000002165014475643423030522 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/echo_control_mobile_impl.h" #include #include #include "modules/audio_processing/aecm/echo_control_mobile.h" #include "modules/audio_processing/audio_buffer.h" #include "modules/audio_processing/include/audio_processing.h" #include "rtc_base/checks.h" #include "rtc_base/constructor_magic.h" namespace webrtc { namespace { int16_t MapSetting(EchoControlMobileImpl::RoutingMode mode) { switch (mode) { case EchoControlMobileImpl::kQuietEarpieceOrHeadset: return 0; case EchoControlMobileImpl::kEarpiece: return 1; case EchoControlMobileImpl::kLoudEarpiece: return 2; case EchoControlMobileImpl::kSpeakerphone: return 3; case EchoControlMobileImpl::kLoudSpeakerphone: return 4; } RTC_NOTREACHED(); return -1; } AudioProcessing::Error MapError(int err) { switch (err) { case AECM_UNSUPPORTED_FUNCTION_ERROR: return AudioProcessing::kUnsupportedFunctionError; case AECM_NULL_POINTER_ERROR: return AudioProcessing::kNullPointerError; case AECM_BAD_PARAMETER_ERROR: return AudioProcessing::kBadParameterError; case AECM_BAD_PARAMETER_WARNING: return AudioProcessing::kBadStreamParameterWarning; default: // AECM_UNSPECIFIED_ERROR // AECM_UNINITIALIZED_ERROR return AudioProcessing::kUnspecifiedError; } } } // namespace struct EchoControlMobileImpl::StreamProperties { StreamProperties() = delete; StreamProperties(int sample_rate_hz, size_t num_reverse_channels, size_t num_output_channels) : sample_rate_hz(sample_rate_hz), num_reverse_channels(num_reverse_channels), num_output_channels(num_output_channels) {} int sample_rate_hz; size_t num_reverse_channels; size_t num_output_channels; }; class EchoControlMobileImpl::Canceller { public: Canceller() { state_ = WebRtcAecm_Create(); RTC_CHECK(state_); } ~Canceller() { RTC_DCHECK(state_); WebRtcAecm_Free(state_); } void* state() { RTC_DCHECK(state_); return state_; } void Initialize(int sample_rate_hz) { RTC_DCHECK(state_); int error = WebRtcAecm_Init(state_, sample_rate_hz); RTC_DCHECK_EQ(AudioProcessing::kNoError, error); } private: void* state_; RTC_DISALLOW_COPY_AND_ASSIGN(Canceller); }; EchoControlMobileImpl::EchoControlMobileImpl() : routing_mode_(kSpeakerphone), comfort_noise_enabled_(false) {} EchoControlMobileImpl::~EchoControlMobileImpl() {} void EchoControlMobileImpl::ProcessRenderAudio( rtc::ArrayView packed_render_audio) { RTC_DCHECK(stream_properties_); size_t buffer_index = 0; size_t num_frames_per_band = packed_render_audio.size() / (stream_properties_->num_output_channels * stream_properties_->num_reverse_channels); for (auto& canceller : cancellers_) { WebRtcAecm_BufferFarend(canceller->state(), &packed_render_audio[buffer_index], num_frames_per_band); buffer_index += num_frames_per_band; } } void EchoControlMobileImpl::PackRenderAudioBuffer( const AudioBuffer* audio, size_t num_output_channels, size_t num_channels, std::vector* packed_buffer) { RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio->num_frames_per_band()); RTC_DCHECK_EQ(num_channels, audio->num_channels()); // The ordering convention must be followed to pass to the correct AECM. packed_buffer->clear(); int render_channel = 0; for (size_t i = 0; i < num_output_channels; i++) { for (size_t j = 0; j < audio->num_channels(); j++) { std::array data_to_buffer; FloatS16ToS16(audio->split_bands_const(render_channel)[kBand0To8kHz], audio->num_frames_per_band(), data_to_buffer.data()); // Buffer the samples in the render queue. packed_buffer->insert( packed_buffer->end(), data_to_buffer.data(), data_to_buffer.data() + audio->num_frames_per_band()); render_channel = (render_channel + 1) % audio->num_channels(); } } } size_t EchoControlMobileImpl::NumCancellersRequired( size_t num_output_channels, size_t num_reverse_channels) { return num_output_channels * num_reverse_channels; } int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio, int stream_delay_ms) { RTC_DCHECK(stream_properties_); RTC_DCHECK_GE(160, audio->num_frames_per_band()); RTC_DCHECK_EQ(audio->num_channels(), stream_properties_->num_output_channels); RTC_DCHECK_GE(cancellers_.size(), stream_properties_->num_reverse_channels * audio->num_channels()); int err = AudioProcessing::kNoError; // The ordering convention must be followed to pass to the correct AECM. size_t handle_index = 0; for (size_t capture = 0; capture < audio->num_channels(); ++capture) { // TODO(ajm): improve how this works, possibly inside AECM. // This is kind of hacked up. RTC_DCHECK_LT(capture, low_pass_reference_.size()); const int16_t* noisy = reference_copied_ ? low_pass_reference_[capture].data() : nullptr; RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio->num_frames_per_band()); std::array split_bands_data; int16_t* split_bands = split_bands_data.data(); const int16_t* clean = split_bands_data.data(); if (audio->split_bands(capture)[kBand0To8kHz]) { FloatS16ToS16(audio->split_bands(capture)[kBand0To8kHz], audio->num_frames_per_band(), split_bands_data.data()); } else { clean = nullptr; split_bands = nullptr; } if (noisy == NULL) { noisy = clean; clean = NULL; } for (size_t render = 0; render < stream_properties_->num_reverse_channels; ++render) { err = WebRtcAecm_Process(cancellers_[handle_index]->state(), noisy, clean, split_bands, audio->num_frames_per_band(), stream_delay_ms); if (split_bands) { S16ToFloatS16(split_bands, audio->num_frames_per_band(), audio->split_bands(capture)[kBand0To8kHz]); } if (err != AudioProcessing::kNoError) { return MapError(err); } ++handle_index; } for (size_t band = 1u; band < audio->num_bands(); ++band) { memset(audio->split_bands_f(capture)[band], 0, audio->num_frames_per_band() * sizeof(audio->split_bands_f(capture)[band][0])); } } return AudioProcessing::kNoError; } int EchoControlMobileImpl::set_routing_mode(RoutingMode mode) { if (MapSetting(mode) == -1) { return AudioProcessing::kBadParameterError; } routing_mode_ = mode; return Configure(); } EchoControlMobileImpl::RoutingMode EchoControlMobileImpl::routing_mode() const { return routing_mode_; } int EchoControlMobileImpl::enable_comfort_noise(bool enable) { comfort_noise_enabled_ = enable; return Configure(); } bool EchoControlMobileImpl::is_comfort_noise_enabled() const { return comfort_noise_enabled_; } void EchoControlMobileImpl::Initialize(int sample_rate_hz, size_t num_reverse_channels, size_t num_output_channels) { low_pass_reference_.resize(num_output_channels); for (auto& reference : low_pass_reference_) { reference.fill(0); } stream_properties_.reset(new StreamProperties( sample_rate_hz, num_reverse_channels, num_output_channels)); // AECM only supports 16 kHz or lower sample rates. RTC_DCHECK_LE(stream_properties_->sample_rate_hz, AudioProcessing::kSampleRate16kHz); cancellers_.resize( NumCancellersRequired(stream_properties_->num_output_channels, stream_properties_->num_reverse_channels)); for (auto& canceller : cancellers_) { if (!canceller) { canceller.reset(new Canceller()); } canceller->Initialize(sample_rate_hz); } Configure(); } int EchoControlMobileImpl::Configure() { AecmConfig config; config.cngMode = comfort_noise_enabled_; config.echoMode = MapSetting(routing_mode_); int error = AudioProcessing::kNoError; for (auto& canceller : cancellers_) { int handle_error = WebRtcAecm_set_config(canceller->state(), config); if (handle_error != AudioProcessing::kNoError) { error = handle_error; } } return error; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/echo_control_mobile_impl.h0000664000175000017500000000532714475643423030367 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_ECHO_CONTROL_MOBILE_IMPL_H_ #define MODULES_AUDIO_PROCESSING_ECHO_CONTROL_MOBILE_IMPL_H_ #include #include #include #include #include "api/array_view.h" namespace webrtc { class AudioBuffer; // The acoustic echo control for mobile (AECM) component is a low complexity // robust option intended for use on mobile devices. class EchoControlMobileImpl { public: EchoControlMobileImpl(); ~EchoControlMobileImpl(); // Recommended settings for particular audio routes. In general, the louder // the echo is expected to be, the higher this value should be set. The // preferred setting may vary from device to device. enum RoutingMode { kQuietEarpieceOrHeadset, kEarpiece, kLoudEarpiece, kSpeakerphone, kLoudSpeakerphone }; // Sets echo control appropriate for the audio routing |mode| on the device. // It can and should be updated during a call if the audio routing changes. int set_routing_mode(RoutingMode mode); RoutingMode routing_mode() const; // Comfort noise replaces suppressed background noise to maintain a // consistent signal level. int enable_comfort_noise(bool enable); bool is_comfort_noise_enabled() const; void ProcessRenderAudio(rtc::ArrayView packed_render_audio); int ProcessCaptureAudio(AudioBuffer* audio, int stream_delay_ms); void Initialize(int sample_rate_hz, size_t num_reverse_channels, size_t num_output_channels); static void PackRenderAudioBuffer(const AudioBuffer* audio, size_t num_output_channels, size_t num_channels, std::vector* packed_buffer); static size_t NumCancellersRequired(size_t num_output_channels, size_t num_reverse_channels); private: class Canceller; struct StreamProperties; int Configure(); RoutingMode routing_mode_; bool comfort_noise_enabled_; std::vector> cancellers_; std::unique_ptr stream_properties_; std::vector> low_pass_reference_; bool reference_copied_ = false; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_ECHO_CONTROL_MOBILE_IMPL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/echo_detector/0000775000175000017500000000000014475643423025770 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/echo_detector/circular_buffer.cc0000664000175000017500000000274414475643423031443 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/echo_detector/circular_buffer.h" #include #include "rtc_base/checks.h" namespace webrtc { CircularBuffer::CircularBuffer(size_t size) : buffer_(size) {} CircularBuffer::~CircularBuffer() = default; void CircularBuffer::Push(float value) { buffer_[next_insertion_index_] = value; ++next_insertion_index_; next_insertion_index_ %= buffer_.size(); RTC_DCHECK_LT(next_insertion_index_, buffer_.size()); nr_elements_in_buffer_ = std::min(nr_elements_in_buffer_ + 1, buffer_.size()); RTC_DCHECK_LE(nr_elements_in_buffer_, buffer_.size()); } absl::optional CircularBuffer::Pop() { if (nr_elements_in_buffer_ == 0) { return absl::nullopt; } const size_t index = (buffer_.size() + next_insertion_index_ - nr_elements_in_buffer_) % buffer_.size(); RTC_DCHECK_LT(index, buffer_.size()); --nr_elements_in_buffer_; return buffer_[index]; } void CircularBuffer::Clear() { std::fill(buffer_.begin(), buffer_.end(), 0.f); next_insertion_index_ = 0; nr_elements_in_buffer_ = 0; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/echo_detector/circular_buffer.h0000664000175000017500000000245414475643423031303 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_CIRCULAR_BUFFER_H_ #define MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_CIRCULAR_BUFFER_H_ #include #include #include "absl/types/optional.h" namespace webrtc { // Ring buffer containing floating point values. struct CircularBuffer { public: explicit CircularBuffer(size_t size); ~CircularBuffer(); void Push(float value); absl::optional Pop(); size_t Size() const { return nr_elements_in_buffer_; } // This function fills the buffer with zeros, but does not change its size. void Clear(); private: std::vector buffer_; size_t next_insertion_index_ = 0; // This is the number of elements that have been pushed into the circular // buffer, not the allocated buffer size. size_t nr_elements_in_buffer_ = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_CIRCULAR_BUFFER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/echo_detector/mean_variance_estimator.cc0000664000175000017500000000227214475643423033161 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/echo_detector/mean_variance_estimator.h" #include #include "rtc_base/checks.h" namespace webrtc { namespace { // Parameter controlling the adaptation speed. constexpr float kAlpha = 0.001f; } // namespace void MeanVarianceEstimator::Update(float value) { mean_ = (1.f - kAlpha) * mean_ + kAlpha * value; variance_ = (1.f - kAlpha) * variance_ + kAlpha * (value - mean_) * (value - mean_); RTC_DCHECK(isfinite(mean_)); RTC_DCHECK(isfinite(variance_)); } float MeanVarianceEstimator::std_deviation() const { RTC_DCHECK_GE(variance_, 0.f); return sqrtf(variance_); } float MeanVarianceEstimator::mean() const { return mean_; } void MeanVarianceEstimator::Clear() { mean_ = 0.f; variance_ = 0.f; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/echo_detector/mean_variance_estimator.h0000664000175000017500000000204414475643423033020 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_MEAN_VARIANCE_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_MEAN_VARIANCE_ESTIMATOR_H_ namespace webrtc { // This class iteratively estimates the mean and variance of a signal. class MeanVarianceEstimator { public: void Update(float value); float std_deviation() const; float mean() const; void Clear(); private: // Estimate of the expected value of the input values. float mean_ = 0.f; // Estimate of the variance of the input values. float variance_ = 0.f; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_MEAN_VARIANCE_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/echo_detector/moving_max.cc0000664000175000017500000000242414475643423030445 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/echo_detector/moving_max.h" #include "rtc_base/checks.h" namespace webrtc { namespace { // Parameter for controlling how fast the estimated maximum decays after the // previous maximum is no longer valid. With a value of 0.99, the maximum will // decay to 1% of its former value after 460 updates. constexpr float kDecayFactor = 0.99f; } // namespace MovingMax::MovingMax(size_t window_size) : window_size_(window_size) { RTC_DCHECK_GT(window_size, 0); } MovingMax::~MovingMax() {} void MovingMax::Update(float value) { if (counter_ >= window_size_ - 1) { max_value_ *= kDecayFactor; } else { ++counter_; } if (value > max_value_) { max_value_ = value; counter_ = 0; } } float MovingMax::max() const { return max_value_; } void MovingMax::Clear() { max_value_ = 0.f; counter_ = 0; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/echo_detector/moving_max.h0000664000175000017500000000166714475643423030317 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_MOVING_MAX_H_ #define MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_MOVING_MAX_H_ #include namespace webrtc { class MovingMax { public: explicit MovingMax(size_t window_size); ~MovingMax(); void Update(float value); float max() const; // Reset all of the state in this class. void Clear(); private: float max_value_ = 0.f; size_t counter_ = 0; size_t window_size_ = 1; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_MOVING_MAX_H_ ././@PaxHeader0000000000000000000000000000021400000000000010212 xustar00118 path=webrtc-audio-processing-1.3/webrtc/modules/audio_processing/echo_detector/normalized_covariance_estimator.cc 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/echo_detector/normalized_covariance_esti0000664000175000017500000000260214475643423033275 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/echo_detector/normalized_covariance_estimator.h" #include #include "rtc_base/checks.h" namespace webrtc { namespace { // Parameter controlling the adaptation speed. constexpr float kAlpha = 0.001f; } // namespace void NormalizedCovarianceEstimator::Update(float x, float x_mean, float x_sigma, float y, float y_mean, float y_sigma) { covariance_ = (1.f - kAlpha) * covariance_ + kAlpha * (x - x_mean) * (y - y_mean); normalized_cross_correlation_ = covariance_ / (x_sigma * y_sigma + .0001f); RTC_DCHECK(isfinite(covariance_)); RTC_DCHECK(isfinite(normalized_cross_correlation_)); } void NormalizedCovarianceEstimator::Clear() { covariance_ = 0.f; normalized_cross_correlation_ = 0.f; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000021300000000000010211 xustar00117 path=webrtc-audio-processing-1.3/webrtc/modules/audio_processing/echo_detector/normalized_covariance_estimator.h 22 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/echo_detector/normalized_covariance_esti0000664000175000017500000000266214475643423033303 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_NORMALIZED_COVARIANCE_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_NORMALIZED_COVARIANCE_ESTIMATOR_H_ namespace webrtc { // This class iteratively estimates the normalized covariance between two // signals. class NormalizedCovarianceEstimator { public: void Update(float x, float x_mean, float x_var, float y, float y_mean, float y_var); // This function returns an estimate of the Pearson product-moment correlation // coefficient of the two signals. float normalized_cross_correlation() const { return normalized_cross_correlation_; } float covariance() const { return covariance_; } // This function resets the estimated values to zero. void Clear(); private: float normalized_cross_correlation_ = 0.f; // Estimate of the covariance value. float covariance_ = 0.f; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_NORMALIZED_COVARIANCE_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/gain_control_impl.cc0000664000175000017500000003132514475643423027173 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/gain_control_impl.h" #include #include "absl/types/optional.h" #include "modules/audio_processing/agc/legacy/gain_control.h" #include "modules/audio_processing/audio_buffer.h" #include "modules/audio_processing/include/audio_processing.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "system_wrappers/include/field_trial.h" namespace webrtc { typedef void Handle; namespace { int16_t MapSetting(GainControl::Mode mode) { switch (mode) { case GainControl::kAdaptiveAnalog: return kAgcModeAdaptiveAnalog; case GainControl::kAdaptiveDigital: return kAgcModeAdaptiveDigital; case GainControl::kFixedDigital: return kAgcModeFixedDigital; } RTC_NOTREACHED(); return -1; } // Checks whether the legacy digital gain application should be used. bool UseLegacyDigitalGainApplier() { return field_trial::IsEnabled("WebRTC-UseLegacyDigitalGainApplier"); } // Floating point variant of WebRtcAgc_Process. void ApplyDigitalGain(const int32_t gains[11], size_t num_bands, float* const* out) { constexpr float kScaling = 1.f / 65536.f; constexpr int kNumSubSections = 16; constexpr float kOneByNumSubSections = 1.f / kNumSubSections; float gains_scaled[11]; for (int k = 0; k < 11; ++k) { gains_scaled[k] = gains[k] * kScaling; } for (size_t b = 0; b < num_bands; ++b) { float* out_band = out[b]; for (int k = 0, sample = 0; k < 10; ++k) { const float delta = (gains_scaled[k + 1] - gains_scaled[k]) * kOneByNumSubSections; float gain = gains_scaled[k]; for (int n = 0; n < kNumSubSections; ++n, ++sample) { RTC_DCHECK_EQ(k * kNumSubSections + n, sample); out_band[sample] *= gain; out_band[sample] = std::min(32767.f, std::max(-32768.f, out_band[sample])); gain += delta; } } } } } // namespace struct GainControlImpl::MonoAgcState { MonoAgcState() { state = WebRtcAgc_Create(); RTC_CHECK(state); } ~MonoAgcState() { RTC_DCHECK(state); WebRtcAgc_Free(state); } MonoAgcState(const MonoAgcState&) = delete; MonoAgcState& operator=(const MonoAgcState&) = delete; int32_t gains[11]; Handle* state; }; int GainControlImpl::instance_counter_ = 0; GainControlImpl::GainControlImpl() : data_dumper_(new ApmDataDumper(instance_counter_)), use_legacy_gain_applier_(UseLegacyDigitalGainApplier()), mode_(kAdaptiveAnalog), minimum_capture_level_(0), maximum_capture_level_(255), limiter_enabled_(true), target_level_dbfs_(3), compression_gain_db_(9), analog_capture_level_(0), was_analog_level_set_(false), stream_is_saturated_(false) {} GainControlImpl::~GainControlImpl() = default; void GainControlImpl::ProcessRenderAudio( rtc::ArrayView packed_render_audio) { for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) { WebRtcAgc_AddFarend(mono_agcs_[ch]->state, packed_render_audio.data(), packed_render_audio.size()); } } void GainControlImpl::PackRenderAudioBuffer( const AudioBuffer& audio, std::vector* packed_buffer) { RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio.num_frames_per_band()); std::array mixed_16_kHz_render_data; rtc::ArrayView mixed_16_kHz_render( mixed_16_kHz_render_data.data(), audio.num_frames_per_band()); if (audio.num_channels() == 1) { FloatS16ToS16(audio.split_bands_const(0)[kBand0To8kHz], audio.num_frames_per_band(), mixed_16_kHz_render_data.data()); } else { const int num_channels = static_cast(audio.num_channels()); for (size_t i = 0; i < audio.num_frames_per_band(); ++i) { int32_t sum = 0; for (int ch = 0; ch < num_channels; ++ch) { sum += FloatS16ToS16(audio.split_channels_const(kBand0To8kHz)[ch][i]); } mixed_16_kHz_render_data[i] = sum / num_channels; } } packed_buffer->clear(); packed_buffer->insert( packed_buffer->end(), mixed_16_kHz_render.data(), (mixed_16_kHz_render.data() + audio.num_frames_per_band())); } int GainControlImpl::AnalyzeCaptureAudio(const AudioBuffer& audio) { RTC_DCHECK(num_proc_channels_); RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio.num_frames_per_band()); RTC_DCHECK_EQ(audio.num_channels(), *num_proc_channels_); RTC_DCHECK_LE(*num_proc_channels_, mono_agcs_.size()); int16_t split_band_data[AudioBuffer::kMaxNumBands] [AudioBuffer::kMaxSplitFrameLength]; int16_t* split_bands[AudioBuffer::kMaxNumBands] = { split_band_data[0], split_band_data[1], split_band_data[2]}; if (mode_ == kAdaptiveAnalog) { for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) { capture_levels_[ch] = analog_capture_level_; audio.ExportSplitChannelData(ch, split_bands); int err = WebRtcAgc_AddMic(mono_agcs_[ch]->state, split_bands, audio.num_bands(), audio.num_frames_per_band()); if (err != AudioProcessing::kNoError) { return AudioProcessing::kUnspecifiedError; } } } else if (mode_ == kAdaptiveDigital) { for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) { int32_t capture_level_out = 0; audio.ExportSplitChannelData(ch, split_bands); int err = WebRtcAgc_VirtualMic(mono_agcs_[ch]->state, split_bands, audio.num_bands(), audio.num_frames_per_band(), analog_capture_level_, &capture_level_out); capture_levels_[ch] = capture_level_out; if (err != AudioProcessing::kNoError) { return AudioProcessing::kUnspecifiedError; } } } return AudioProcessing::kNoError; } int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio, bool stream_has_echo) { if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) { return AudioProcessing::kStreamParameterNotSetError; } RTC_DCHECK(num_proc_channels_); RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio->num_frames_per_band()); RTC_DCHECK_EQ(audio->num_channels(), *num_proc_channels_); stream_is_saturated_ = false; bool error_reported = false; for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) { int16_t split_band_data[AudioBuffer::kMaxNumBands] [AudioBuffer::kMaxSplitFrameLength]; int16_t* split_bands[AudioBuffer::kMaxNumBands] = { split_band_data[0], split_band_data[1], split_band_data[2]}; audio->ExportSplitChannelData(ch, split_bands); // The call to stream_has_echo() is ok from a deadlock perspective // as the capture lock is allready held. int32_t new_capture_level = 0; uint8_t saturation_warning = 0; int err_analyze = WebRtcAgc_Analyze( mono_agcs_[ch]->state, split_bands, audio->num_bands(), audio->num_frames_per_band(), capture_levels_[ch], &new_capture_level, stream_has_echo, &saturation_warning, mono_agcs_[ch]->gains); capture_levels_[ch] = new_capture_level; error_reported = error_reported || err_analyze != AudioProcessing::kNoError; stream_is_saturated_ = stream_is_saturated_ || saturation_warning == 1; } // Choose the minimun gain for application size_t index_to_apply = 0; for (size_t ch = 1; ch < mono_agcs_.size(); ++ch) { if (mono_agcs_[index_to_apply]->gains[10] < mono_agcs_[ch]->gains[10]) { index_to_apply = ch; } } if (use_legacy_gain_applier_) { for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) { int16_t split_band_data[AudioBuffer::kMaxNumBands] [AudioBuffer::kMaxSplitFrameLength]; int16_t* split_bands[AudioBuffer::kMaxNumBands] = { split_band_data[0], split_band_data[1], split_band_data[2]}; audio->ExportSplitChannelData(ch, split_bands); int err_process = WebRtcAgc_Process( mono_agcs_[ch]->state, mono_agcs_[index_to_apply]->gains, split_bands, audio->num_bands(), split_bands); RTC_DCHECK_EQ(err_process, 0); audio->ImportSplitChannelData(ch, split_bands); } } else { for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) { ApplyDigitalGain(mono_agcs_[index_to_apply]->gains, audio->num_bands(), audio->split_bands(ch)); } } RTC_DCHECK_LT(0ul, *num_proc_channels_); if (mode_ == kAdaptiveAnalog) { // Take the analog level to be the minimum accross all channels. analog_capture_level_ = capture_levels_[0]; for (size_t ch = 1; ch < mono_agcs_.size(); ++ch) { analog_capture_level_ = std::min(analog_capture_level_, capture_levels_[ch]); } } if (error_reported) { return AudioProcessing::kUnspecifiedError; } was_analog_level_set_ = false; return AudioProcessing::kNoError; } // TODO(ajm): ensure this is called under kAdaptiveAnalog. int GainControlImpl::set_stream_analog_level(int level) { data_dumper_->DumpRaw("gain_control_set_stream_analog_level", 1, &level); was_analog_level_set_ = true; if (level < minimum_capture_level_ || level > maximum_capture_level_) { return AudioProcessing::kBadParameterError; } analog_capture_level_ = level; return AudioProcessing::kNoError; } int GainControlImpl::stream_analog_level() const { data_dumper_->DumpRaw("gain_control_stream_analog_level", 1, &analog_capture_level_); return analog_capture_level_; } int GainControlImpl::set_mode(Mode mode) { if (MapSetting(mode) == -1) { return AudioProcessing::kBadParameterError; } mode_ = mode; RTC_DCHECK(num_proc_channels_); RTC_DCHECK(sample_rate_hz_); Initialize(*num_proc_channels_, *sample_rate_hz_); return AudioProcessing::kNoError; } int GainControlImpl::set_analog_level_limits(int minimum, int maximum) { if (minimum < 0 || maximum > 65535 || maximum < minimum) { return AudioProcessing::kBadParameterError; } minimum_capture_level_ = minimum; maximum_capture_level_ = maximum; RTC_DCHECK(num_proc_channels_); RTC_DCHECK(sample_rate_hz_); Initialize(*num_proc_channels_, *sample_rate_hz_); return AudioProcessing::kNoError; } int GainControlImpl::set_target_level_dbfs(int level) { if (level > 31 || level < 0) { return AudioProcessing::kBadParameterError; } target_level_dbfs_ = level; return Configure(); } int GainControlImpl::set_compression_gain_db(int gain) { if (gain < 0 || gain > 90) { RTC_LOG(LS_ERROR) << "set_compression_gain_db(" << gain << ") failed."; return AudioProcessing::kBadParameterError; } compression_gain_db_ = gain; return Configure(); } int GainControlImpl::enable_limiter(bool enable) { limiter_enabled_ = enable; return Configure(); } void GainControlImpl::Initialize(size_t num_proc_channels, int sample_rate_hz) { data_dumper_->InitiateNewSetOfRecordings(); RTC_DCHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000 || sample_rate_hz == 48000); num_proc_channels_ = num_proc_channels; sample_rate_hz_ = sample_rate_hz; mono_agcs_.resize(*num_proc_channels_); capture_levels_.resize(*num_proc_channels_); for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) { if (!mono_agcs_[ch]) { mono_agcs_[ch].reset(new MonoAgcState()); } int error = WebRtcAgc_Init(mono_agcs_[ch]->state, minimum_capture_level_, maximum_capture_level_, MapSetting(mode_), *sample_rate_hz_); RTC_DCHECK_EQ(error, 0); capture_levels_[ch] = analog_capture_level_; } Configure(); } int GainControlImpl::Configure() { WebRtcAgcConfig config; // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we // change the interface. // RTC_DCHECK_LE(target_level_dbfs_, 0); // config.targetLevelDbfs = static_cast(-target_level_dbfs_); config.targetLevelDbfs = static_cast(target_level_dbfs_); config.compressionGaindB = static_cast(compression_gain_db_); config.limiterEnable = limiter_enabled_; int error = AudioProcessing::kNoError; for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) { int error_ch = WebRtcAgc_set_config(mono_agcs_[ch]->state, config); if (error_ch != AudioProcessing::kNoError) { error = error_ch; } } return error; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/gain_control_impl.h0000664000175000017500000000566614475643423027046 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_GAIN_CONTROL_IMPL_H_ #define MODULES_AUDIO_PROCESSING_GAIN_CONTROL_IMPL_H_ #include #include #include #include #include "absl/types/optional.h" #include "api/array_view.h" #include "modules/audio_processing/agc/gain_control.h" namespace webrtc { class ApmDataDumper; class AudioBuffer; class GainControlImpl : public GainControl { public: GainControlImpl(); GainControlImpl(const GainControlImpl&) = delete; GainControlImpl& operator=(const GainControlImpl&) = delete; ~GainControlImpl() override; void ProcessRenderAudio(rtc::ArrayView packed_render_audio); int AnalyzeCaptureAudio(const AudioBuffer& audio); int ProcessCaptureAudio(AudioBuffer* audio, bool stream_has_echo); void Initialize(size_t num_proc_channels, int sample_rate_hz); static void PackRenderAudioBuffer(const AudioBuffer& audio, std::vector* packed_buffer); // GainControl implementation. int stream_analog_level() const override; bool is_limiter_enabled() const override { return limiter_enabled_; } Mode mode() const override { return mode_; } int set_mode(Mode mode) override; int compression_gain_db() const override { return compression_gain_db_; } int set_analog_level_limits(int minimum, int maximum) override; int set_compression_gain_db(int gain) override; int set_target_level_dbfs(int level) override; int enable_limiter(bool enable) override; int set_stream_analog_level(int level) override; private: struct MonoAgcState; // GainControl implementation. int target_level_dbfs() const override { return target_level_dbfs_; } int analog_level_minimum() const override { return minimum_capture_level_; } int analog_level_maximum() const override { return maximum_capture_level_; } bool stream_is_saturated() const override { return stream_is_saturated_; } int Configure(); std::unique_ptr data_dumper_; const bool use_legacy_gain_applier_; Mode mode_; int minimum_capture_level_; int maximum_capture_level_; bool limiter_enabled_; int target_level_dbfs_; int compression_gain_db_; int analog_capture_level_ = 0; bool was_analog_level_set_; bool stream_is_saturated_; std::vector> mono_agcs_; std::vector capture_levels_; absl::optional num_proc_channels_; absl::optional sample_rate_hz_; static int instance_counter_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_GAIN_CONTROL_IMPL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/gain_controller2.cc0000664000175000017500000001223114475643423026732 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/gain_controller2.h" #include "common_audio/include/audio_util.h" #include "modules/audio_processing/audio_buffer.h" #include "modules/audio_processing/include/audio_frame_view.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/atomic_ops.h" #include "rtc_base/checks.h" #include "rtc_base/strings/string_builder.h" namespace webrtc { int GainController2::instance_count_ = 0; GainController2::GainController2() : data_dumper_( new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), gain_applier_(/*hard_clip_samples=*/false, /*initial_gain_factor=*/0.f), limiter_(static_cast(48000), data_dumper_.get(), "Agc2") { if (config_.adaptive_digital.enabled) { adaptive_agc_.reset(new AdaptiveAgc(data_dumper_.get())); } } GainController2::~GainController2() = default; void GainController2::Initialize(int sample_rate_hz) { RTC_DCHECK(sample_rate_hz == AudioProcessing::kSampleRate8kHz || sample_rate_hz == AudioProcessing::kSampleRate16kHz || sample_rate_hz == AudioProcessing::kSampleRate32kHz || sample_rate_hz == AudioProcessing::kSampleRate48kHz); limiter_.SetSampleRate(sample_rate_hz); data_dumper_->InitiateNewSetOfRecordings(); data_dumper_->DumpRaw("sample_rate_hz", sample_rate_hz); } void GainController2::Process(AudioBuffer* audio) { AudioFrameView float_frame(audio->channels(), audio->num_channels(), audio->num_frames()); // Apply fixed gain first, then the adaptive one. gain_applier_.ApplyGain(float_frame); if (adaptive_agc_) { adaptive_agc_->Process(float_frame, limiter_.LastAudioLevel()); } limiter_.Process(float_frame); } void GainController2::NotifyAnalogLevel(int level) { if (analog_level_ != level && adaptive_agc_) { adaptive_agc_->Reset(); } analog_level_ = level; } void GainController2::ApplyConfig( const AudioProcessing::Config::GainController2& config) { RTC_DCHECK(Validate(config)) << " the invalid config was " << ToString(config); config_ = config; if (config.fixed_digital.gain_db != config_.fixed_digital.gain_db) { // Reset the limiter to quickly react on abrupt level changes caused by // large changes of the fixed gain. limiter_.Reset(); } gain_applier_.SetGainFactor(DbToRatio(config_.fixed_digital.gain_db)); if (config_.adaptive_digital.enabled) { adaptive_agc_.reset(new AdaptiveAgc(data_dumper_.get(), config_)); } else { adaptive_agc_.reset(); } } bool GainController2::Validate( const AudioProcessing::Config::GainController2& config) { return config.fixed_digital.gain_db >= 0.f && config.fixed_digital.gain_db < 50.f && config.adaptive_digital.extra_saturation_margin_db >= 0.f && config.adaptive_digital.extra_saturation_margin_db <= 100.f; } std::string GainController2::ToString( const AudioProcessing::Config::GainController2& config) { rtc::StringBuilder ss; std::string adaptive_digital_level_estimator; using LevelEstimatorType = AudioProcessing::Config::GainController2::LevelEstimator; switch (config.adaptive_digital.level_estimator) { case LevelEstimatorType::kRms: adaptive_digital_level_estimator = "RMS"; break; case LevelEstimatorType::kPeak: adaptive_digital_level_estimator = "peak"; break; } // clang-format off // clang formatting doesn't respect custom nested style. ss << "{" "enabled: " << (config.enabled ? "true" : "false") << ", " "fixed_digital: {gain_db: " << config.fixed_digital.gain_db << "}, " "adaptive_digital: {" "enabled: " << (config.adaptive_digital.enabled ? "true" : "false") << ", " "level_estimator: {" "type: " << adaptive_digital_level_estimator << ", " "adjacent_speech_frames_threshold: " << config.adaptive_digital .level_estimator_adjacent_speech_frames_threshold << ", " "initial_saturation_margin_db: " << config.adaptive_digital.initial_saturation_margin_db << ", " "extra_saturation_margin_db: " << config.adaptive_digital.extra_saturation_margin_db << "}, " "gain_applier: {" "adjacent_speech_frames_threshold: " << config.adaptive_digital .gain_applier_adjacent_speech_frames_threshold << ", " "max_gain_change_db_per_second: " << config.adaptive_digital.max_gain_change_db_per_second << ", " "max_output_noise_level_dbfs: " << config.adaptive_digital.max_output_noise_level_dbfs << "}" "}" "}"; // clang-format on return ss.Release(); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/gain_controller2.h0000664000175000017500000000346414475643423026604 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_GAIN_CONTROLLER2_H_ #define MODULES_AUDIO_PROCESSING_GAIN_CONTROLLER2_H_ #include #include #include "modules/audio_processing/agc2/adaptive_agc.h" #include "modules/audio_processing/agc2/gain_applier.h" #include "modules/audio_processing/agc2/limiter.h" #include "modules/audio_processing/include/audio_processing.h" #include "rtc_base/constructor_magic.h" namespace webrtc { class ApmDataDumper; class AudioBuffer; // Gain Controller 2 aims to automatically adjust levels by acting on the // microphone gain and/or applying digital gain. class GainController2 { public: GainController2(); ~GainController2(); void Initialize(int sample_rate_hz); void Process(AudioBuffer* audio); void NotifyAnalogLevel(int level); void ApplyConfig(const AudioProcessing::Config::GainController2& config); static bool Validate(const AudioProcessing::Config::GainController2& config); static std::string ToString( const AudioProcessing::Config::GainController2& config); private: static int instance_count_; std::unique_ptr data_dumper_; AudioProcessing::Config::GainController2 config_; GainApplier gain_applier_; std::unique_ptr adaptive_agc_; Limiter limiter_; int analog_level_ = -1; RTC_DISALLOW_COPY_AND_ASSIGN(GainController2); }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_GAIN_CONTROLLER2_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/high_pass_filter.cc0000664000175000017500000000723314475643423027007 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/high_pass_filter.h" #include "api/array_view.h" #include "modules/audio_processing/audio_buffer.h" #include "rtc_base/checks.h" namespace webrtc { namespace { // [B,A] = butter(2,100/8000,'high') constexpr CascadedBiQuadFilter::BiQuadCoefficients kHighPassFilterCoefficients16kHz = {{0.97261f, -1.94523f, 0.97261f}, {-1.94448f, 0.94598f}}; // [B,A] = butter(2,100/16000,'high') constexpr CascadedBiQuadFilter::BiQuadCoefficients kHighPassFilterCoefficients32kHz = {{0.98621f, -1.97242f, 0.98621f}, {-1.97223f, 0.97261f}}; // [B,A] = butter(2,100/24000,'high') constexpr CascadedBiQuadFilter::BiQuadCoefficients kHighPassFilterCoefficients48kHz = {{0.99079f, -1.98157f, 0.99079f}, {-1.98149f, 0.98166f}}; constexpr size_t kNumberOfHighPassBiQuads = 1; const CascadedBiQuadFilter::BiQuadCoefficients& ChooseCoefficients( int sample_rate_hz) { switch (sample_rate_hz) { case 16000: return kHighPassFilterCoefficients16kHz; case 32000: return kHighPassFilterCoefficients32kHz; case 48000: return kHighPassFilterCoefficients48kHz; default: RTC_NOTREACHED(); } RTC_NOTREACHED(); return kHighPassFilterCoefficients16kHz; } } // namespace HighPassFilter::HighPassFilter(int sample_rate_hz, size_t num_channels) : sample_rate_hz_(sample_rate_hz) { filters_.resize(num_channels); const auto& coefficients = ChooseCoefficients(sample_rate_hz_); for (size_t k = 0; k < filters_.size(); ++k) { filters_[k].reset( new CascadedBiQuadFilter(coefficients, kNumberOfHighPassBiQuads)); } } HighPassFilter::~HighPassFilter() = default; void HighPassFilter::Process(AudioBuffer* audio, bool use_split_band_data) { RTC_DCHECK(audio); RTC_DCHECK_EQ(filters_.size(), audio->num_channels()); if (use_split_band_data) { for (size_t k = 0; k < audio->num_channels(); ++k) { rtc::ArrayView channel_data = rtc::ArrayView( audio->split_bands(k)[0], audio->num_frames_per_band()); filters_[k]->Process(channel_data); } } else { for (size_t k = 0; k < audio->num_channels(); ++k) { rtc::ArrayView channel_data = rtc::ArrayView(&audio->channels()[k][0], audio->num_frames()); filters_[k]->Process(channel_data); } } } void HighPassFilter::Process(std::vector>* audio) { RTC_DCHECK_EQ(filters_.size(), audio->size()); for (size_t k = 0; k < audio->size(); ++k) { filters_[k]->Process((*audio)[k]); } } void HighPassFilter::Reset() { for (size_t k = 0; k < filters_.size(); ++k) { filters_[k]->Reset(); } } void HighPassFilter::Reset(size_t num_channels) { const size_t old_num_channels = filters_.size(); filters_.resize(num_channels); if (filters_.size() < old_num_channels) { Reset(); } else { for (size_t k = 0; k < old_num_channels; ++k) { filters_[k]->Reset(); } const auto& coefficients = ChooseCoefficients(sample_rate_hz_); for (size_t k = old_num_channels; k < filters_.size(); ++k) { filters_[k].reset( new CascadedBiQuadFilter(coefficients, kNumberOfHighPassBiQuads)); } } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/high_pass_filter.h0000664000175000017500000000255714475643423026655 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_HIGH_PASS_FILTER_H_ #define MODULES_AUDIO_PROCESSING_HIGH_PASS_FILTER_H_ #include #include #include "api/array_view.h" #include "modules/audio_processing/utility/cascaded_biquad_filter.h" namespace webrtc { class AudioBuffer; class HighPassFilter { public: HighPassFilter(int sample_rate_hz, size_t num_channels); ~HighPassFilter(); HighPassFilter(const HighPassFilter&) = delete; HighPassFilter& operator=(const HighPassFilter&) = delete; void Process(AudioBuffer* audio, bool use_split_band_data); void Process(std::vector>* audio); void Reset(); void Reset(size_t num_channels); int sample_rate_hz() const { return sample_rate_hz_; } size_t num_channels() const { return filters_.size(); } private: const int sample_rate_hz_; std::vector> filters_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_HIGH_PASS_FILTER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/include/0000775000175000017500000000000014475643423024604 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/include/aec_dump.cc0000664000175000017500000000376714475643423026705 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/include/aec_dump.h" namespace webrtc { InternalAPMConfig::InternalAPMConfig() = default; InternalAPMConfig::InternalAPMConfig(const InternalAPMConfig&) = default; InternalAPMConfig::InternalAPMConfig(InternalAPMConfig&&) = default; InternalAPMConfig& InternalAPMConfig::operator=(const InternalAPMConfig&) = default; bool InternalAPMConfig::operator==(const InternalAPMConfig& other) { return aec_enabled == other.aec_enabled && aec_delay_agnostic_enabled == other.aec_delay_agnostic_enabled && aec_drift_compensation_enabled == other.aec_drift_compensation_enabled && aec_extended_filter_enabled == other.aec_extended_filter_enabled && aec_suppression_level == other.aec_suppression_level && aecm_enabled == other.aecm_enabled && aecm_comfort_noise_enabled == other.aecm_comfort_noise_enabled && aecm_routing_mode == other.aecm_routing_mode && agc_enabled == other.agc_enabled && agc_mode == other.agc_mode && agc_limiter_enabled == other.agc_limiter_enabled && hpf_enabled == other.hpf_enabled && ns_enabled == other.ns_enabled && ns_level == other.ns_level && transient_suppression_enabled == other.transient_suppression_enabled && noise_robust_agc_enabled == other.noise_robust_agc_enabled && pre_amplifier_enabled == other.pre_amplifier_enabled && pre_amplifier_fixed_gain_factor == other.pre_amplifier_fixed_gain_factor && experiments_description == other.experiments_description; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/include/aec_dump.h0000664000175000017500000001015514475643423026534 0ustar00arunarun/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_INCLUDE_AEC_DUMP_H_ #define MODULES_AUDIO_PROCESSING_INCLUDE_AEC_DUMP_H_ #include #include #include "modules/audio_processing/include/audio_frame_view.h" #include "modules/audio_processing/include/audio_processing.h" #include "rtc_base/deprecation.h" namespace webrtc { // Struct for passing current config from APM without having to // include protobuf headers. struct InternalAPMConfig { InternalAPMConfig(); InternalAPMConfig(const InternalAPMConfig&); InternalAPMConfig(InternalAPMConfig&&); InternalAPMConfig& operator=(const InternalAPMConfig&); InternalAPMConfig& operator=(InternalAPMConfig&&) = delete; bool operator==(const InternalAPMConfig& other); bool aec_enabled = false; bool aec_delay_agnostic_enabled = false; bool aec_drift_compensation_enabled = false; bool aec_extended_filter_enabled = false; int aec_suppression_level = 0; bool aecm_enabled = false; bool aecm_comfort_noise_enabled = false; int aecm_routing_mode = 0; bool agc_enabled = false; int agc_mode = 0; bool agc_limiter_enabled = false; bool hpf_enabled = false; bool ns_enabled = false; int ns_level = 0; bool transient_suppression_enabled = false; bool noise_robust_agc_enabled = false; bool pre_amplifier_enabled = false; float pre_amplifier_fixed_gain_factor = 1.f; std::string experiments_description = ""; }; // An interface for recording configuration and input/output streams // of the Audio Processing Module. The recordings are called // 'aec-dumps' and are stored in a protobuf format defined in // debug.proto. // The Write* methods are always safe to call concurrently or // otherwise for all implementing subclasses. The intended mode of // operation is to create a protobuf object from the input, and send // it away to be written to file asynchronously. class AecDump { public: struct AudioProcessingState { int delay; int drift; int level; bool keypress; }; virtual ~AecDump() = default; // Logs Event::Type INIT message. virtual void WriteInitMessage(const ProcessingConfig& api_format, int64_t time_now_ms) = 0; RTC_DEPRECATED void WriteInitMessage(const ProcessingConfig& api_format) { WriteInitMessage(api_format, 0); } // Logs Event::Type STREAM message. To log an input/output pair, // call the AddCapture* and AddAudioProcessingState methods followed // by a WriteCaptureStreamMessage call. virtual void AddCaptureStreamInput( const AudioFrameView& src) = 0; virtual void AddCaptureStreamOutput( const AudioFrameView& src) = 0; virtual void AddCaptureStreamInput(const int16_t* const data, int num_channels, int samples_per_channel) = 0; virtual void AddCaptureStreamOutput(const int16_t* const data, int num_channels, int samples_per_channel) = 0; virtual void AddAudioProcessingState(const AudioProcessingState& state) = 0; virtual void WriteCaptureStreamMessage() = 0; // Logs Event::Type REVERSE_STREAM message. virtual void WriteRenderStreamMessage(const int16_t* const data, int num_channels, int samples_per_channel) = 0; virtual void WriteRenderStreamMessage( const AudioFrameView& src) = 0; virtual void WriteRuntimeSetting( const AudioProcessing::RuntimeSetting& runtime_setting) = 0; // Logs Event::Type CONFIG message. virtual void WriteConfig(const InternalAPMConfig& config) = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_INCLUDE_AEC_DUMP_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/include/audio_frame_proxies.cc0000664000175000017500000000507614475643423031147 0ustar00arunarun/* * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/include/audio_frame_proxies.h" #include "api/audio/audio_frame.h" #include "modules/audio_processing/include/audio_processing.h" namespace webrtc { int ProcessAudioFrame(AudioProcessing* ap, AudioFrame* frame) { if (!frame || !ap) { return AudioProcessing::Error::kNullPointerError; } StreamConfig input_config(frame->sample_rate_hz_, frame->num_channels_, /*has_keyboard=*/false); StreamConfig output_config(frame->sample_rate_hz_, frame->num_channels_, /*has_keyboard=*/false); RTC_DCHECK_EQ(frame->samples_per_channel(), input_config.num_frames()); int result = ap->ProcessStream(frame->data(), input_config, output_config, frame->mutable_data()); AudioProcessingStats stats = ap->GetStatistics(); if (stats.voice_detected) { frame->vad_activity_ = *stats.voice_detected ? AudioFrame::VADActivity::kVadActive : AudioFrame::VADActivity::kVadPassive; } return result; } int ProcessReverseAudioFrame(AudioProcessing* ap, AudioFrame* frame) { if (!frame || !ap) { return AudioProcessing::Error::kNullPointerError; } // Must be a native rate. if (frame->sample_rate_hz_ != AudioProcessing::NativeRate::kSampleRate8kHz && frame->sample_rate_hz_ != AudioProcessing::NativeRate::kSampleRate16kHz && frame->sample_rate_hz_ != AudioProcessing::NativeRate::kSampleRate32kHz && frame->sample_rate_hz_ != AudioProcessing::NativeRate::kSampleRate48kHz) { return AudioProcessing::Error::kBadSampleRateError; } if (frame->num_channels_ <= 0) { return AudioProcessing::Error::kBadNumberChannelsError; } StreamConfig input_config(frame->sample_rate_hz_, frame->num_channels_, /*has_keyboard=*/false); StreamConfig output_config(frame->sample_rate_hz_, frame->num_channels_, /*has_keyboard=*/false); int result = ap->ProcessReverseStream(frame->data(), input_config, output_config, frame->mutable_data()); return result; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/include/audio_frame_proxies.h0000664000175000017500000000353214475643423031004 0ustar00arunarun/* * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_FRAME_PROXIES_H_ #define MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_FRAME_PROXIES_H_ namespace webrtc { class AudioFrame; class AudioProcessing; // Processes a 10 ms |frame| of the primary audio stream using the provided // AudioProcessing object. On the client-side, this is the near-end (or // captured) audio. The |sample_rate_hz_|, |num_channels_|, and // |samples_per_channel_| members of |frame| must be valid. If changed from the // previous call to this function, it will trigger an initialization of the // provided AudioProcessing object. // The function returns any error codes passed from the AudioProcessing // ProcessStream method. int ProcessAudioFrame(AudioProcessing* ap, AudioFrame* frame); // Processes a 10 ms |frame| of the reverse direction audio stream using the // provided AudioProcessing object. The frame may be modified. On the // client-side, this is the far-end (or to be rendered) audio. The // |sample_rate_hz_|, |num_channels_|, and |samples_per_channel_| members of // |frame| must be valid. If changed from the previous call to this function, it // will trigger an initialization of the provided AudioProcessing object. // The function returns any error codes passed from the AudioProcessing // ProcessReverseStream method. int ProcessReverseAudioFrame(AudioProcessing* ap, AudioFrame* frame); } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_FRAME_PROXIES_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/include/audio_frame_view.h0000664000175000017500000000416014475643423030263 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_FRAME_VIEW_H_ #define MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_FRAME_VIEW_H_ #include "api/array_view.h" namespace webrtc { // Class to pass audio data in T** format, where T is a numeric type. template class AudioFrameView { public: // |num_channels| and |channel_size| describe the T** // |audio_samples|. |audio_samples| is assumed to point to a // two-dimensional |num_channels * channel_size| array of floats. AudioFrameView(T* const* audio_samples, size_t num_channels, size_t channel_size) : audio_samples_(audio_samples), num_channels_(num_channels), channel_size_(channel_size) {} // Implicit cast to allow converting Frame to // Frame. template AudioFrameView(AudioFrameView other) : audio_samples_(other.data()), num_channels_(other.num_channels()), channel_size_(other.samples_per_channel()) {} AudioFrameView() = delete; size_t num_channels() const { return num_channels_; } size_t samples_per_channel() const { return channel_size_; } rtc::ArrayView channel(size_t idx) { RTC_DCHECK_LE(0, idx); RTC_DCHECK_LE(idx, num_channels_); return rtc::ArrayView(audio_samples_[idx], channel_size_); } rtc::ArrayView channel(size_t idx) const { RTC_DCHECK_LE(0, idx); RTC_DCHECK_LE(idx, num_channels_); return rtc::ArrayView(audio_samples_[idx], channel_size_); } T* const* data() { return audio_samples_; } private: T* const* audio_samples_; size_t num_channels_; size_t channel_size_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_FRAME_VIEW_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/include/audio_processing.cc0000664000175000017500000001162014475643423030450 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/include/audio_processing.h" #include "rtc_base/strings/string_builder.h" #include "rtc_base/system/arch.h" namespace webrtc { namespace { std::string NoiseSuppressionLevelToString( const AudioProcessing::Config::NoiseSuppression::Level& level) { switch (level) { case AudioProcessing::Config::NoiseSuppression::Level::kLow: return "Low"; case AudioProcessing::Config::NoiseSuppression::Level::kModerate: return "Moderate"; case AudioProcessing::Config::NoiseSuppression::Level::kHigh: return "High"; case AudioProcessing::Config::NoiseSuppression::Level::kVeryHigh: return "VeryHigh"; } } std::string GainController1ModeToString( const AudioProcessing::Config::GainController1::Mode& mode) { switch (mode) { case AudioProcessing::Config::GainController1::Mode::kAdaptiveAnalog: return "AdaptiveAnalog"; case AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital: return "AdaptiveDigital"; case AudioProcessing::Config::GainController1::Mode::kFixedDigital: return "FixedDigital"; } } std::string GainController2LevelEstimatorToString( const AudioProcessing::Config::GainController2::LevelEstimator& level) { switch (level) { case AudioProcessing::Config::GainController2::LevelEstimator::kRms: return "Rms"; case AudioProcessing::Config::GainController2::LevelEstimator::kPeak: return "Peak"; } } int GetDefaultMaxInternalRate() { #ifdef WEBRTC_ARCH_ARM_FAMILY return 32000; #else return 48000; #endif } } // namespace constexpr int AudioProcessing::kNativeSampleRatesHz[]; void CustomProcessing::SetRuntimeSetting( AudioProcessing::RuntimeSetting setting) {} AudioProcessing::Config::Pipeline::Pipeline() : maximum_internal_processing_rate(GetDefaultMaxInternalRate()) {} std::string AudioProcessing::Config::ToString() const { char buf[1024]; rtc::SimpleStringBuilder builder(buf); builder << "AudioProcessing::Config{ " "pipeline: {" "maximum_internal_processing_rate: " << pipeline.maximum_internal_processing_rate << ", multi_channel_render: " << pipeline.multi_channel_render << ", " ", multi_channel_capture: " << pipeline.multi_channel_capture << "}, " "pre_amplifier: { enabled: " << pre_amplifier.enabled << ", fixed_gain_factor: " << pre_amplifier.fixed_gain_factor << " }, high_pass_filter: { enabled: " << high_pass_filter.enabled << " }, echo_canceller: { enabled: " << echo_canceller.enabled << ", mobile_mode: " << echo_canceller.mobile_mode << ", enforce_high_pass_filtering: " << echo_canceller.enforce_high_pass_filtering << " }, noise_suppression: { enabled: " << noise_suppression.enabled << ", level: " << NoiseSuppressionLevelToString(noise_suppression.level) << " }, transient_suppression: { enabled: " << transient_suppression.enabled << " }, voice_detection: { enabled: " << voice_detection.enabled << " }, gain_controller1: { enabled: " << gain_controller1.enabled << ", mode: " << GainController1ModeToString(gain_controller1.mode) << ", target_level_dbfs: " << gain_controller1.target_level_dbfs << ", compression_gain_db: " << gain_controller1.compression_gain_db << ", enable_limiter: " << gain_controller1.enable_limiter << ", analog_level_minimum: " << gain_controller1.analog_level_minimum << ", analog_level_maximum: " << gain_controller1.analog_level_maximum << " }, gain_controller2: { enabled: " << gain_controller2.enabled << ", fixed_digital: { gain_db: " << gain_controller2.fixed_digital.gain_db << " }, adaptive_digital: { enabled: " << gain_controller2.adaptive_digital.enabled << ", level_estimator: " << GainController2LevelEstimatorToString( gain_controller2.adaptive_digital.level_estimator) << ", use_saturation_protector: " << gain_controller2.adaptive_digital.use_saturation_protector << ", extra_saturation_margin_db: " << gain_controller2.adaptive_digital.extra_saturation_margin_db << " } }, residual_echo_detector: { enabled: " << residual_echo_detector.enabled << " }, level_estimation: { enabled: " << level_estimation.enabled << " } }"; return builder.str(); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/include/audio_processing.h0000664000175000017500000011033314475643423030313 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_PROCESSING_H_ #define MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_PROCESSING_H_ // MSVC++ requires this to be set before any other includes to get M_PI. #ifndef _USE_MATH_DEFINES #define _USE_MATH_DEFINES #endif #include #include // size_t #include // FILE #include #include #include "absl/types/optional.h" #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "api/audio/echo_control.h" #include "api/scoped_refptr.h" #include "modules/audio_processing/include/audio_processing_statistics.h" #include "modules/audio_processing/include/config.h" #include "rtc_base/arraysize.h" #include "rtc_base/constructor_magic.h" #include "rtc_base/deprecation.h" #include "rtc_base/ref_count.h" #include "rtc_base/system/file_wrapper.h" #include "rtc_base/system/rtc_export.h" namespace rtc { class TaskQueue; } // namespace rtc namespace webrtc { class AecDump; class AudioBuffer; class StreamConfig; class ProcessingConfig; class EchoDetector; class CustomAudioAnalyzer; class CustomProcessing; // Use to enable experimental gain control (AGC). At startup the experimental // AGC moves the microphone volume up to |startup_min_volume| if the current // microphone volume is set too low. The value is clamped to its operating range // [12, 255]. Here, 255 maps to 100%. // // Must be provided through AudioProcessingBuilder().Create(config). #if defined(WEBRTC_CHROMIUM_BUILD) static const int kAgcStartupMinVolume = 85; #else static const int kAgcStartupMinVolume = 0; #endif // defined(WEBRTC_CHROMIUM_BUILD) static constexpr int kClippedLevelMin = 70; // To be deprecated: Please instead use the flag in the // AudioProcessing::Config::AnalogGainController. // TODO(webrtc:5298): Remove. struct ExperimentalAgc { ExperimentalAgc() = default; explicit ExperimentalAgc(bool enabled) : enabled(enabled) {} ExperimentalAgc(bool enabled, bool enabled_agc2_level_estimator, bool digital_adaptive_disabled) : enabled(enabled), enabled_agc2_level_estimator(enabled_agc2_level_estimator), digital_adaptive_disabled(digital_adaptive_disabled) {} // Deprecated constructor: will be removed. ExperimentalAgc(bool enabled, bool enabled_agc2_level_estimator, bool digital_adaptive_disabled, bool analyze_before_aec) : enabled(enabled), enabled_agc2_level_estimator(enabled_agc2_level_estimator), digital_adaptive_disabled(digital_adaptive_disabled) {} ExperimentalAgc(bool enabled, int startup_min_volume) : enabled(enabled), startup_min_volume(startup_min_volume) {} ExperimentalAgc(bool enabled, int startup_min_volume, int clipped_level_min) : enabled(enabled), startup_min_volume(startup_min_volume), clipped_level_min(clipped_level_min) {} static const ConfigOptionID identifier = ConfigOptionID::kExperimentalAgc; bool enabled = true; int startup_min_volume = kAgcStartupMinVolume; // Lowest microphone level that will be applied in response to clipping. int clipped_level_min = kClippedLevelMin; bool enabled_agc2_level_estimator = false; bool digital_adaptive_disabled = false; }; // To be deprecated: Please instead use the flag in the // AudioProcessing::Config::TransientSuppression. // // Use to enable experimental noise suppression. It can be set in the // constructor. // TODO(webrtc:5298): Remove. struct ExperimentalNs { ExperimentalNs() : enabled(false) {} explicit ExperimentalNs(bool enabled) : enabled(enabled) {} static const ConfigOptionID identifier = ConfigOptionID::kExperimentalNs; bool enabled; }; // The Audio Processing Module (APM) provides a collection of voice processing // components designed for real-time communications software. // // APM operates on two audio streams on a frame-by-frame basis. Frames of the // primary stream, on which all processing is applied, are passed to // |ProcessStream()|. Frames of the reverse direction stream are passed to // |ProcessReverseStream()|. On the client-side, this will typically be the // near-end (capture) and far-end (render) streams, respectively. APM should be // placed in the signal chain as close to the audio hardware abstraction layer // (HAL) as possible. // // On the server-side, the reverse stream will normally not be used, with // processing occurring on each incoming stream. // // Component interfaces follow a similar pattern and are accessed through // corresponding getters in APM. All components are disabled at create-time, // with default settings that are recommended for most situations. New settings // can be applied without enabling a component. Enabling a component triggers // memory allocation and initialization to allow it to start processing the // streams. // // Thread safety is provided with the following assumptions to reduce locking // overhead: // 1. The stream getters and setters are called from the same thread as // ProcessStream(). More precisely, stream functions are never called // concurrently with ProcessStream(). // 2. Parameter getters are never called concurrently with the corresponding // setter. // // APM accepts only linear PCM audio data in chunks of 10 ms. The int16 // interfaces use interleaved data, while the float interfaces use deinterleaved // data. // // Usage example, omitting error checking: // AudioProcessing* apm = AudioProcessingBuilder().Create(); // // AudioProcessing::Config config; // config.echo_canceller.enabled = true; // config.echo_canceller.mobile_mode = false; // // config.gain_controller1.enabled = true; // config.gain_controller1.mode = // AudioProcessing::Config::GainController1::kAdaptiveAnalog; // config.gain_controller1.analog_level_minimum = 0; // config.gain_controller1.analog_level_maximum = 255; // // config.gain_controller2.enabled = true; // // config.high_pass_filter.enabled = true; // // config.voice_detection.enabled = true; // // apm->ApplyConfig(config) // // apm->noise_reduction()->set_level(kHighSuppression); // apm->noise_reduction()->Enable(true); // // // Start a voice call... // // // ... Render frame arrives bound for the audio HAL ... // apm->ProcessReverseStream(render_frame); // // // ... Capture frame arrives from the audio HAL ... // // Call required set_stream_ functions. // apm->set_stream_delay_ms(delay_ms); // apm->set_stream_analog_level(analog_level); // // apm->ProcessStream(capture_frame); // // // Call required stream_ functions. // analog_level = apm->recommended_stream_analog_level(); // has_voice = apm->stream_has_voice(); // // // Repeate render and capture processing for the duration of the call... // // Start a new call... // apm->Initialize(); // // // Close the application... // delete apm; // class RTC_EXPORT AudioProcessing : public rtc::RefCountInterface { public: // The struct below constitutes the new parameter scheme for the audio // processing. It is being introduced gradually and until it is fully // introduced, it is prone to change. // TODO(peah): Remove this comment once the new config scheme is fully rolled // out. // // The parameters and behavior of the audio processing module are controlled // by changing the default values in the AudioProcessing::Config struct. // The config is applied by passing the struct to the ApplyConfig method. // // This config is intended to be used during setup, and to enable/disable // top-level processing effects. Use during processing may cause undesired // submodule resets, affecting the audio quality. Use the RuntimeSetting // construct for runtime configuration. struct RTC_EXPORT Config { // Sets the properties of the audio processing pipeline. struct RTC_EXPORT Pipeline { Pipeline(); // Maximum allowed processing rate used internally. May only be set to // 32000 or 48000 and any differing values will be treated as 48000. The // default rate is currently selected based on the CPU architecture, but // that logic may change. int maximum_internal_processing_rate; // Allow multi-channel processing of render audio. bool multi_channel_render = false; // Allow multi-channel processing of capture audio when AEC3 is active // or a custom AEC is injected.. bool multi_channel_capture = false; } pipeline; // Enabled the pre-amplifier. It amplifies the capture signal // before any other processing is done. struct PreAmplifier { bool enabled = false; float fixed_gain_factor = 1.f; } pre_amplifier; struct HighPassFilter { bool enabled = false; bool apply_in_full_band = true; } high_pass_filter; struct EchoCanceller { bool enabled = false; bool mobile_mode = false; bool export_linear_aec_output = false; // Enforce the highpass filter to be on (has no effect for the mobile // mode). bool enforce_high_pass_filtering = true; } echo_canceller; // Enables background noise suppression. struct NoiseSuppression { bool enabled = false; enum Level { kLow, kModerate, kHigh, kVeryHigh }; Level level = kModerate; bool analyze_linear_aec_output_when_available = false; } noise_suppression; // Enables transient suppression. struct TransientSuppression { bool enabled = false; } transient_suppression; // Enables reporting of |voice_detected| in webrtc::AudioProcessingStats. struct VoiceDetection { bool enabled = false; } voice_detection; // Enables automatic gain control (AGC) functionality. // The automatic gain control (AGC) component brings the signal to an // appropriate range. This is done by applying a digital gain directly and, // in the analog mode, prescribing an analog gain to be applied at the audio // HAL. // Recommended to be enabled on the client-side. struct GainController1 { bool enabled = false; enum Mode { // Adaptive mode intended for use if an analog volume control is // available on the capture device. It will require the user to provide // coupling between the OS mixer controls and AGC through the // stream_analog_level() functions. // It consists of an analog gain prescription for the audio device and a // digital compression stage. kAdaptiveAnalog, // Adaptive mode intended for situations in which an analog volume // control is unavailable. It operates in a similar fashion to the // adaptive analog mode, but with scaling instead applied in the digital // domain. As with the analog mode, it additionally uses a digital // compression stage. kAdaptiveDigital, // Fixed mode which enables only the digital compression stage also used // by the two adaptive modes. // It is distinguished from the adaptive modes by considering only a // short time-window of the input signal. It applies a fixed gain // through most of the input level range, and compresses (gradually // reduces gain with increasing level) the input signal at higher // levels. This mode is preferred on embedded devices where the capture // signal level is predictable, so that a known gain can be applied. kFixedDigital }; Mode mode = kAdaptiveAnalog; // Sets the target peak level (or envelope) of the AGC in dBFs (decibels // from digital full-scale). The convention is to use positive values. For // instance, passing in a value of 3 corresponds to -3 dBFs, or a target // level 3 dB below full-scale. Limited to [0, 31]. int target_level_dbfs = 3; // Sets the maximum gain the digital compression stage may apply, in dB. A // higher number corresponds to greater compression, while a value of 0 // will leave the signal uncompressed. Limited to [0, 90]. // For updates after APM setup, use a RuntimeSetting instead. int compression_gain_db = 9; // When enabled, the compression stage will hard limit the signal to the // target level. Otherwise, the signal will be compressed but not limited // above the target level. bool enable_limiter = true; // Sets the minimum and maximum analog levels of the audio capture device. // Must be set if an analog mode is used. Limited to [0, 65535]. int analog_level_minimum = 0; int analog_level_maximum = 255; // Enables the analog gain controller functionality. struct AnalogGainController { bool enabled = true; int startup_min_volume = kAgcStartupMinVolume; // Lowest analog microphone level that will be applied in response to // clipping. int clipped_level_min = kClippedLevelMin; bool enable_agc2_level_estimator = false; bool enable_digital_adaptive = true; } analog_gain_controller; } gain_controller1; // Enables the next generation AGC functionality. This feature replaces the // standard methods of gain control in the previous AGC. Enabling this // submodule enables an adaptive digital AGC followed by a limiter. By // setting |fixed_gain_db|, the limiter can be turned into a compressor that // first applies a fixed gain. The adaptive digital AGC can be turned off by // setting |adaptive_digital_mode=false|. struct GainController2 { enum LevelEstimator { kRms, kPeak }; bool enabled = false; struct { float gain_db = 0.f; } fixed_digital; struct { bool enabled = false; float vad_probability_attack = 1.f; LevelEstimator level_estimator = kRms; int level_estimator_adjacent_speech_frames_threshold = 1; // TODO(crbug.com/webrtc/7494): Remove `use_saturation_protector`. bool use_saturation_protector = true; float initial_saturation_margin_db = 20.f; float extra_saturation_margin_db = 2.f; int gain_applier_adjacent_speech_frames_threshold = 1; float max_gain_change_db_per_second = 3.f; float max_output_noise_level_dbfs = -50.f; } adaptive_digital; } gain_controller2; struct ResidualEchoDetector { bool enabled = true; } residual_echo_detector; // Enables reporting of |output_rms_dbfs| in webrtc::AudioProcessingStats. struct LevelEstimation { bool enabled = false; } level_estimation; std::string ToString() const; }; // TODO(mgraczyk): Remove once all methods that use ChannelLayout are gone. enum ChannelLayout { kMono, // Left, right. kStereo, // Mono, keyboard, and mic. kMonoAndKeyboard, // Left, right, keyboard, and mic. kStereoAndKeyboard }; // Specifies the properties of a setting to be passed to AudioProcessing at // runtime. class RuntimeSetting { public: enum class Type { kNotSpecified, kCapturePreGain, kCaptureCompressionGain, kCaptureFixedPostGain, kPlayoutVolumeChange, kCustomRenderProcessingRuntimeSetting, kPlayoutAudioDeviceChange, kCaptureOutputUsed }; // Play-out audio device properties. struct PlayoutAudioDeviceInfo { int id; // Identifies the audio device. int max_volume; // Maximum play-out volume. }; RuntimeSetting() : type_(Type::kNotSpecified), value_(0.f) {} ~RuntimeSetting() = default; static RuntimeSetting CreateCapturePreGain(float gain) { RTC_DCHECK_GE(gain, 1.f) << "Attenuation is not allowed."; return {Type::kCapturePreGain, gain}; } // Corresponds to Config::GainController1::compression_gain_db, but for // runtime configuration. static RuntimeSetting CreateCompressionGainDb(int gain_db) { RTC_DCHECK_GE(gain_db, 0); RTC_DCHECK_LE(gain_db, 90); return {Type::kCaptureCompressionGain, static_cast(gain_db)}; } // Corresponds to Config::GainController2::fixed_digital::gain_db, but for // runtime configuration. static RuntimeSetting CreateCaptureFixedPostGain(float gain_db) { RTC_DCHECK_GE(gain_db, 0.f); RTC_DCHECK_LE(gain_db, 90.f); return {Type::kCaptureFixedPostGain, gain_db}; } // Creates a runtime setting to notify play-out (aka render) audio device // changes. static RuntimeSetting CreatePlayoutAudioDeviceChange( PlayoutAudioDeviceInfo audio_device) { return {Type::kPlayoutAudioDeviceChange, audio_device}; } // Creates a runtime setting to notify play-out (aka render) volume changes. // |volume| is the unnormalized volume, the maximum of which static RuntimeSetting CreatePlayoutVolumeChange(int volume) { return {Type::kPlayoutVolumeChange, volume}; } static RuntimeSetting CreateCustomRenderSetting(float payload) { return {Type::kCustomRenderProcessingRuntimeSetting, payload}; } static RuntimeSetting CreateCaptureOutputUsedSetting(bool payload) { return {Type::kCaptureOutputUsed, payload}; } Type type() const { return type_; } // Getters do not return a value but instead modify the argument to protect // from implicit casting. void GetFloat(float* value) const { RTC_DCHECK(value); *value = value_.float_value; } void GetInt(int* value) const { RTC_DCHECK(value); *value = value_.int_value; } void GetBool(bool* value) const { RTC_DCHECK(value); *value = value_.bool_value; } void GetPlayoutAudioDeviceInfo(PlayoutAudioDeviceInfo* value) const { RTC_DCHECK(value); *value = value_.playout_audio_device_info; } private: RuntimeSetting(Type id, float value) : type_(id), value_(value) {} RuntimeSetting(Type id, int value) : type_(id), value_(value) {} RuntimeSetting(Type id, PlayoutAudioDeviceInfo value) : type_(id), value_(value) {} Type type_; union U { U() {} U(int value) : int_value(value) {} U(float value) : float_value(value) {} U(PlayoutAudioDeviceInfo value) : playout_audio_device_info(value) {} float float_value; int int_value; bool bool_value; PlayoutAudioDeviceInfo playout_audio_device_info; } value_; }; ~AudioProcessing() override {} // Initializes internal states, while retaining all user settings. This // should be called before beginning to process a new audio stream. However, // it is not necessary to call before processing the first stream after // creation. // // It is also not necessary to call if the audio parameters (sample // rate and number of channels) have changed. Passing updated parameters // directly to |ProcessStream()| and |ProcessReverseStream()| is permissible. // If the parameters are known at init-time though, they may be provided. // TODO(webrtc:5298): Change to return void. virtual int Initialize() = 0; // The int16 interfaces require: // - only |NativeRate|s be used // - that the input, output and reverse rates must match // - that |processing_config.output_stream()| matches // |processing_config.input_stream()|. // // The float interfaces accept arbitrary rates and support differing input and // output layouts, but the output must have either one channel or the same // number of channels as the input. virtual int Initialize(const ProcessingConfig& processing_config) = 0; // Initialize with unpacked parameters. See Initialize() above for details. // // TODO(mgraczyk): Remove once clients are updated to use the new interface. virtual int Initialize(int capture_input_sample_rate_hz, int capture_output_sample_rate_hz, int render_sample_rate_hz, ChannelLayout capture_input_layout, ChannelLayout capture_output_layout, ChannelLayout render_input_layout) = 0; // TODO(peah): This method is a temporary solution used to take control // over the parameters in the audio processing module and is likely to change. virtual void ApplyConfig(const Config& config) = 0; // TODO(ajm): Only intended for internal use. Make private and friend the // necessary classes? virtual int proc_sample_rate_hz() const = 0; virtual int proc_split_sample_rate_hz() const = 0; virtual size_t num_input_channels() const = 0; virtual size_t num_proc_channels() const = 0; virtual size_t num_output_channels() const = 0; virtual size_t num_reverse_channels() const = 0; // Set to true when the output of AudioProcessing will be muted or in some // other way not used. Ideally, the captured audio would still be processed, // but some components may change behavior based on this information. // Default false. virtual void set_output_will_be_muted(bool muted) = 0; // Enqueue a runtime setting. virtual void SetRuntimeSetting(RuntimeSetting setting) = 0; // Accepts and produces a 10 ms frame interleaved 16 bit integer audio as // specified in |input_config| and |output_config|. |src| and |dest| may use // the same memory, if desired. virtual int ProcessStream(const int16_t* const src, const StreamConfig& input_config, const StreamConfig& output_config, int16_t* const dest) = 0; // Accepts deinterleaved float audio with the range [-1, 1]. Each element of // |src| points to a channel buffer, arranged according to |input_stream|. At // output, the channels will be arranged according to |output_stream| in // |dest|. // // The output must have one channel or as many channels as the input. |src| // and |dest| may use the same memory, if desired. virtual int ProcessStream(const float* const* src, const StreamConfig& input_config, const StreamConfig& output_config, float* const* dest) = 0; // Accepts and produces a 10 ms frame of interleaved 16 bit integer audio for // the reverse direction audio stream as specified in |input_config| and // |output_config|. |src| and |dest| may use the same memory, if desired. virtual int ProcessReverseStream(const int16_t* const src, const StreamConfig& input_config, const StreamConfig& output_config, int16_t* const dest) = 0; // Accepts deinterleaved float audio with the range [-1, 1]. Each element of // |data| points to a channel buffer, arranged according to |reverse_config|. virtual int ProcessReverseStream(const float* const* src, const StreamConfig& input_config, const StreamConfig& output_config, float* const* dest) = 0; // Accepts deinterleaved float audio with the range [-1, 1]. Each element // of |data| points to a channel buffer, arranged according to // |reverse_config|. virtual int AnalyzeReverseStream(const float* const* data, const StreamConfig& reverse_config) = 0; // Returns the most recently produced 10 ms of the linear AEC output at a rate // of 16 kHz. If there is more than one capture channel, a mono representation // of the input is returned. Returns true/false to indicate whether an output // returned. virtual bool GetLinearAecOutput( rtc::ArrayView> linear_output) const = 0; // This must be called prior to ProcessStream() if and only if adaptive analog // gain control is enabled, to pass the current analog level from the audio // HAL. Must be within the range provided in Config::GainController1. virtual void set_stream_analog_level(int level) = 0; // When an analog mode is set, this should be called after ProcessStream() // to obtain the recommended new analog level for the audio HAL. It is the // user's responsibility to apply this level. virtual int recommended_stream_analog_level() const = 0; // This must be called if and only if echo processing is enabled. // // Sets the |delay| in ms between ProcessReverseStream() receiving a far-end // frame and ProcessStream() receiving a near-end frame containing the // corresponding echo. On the client-side this can be expressed as // delay = (t_render - t_analyze) + (t_process - t_capture) // where, // - t_analyze is the time a frame is passed to ProcessReverseStream() and // t_render is the time the first sample of the same frame is rendered by // the audio hardware. // - t_capture is the time the first sample of a frame is captured by the // audio hardware and t_process is the time the same frame is passed to // ProcessStream(). virtual int set_stream_delay_ms(int delay) = 0; virtual int stream_delay_ms() const = 0; // Call to signal that a key press occurred (true) or did not occur (false) // with this chunk of audio. virtual void set_stream_key_pressed(bool key_pressed) = 0; // Creates and attaches an webrtc::AecDump for recording debugging // information. // The |worker_queue| may not be null and must outlive the created // AecDump instance. |max_log_size_bytes == -1| means the log size // will be unlimited. |handle| may not be null. The AecDump takes // responsibility for |handle| and closes it in the destructor. A // return value of true indicates that the file has been // sucessfully opened, while a value of false indicates that // opening the file failed. virtual bool CreateAndAttachAecDump(const std::string& file_name, int64_t max_log_size_bytes, rtc::TaskQueue* worker_queue) = 0; virtual bool CreateAndAttachAecDump(FILE* handle, int64_t max_log_size_bytes, rtc::TaskQueue* worker_queue) = 0; // TODO(webrtc:5298) Deprecated variant. // Attaches provided webrtc::AecDump for recording debugging // information. Log file and maximum file size logic is supposed to // be handled by implementing instance of AecDump. Calling this // method when another AecDump is attached resets the active AecDump // with a new one. This causes the d-tor of the earlier AecDump to // be called. The d-tor call may block until all pending logging // tasks are completed. virtual void AttachAecDump(std::unique_ptr aec_dump) = 0; // If no AecDump is attached, this has no effect. If an AecDump is // attached, it's destructor is called. The d-tor may block until // all pending logging tasks are completed. virtual void DetachAecDump() = 0; // Get audio processing statistics. virtual AudioProcessingStats GetStatistics() = 0; // TODO(webrtc:5298) Deprecated variant. The |has_remote_tracks| argument // should be set if there are active remote tracks (this would usually be true // during a call). If there are no remote tracks some of the stats will not be // set by AudioProcessing, because they only make sense if there is at least // one remote track. virtual AudioProcessingStats GetStatistics(bool has_remote_tracks) = 0; // Returns the last applied configuration. virtual AudioProcessing::Config GetConfig() const = 0; enum Error { // Fatal errors. kNoError = 0, kUnspecifiedError = -1, kCreationFailedError = -2, kUnsupportedComponentError = -3, kUnsupportedFunctionError = -4, kNullPointerError = -5, kBadParameterError = -6, kBadSampleRateError = -7, kBadDataLengthError = -8, kBadNumberChannelsError = -9, kFileError = -10, kStreamParameterNotSetError = -11, kNotEnabledError = -12, // Warnings are non-fatal. // This results when a set_stream_ parameter is out of range. Processing // will continue, but the parameter may have been truncated. kBadStreamParameterWarning = -13 }; // Native rates supported by the integer interfaces. enum NativeRate { kSampleRate8kHz = 8000, kSampleRate16kHz = 16000, kSampleRate32kHz = 32000, kSampleRate48kHz = 48000 }; // TODO(kwiberg): We currently need to support a compiler (Visual C++) that // complains if we don't explicitly state the size of the array here. Remove // the size when that's no longer the case. static constexpr int kNativeSampleRatesHz[4] = { kSampleRate8kHz, kSampleRate16kHz, kSampleRate32kHz, kSampleRate48kHz}; static constexpr size_t kNumNativeSampleRates = arraysize(kNativeSampleRatesHz); static constexpr int kMaxNativeSampleRateHz = kNativeSampleRatesHz[kNumNativeSampleRates - 1]; static const int kChunkSizeMs = 10; }; class RTC_EXPORT AudioProcessingBuilder { public: AudioProcessingBuilder(); ~AudioProcessingBuilder(); // The AudioProcessingBuilder takes ownership of the echo_control_factory. AudioProcessingBuilder& SetEchoControlFactory( std::unique_ptr echo_control_factory) { echo_control_factory_ = std::move(echo_control_factory); return *this; } // The AudioProcessingBuilder takes ownership of the capture_post_processing. AudioProcessingBuilder& SetCapturePostProcessing( std::unique_ptr capture_post_processing) { capture_post_processing_ = std::move(capture_post_processing); return *this; } // The AudioProcessingBuilder takes ownership of the render_pre_processing. AudioProcessingBuilder& SetRenderPreProcessing( std::unique_ptr render_pre_processing) { render_pre_processing_ = std::move(render_pre_processing); return *this; } // The AudioProcessingBuilder takes ownership of the echo_detector. AudioProcessingBuilder& SetEchoDetector( rtc::scoped_refptr echo_detector) { echo_detector_ = std::move(echo_detector); return *this; } // The AudioProcessingBuilder takes ownership of the capture_analyzer. AudioProcessingBuilder& SetCaptureAnalyzer( std::unique_ptr capture_analyzer) { capture_analyzer_ = std::move(capture_analyzer); return *this; } // This creates an APM instance using the previously set components. Calling // the Create function resets the AudioProcessingBuilder to its initial state. AudioProcessing* Create(); AudioProcessing* Create(const webrtc::Config& config); private: std::unique_ptr echo_control_factory_; std::unique_ptr capture_post_processing_; std::unique_ptr render_pre_processing_; rtc::scoped_refptr echo_detector_; std::unique_ptr capture_analyzer_; RTC_DISALLOW_COPY_AND_ASSIGN(AudioProcessingBuilder); }; class StreamConfig { public: // sample_rate_hz: The sampling rate of the stream. // // num_channels: The number of audio channels in the stream, excluding the // keyboard channel if it is present. When passing a // StreamConfig with an array of arrays T*[N], // // N == {num_channels + 1 if has_keyboard // {num_channels if !has_keyboard // // has_keyboard: True if the stream has a keyboard channel. When has_keyboard // is true, the last channel in any corresponding list of // channels is the keyboard channel. StreamConfig(int sample_rate_hz = 0, size_t num_channels = 0, bool has_keyboard = false) : sample_rate_hz_(sample_rate_hz), num_channels_(num_channels), has_keyboard_(has_keyboard), num_frames_(calculate_frames(sample_rate_hz)) {} void set_sample_rate_hz(int value) { sample_rate_hz_ = value; num_frames_ = calculate_frames(value); } void set_num_channels(size_t value) { num_channels_ = value; } void set_has_keyboard(bool value) { has_keyboard_ = value; } int sample_rate_hz() const { return sample_rate_hz_; } // The number of channels in the stream, not including the keyboard channel if // present. size_t num_channels() const { return num_channels_; } bool has_keyboard() const { return has_keyboard_; } size_t num_frames() const { return num_frames_; } size_t num_samples() const { return num_channels_ * num_frames_; } bool operator==(const StreamConfig& other) const { return sample_rate_hz_ == other.sample_rate_hz_ && num_channels_ == other.num_channels_ && has_keyboard_ == other.has_keyboard_; } bool operator!=(const StreamConfig& other) const { return !(*this == other); } private: static size_t calculate_frames(int sample_rate_hz) { return static_cast(AudioProcessing::kChunkSizeMs * sample_rate_hz / 1000); } int sample_rate_hz_; size_t num_channels_; bool has_keyboard_; size_t num_frames_; }; class ProcessingConfig { public: enum StreamName { kInputStream, kOutputStream, kReverseInputStream, kReverseOutputStream, kNumStreamNames, }; const StreamConfig& input_stream() const { return streams[StreamName::kInputStream]; } const StreamConfig& output_stream() const { return streams[StreamName::kOutputStream]; } const StreamConfig& reverse_input_stream() const { return streams[StreamName::kReverseInputStream]; } const StreamConfig& reverse_output_stream() const { return streams[StreamName::kReverseOutputStream]; } StreamConfig& input_stream() { return streams[StreamName::kInputStream]; } StreamConfig& output_stream() { return streams[StreamName::kOutputStream]; } StreamConfig& reverse_input_stream() { return streams[StreamName::kReverseInputStream]; } StreamConfig& reverse_output_stream() { return streams[StreamName::kReverseOutputStream]; } bool operator==(const ProcessingConfig& other) const { for (int i = 0; i < StreamName::kNumStreamNames; ++i) { if (this->streams[i] != other.streams[i]) { return false; } } return true; } bool operator!=(const ProcessingConfig& other) const { return !(*this == other); } StreamConfig streams[StreamName::kNumStreamNames]; }; // Experimental interface for a custom analysis submodule. class CustomAudioAnalyzer { public: // (Re-) Initializes the submodule. virtual void Initialize(int sample_rate_hz, int num_channels) = 0; // Analyzes the given capture or render signal. virtual void Analyze(const AudioBuffer* audio) = 0; // Returns a string representation of the module state. virtual std::string ToString() const = 0; virtual ~CustomAudioAnalyzer() {} }; // Interface for a custom processing submodule. class CustomProcessing { public: // (Re-)Initializes the submodule. virtual void Initialize(int sample_rate_hz, int num_channels) = 0; // Processes the given capture or render signal. virtual void Process(AudioBuffer* audio) = 0; // Returns a string representation of the module state. virtual std::string ToString() const = 0; // Handles RuntimeSettings. TODO(webrtc:9262): make pure virtual // after updating dependencies. virtual void SetRuntimeSetting(AudioProcessing::RuntimeSetting setting); virtual ~CustomProcessing() {} }; // Interface for an echo detector submodule. class EchoDetector : public rtc::RefCountInterface { public: // (Re-)Initializes the submodule. virtual void Initialize(int capture_sample_rate_hz, int num_capture_channels, int render_sample_rate_hz, int num_render_channels) = 0; // Analysis (not changing) of the render signal. virtual void AnalyzeRenderAudio(rtc::ArrayView render_audio) = 0; // Analysis (not changing) of the capture signal. virtual void AnalyzeCaptureAudio( rtc::ArrayView capture_audio) = 0; // Pack an AudioBuffer into a vector. static void PackRenderAudioBuffer(AudioBuffer* audio, std::vector* packed_buffer); struct Metrics { absl::optional echo_likelihood; absl::optional echo_likelihood_recent_max; }; // Collect current metrics from the echo detector. virtual Metrics GetMetrics() const = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_PROCESSING_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/include/audio_processing_statistics.cc0000664000175000017500000000134114475643423032721 0ustar00arunarun/* * Copyright 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/include/audio_processing_statistics.h" namespace webrtc { AudioProcessingStats::AudioProcessingStats() = default; AudioProcessingStats::AudioProcessingStats(const AudioProcessingStats& other) = default; AudioProcessingStats::~AudioProcessingStats() = default; } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/include/audio_processing_statistics.h0000664000175000017500000000616114475643423032570 0ustar00arunarun/* * Copyright 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_PROCESSING_STATISTICS_H_ #define MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_PROCESSING_STATISTICS_H_ #include #include "absl/types/optional.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { // This version of the stats uses Optionals, it will replace the regular // AudioProcessingStatistics struct. struct RTC_EXPORT AudioProcessingStats { AudioProcessingStats(); AudioProcessingStats(const AudioProcessingStats& other); ~AudioProcessingStats(); // The root mean square (RMS) level in dBFS (decibels from digital // full-scale) of the last capture frame, after processing. It is // constrained to [-127, 0]. // The computation follows: https://tools.ietf.org/html/rfc6465 // with the intent that it can provide the RTP audio level indication. // Only reported if level estimation is enabled in AudioProcessing::Config. absl::optional output_rms_dbfs; // True if voice is detected in the last capture frame, after processing. // It is conservative in flagging audio as speech, with low likelihood of // incorrectly flagging a frame as voice. // Only reported if voice detection is enabled in AudioProcessing::Config. absl::optional voice_detected; // AEC Statistics. // ERL = 10log_10(P_far / P_echo) absl::optional echo_return_loss; // ERLE = 10log_10(P_echo / P_out) absl::optional echo_return_loss_enhancement; // Fraction of time that the AEC linear filter is divergent, in a 1-second // non-overlapped aggregation window. absl::optional divergent_filter_fraction; // The delay metrics consists of the delay median and standard deviation. It // also consists of the fraction of delay estimates that can make the echo // cancellation perform poorly. The values are aggregated until the first // call to |GetStatistics()| and afterwards aggregated and updated every // second. Note that if there are several clients pulling metrics from // |GetStatistics()| during a session the first call from any of them will // change to one second aggregation window for all. absl::optional delay_median_ms; absl::optional delay_standard_deviation_ms; // Residual echo detector likelihood. absl::optional residual_echo_likelihood; // Maximum residual echo likelihood from the last time period. absl::optional residual_echo_likelihood_recent_max; // The instantaneous delay estimate produced in the AEC. The unit is in // milliseconds and the value is the instantaneous value at the time of the // call to |GetStatistics()|. absl::optional delay_ms; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_PROCESSING_STATISTICS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/include/config.cc0000664000175000017500000000122614475643423026361 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/include/config.h" namespace webrtc { Config::Config() {} Config::~Config() { for (OptionMap::iterator it = options_.begin(); it != options_.end(); ++it) { delete it->second; } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/include/config.h0000664000175000017500000000723114475643423026225 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_INCLUDE_CONFIG_H_ #define MODULES_AUDIO_PROCESSING_INCLUDE_CONFIG_H_ #include #include "rtc_base/system/rtc_export.h" namespace webrtc { // Only add new values to the end of the enumeration and never remove (only // deprecate) to maintain binary compatibility. enum class ConfigOptionID { kMyExperimentForTest, kAlgo1CostFunctionForTest, kTemporalLayersFactory, // Deprecated kNetEqCapacityConfig, // Deprecated kNetEqFastAccelerate, // Deprecated kVoicePacing, // Deprecated kExtendedFilter, // Deprecated kDelayAgnostic, // Deprecated kExperimentalAgc, kExperimentalNs, kBeamforming, // Deprecated kIntelligibility, // Deprecated kEchoCanceller3, // Deprecated kAecRefinedAdaptiveFilter, // Deprecated kLevelControl // Deprecated }; // Class Config is designed to ease passing a set of options across webrtc code. // Options are identified by typename in order to avoid incorrect casts. // // Usage: // * declaring an option: // struct Algo1_CostFunction { // virtual float cost(int x) const { return x; } // virtual ~Algo1_CostFunction() {} // }; // // * accessing an option: // config.Get().cost(value); // // * setting an option: // struct SqrCost : Algo1_CostFunction { // virtual float cost(int x) const { return x*x; } // }; // config.Set(new SqrCost()); // // Note: This class is thread-compatible (like STL containers). class RTC_EXPORT Config { public: // Returns the option if set or a default constructed one. // Callers that access options too often are encouraged to cache the result. // Returned references are owned by this. // // Requires std::is_default_constructible template const T& Get() const; // Set the option, deleting any previous instance of the same. // This instance gets ownership of the newly set value. template void Set(T* value); Config(); ~Config(); private: struct BaseOption { virtual ~BaseOption() {} }; template struct Option : BaseOption { explicit Option(T* v) : value(v) {} ~Option() { delete value; } T* value; }; template static ConfigOptionID identifier() { return T::identifier; } // Used to instantiate a default constructed object that doesn't needs to be // owned. This allows Get to be implemented without requiring explicitly // locks. template static const T& default_value() { static const T* const def = new T(); return *def; } typedef std::map OptionMap; OptionMap options_; Config(const Config&); void operator=(const Config&); }; template const T& Config::Get() const { OptionMap::const_iterator it = options_.find(identifier()); if (it != options_.end()) { const T* t = static_cast*>(it->second)->value; if (t) { return *t; } } return default_value(); } template void Config::Set(T* value) { BaseOption*& it = options_[identifier()]; delete it; it = new Option(value); } } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_INCLUDE_CONFIG_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/level_estimator.cc0000664000175000017500000000160714475643423026672 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/level_estimator.h" #include "api/array_view.h" namespace webrtc { LevelEstimator::LevelEstimator() { rms_.Reset(); } LevelEstimator::~LevelEstimator() = default; void LevelEstimator::ProcessStream(const AudioBuffer& audio) { for (size_t i = 0; i < audio.num_channels(); i++) { rms_.Analyze(rtc::ArrayView(audio.channels_const()[i], audio.num_frames())); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/level_estimator.h0000664000175000017500000000321414475643423026530 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_LEVEL_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_LEVEL_ESTIMATOR_H_ #include "modules/audio_processing/audio_buffer.h" #include "modules/audio_processing/rms_level.h" namespace webrtc { // An estimation component used to retrieve level metrics. class LevelEstimator { public: LevelEstimator(); ~LevelEstimator(); LevelEstimator(LevelEstimator&) = delete; LevelEstimator& operator=(LevelEstimator&) = delete; void ProcessStream(const AudioBuffer& audio); // Returns the root mean square (RMS) level in dBFs (decibels from digital // full-scale), or alternately dBov. It is computed over all primary stream // frames since the last call to RMS(). The returned value is positive but // should be interpreted as negative. It is constrained to [0, 127]. // // The computation follows: https://tools.ietf.org/html/rfc6465 // with the intent that it can provide the RTP audio level indication. // // Frames passed to ProcessStream() with an |_energy| of zero are considered // to have been muted. The RMS of the frame will be interpreted as -127. int RMS() { return rms_.Average(); } private: RmsLevel rms_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_LEVEL_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/logging/0000775000175000017500000000000014475643423024607 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/logging/apm_data_dumper.cc0000664000175000017500000000541214475643423030242 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/strings/string_builder.h" // Check to verify that the define is properly set. #if !defined(WEBRTC_APM_DEBUG_DUMP) || \ (WEBRTC_APM_DEBUG_DUMP != 0 && WEBRTC_APM_DEBUG_DUMP != 1) #error "Set WEBRTC_APM_DEBUG_DUMP to either 0 or 1" #endif namespace webrtc { namespace { #if WEBRTC_APM_DEBUG_DUMP == 1 #if defined(WEBRTC_WIN) constexpr char kPathDelimiter = '\\'; #else constexpr char kPathDelimiter = '/'; #endif std::string FormFileName(const char* output_dir, const char* name, int instance_index, int reinit_index, const std::string& suffix) { char buf[1024]; rtc::SimpleStringBuilder ss(buf); const size_t output_dir_size = strlen(output_dir); if (output_dir_size > 0) { ss << output_dir; if (output_dir[output_dir_size - 1] != kPathDelimiter) { ss << kPathDelimiter; } } ss << name << "_" << instance_index << "-" << reinit_index << suffix; return ss.str(); } #endif } // namespace #if WEBRTC_APM_DEBUG_DUMP == 1 ApmDataDumper::ApmDataDumper(int instance_index) : instance_index_(instance_index) {} #else ApmDataDumper::ApmDataDumper(int instance_index) {} #endif ApmDataDumper::~ApmDataDumper() = default; #if WEBRTC_APM_DEBUG_DUMP == 1 bool ApmDataDumper::recording_activated_ = false; char ApmDataDumper::output_dir_[] = ""; FILE* ApmDataDumper::GetRawFile(const char* name) { std::string filename = FormFileName(output_dir_, name, instance_index_, recording_set_index_, ".dat"); auto& f = raw_files_[filename]; if (!f) { f.reset(fopen(filename.c_str(), "wb")); RTC_CHECK(f.get()) << "Cannot write to " << filename << "."; } return f.get(); } WavWriter* ApmDataDumper::GetWavFile(const char* name, int sample_rate_hz, int num_channels, WavFile::SampleFormat format) { std::string filename = FormFileName(output_dir_, name, instance_index_, recording_set_index_, ".wav"); auto& f = wav_files_[filename]; if (!f) { f.reset( new WavWriter(filename.c_str(), sample_rate_hz, num_channels, format)); } return f.get(); } #endif } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/logging/apm_data_dumper.h0000664000175000017500000001700714475643423030107 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_LOGGING_APM_DATA_DUMPER_H_ #define MODULES_AUDIO_PROCESSING_LOGGING_APM_DATA_DUMPER_H_ #include #include #include #include #if WEBRTC_APM_DEBUG_DUMP == 1 #include #include #endif #include "api/array_view.h" #if WEBRTC_APM_DEBUG_DUMP == 1 #include "common_audio/wav_file.h" #include "rtc_base/checks.h" #endif // Check to verify that the define is properly set. #if !defined(WEBRTC_APM_DEBUG_DUMP) || \ (WEBRTC_APM_DEBUG_DUMP != 0 && WEBRTC_APM_DEBUG_DUMP != 1) #error "Set WEBRTC_APM_DEBUG_DUMP to either 0 or 1" #endif namespace webrtc { #if WEBRTC_APM_DEBUG_DUMP == 1 // Functor used to use as a custom deleter in the map of file pointers to raw // files. struct RawFileCloseFunctor { void operator()(FILE* f) const { fclose(f); } }; #endif // Class that handles dumping of variables into files. class ApmDataDumper { public: // Constructor that takes an instance index that may // be used to distinguish data dumped from different // instances of the code. explicit ApmDataDumper(int instance_index); ApmDataDumper() = delete; ApmDataDumper(const ApmDataDumper&) = delete; ApmDataDumper& operator=(const ApmDataDumper&) = delete; ~ApmDataDumper(); // Activates or deactivate the dumping functionality. static void SetActivated(bool activated) { #if WEBRTC_APM_DEBUG_DUMP == 1 recording_activated_ = activated; #endif } // Set an optional output directory. static void SetOutputDirectory(const std::string& output_dir) { #if WEBRTC_APM_DEBUG_DUMP == 1 RTC_CHECK_LT(output_dir.size(), kOutputDirMaxLength); strncpy(output_dir_, output_dir.c_str(), output_dir.size()); #endif } // Reinitializes the data dumping such that new versions // of all files being dumped to are created. void InitiateNewSetOfRecordings() { #if WEBRTC_APM_DEBUG_DUMP == 1 ++recording_set_index_; #endif } // Methods for performing dumping of data of various types into // various formats. void DumpRaw(const char* name, double v) { #if WEBRTC_APM_DEBUG_DUMP == 1 if (recording_activated_) { FILE* file = GetRawFile(name); fwrite(&v, sizeof(v), 1, file); } #endif } void DumpRaw(const char* name, size_t v_length, const double* v) { #if WEBRTC_APM_DEBUG_DUMP == 1 if (recording_activated_) { FILE* file = GetRawFile(name); fwrite(v, sizeof(v[0]), v_length, file); } #endif } void DumpRaw(const char* name, rtc::ArrayView v) { #if WEBRTC_APM_DEBUG_DUMP == 1 if (recording_activated_) { DumpRaw(name, v.size(), v.data()); } #endif } void DumpRaw(const char* name, float v) { #if WEBRTC_APM_DEBUG_DUMP == 1 if (recording_activated_) { FILE* file = GetRawFile(name); fwrite(&v, sizeof(v), 1, file); } #endif } void DumpRaw(const char* name, size_t v_length, const float* v) { #if WEBRTC_APM_DEBUG_DUMP == 1 if (recording_activated_) { FILE* file = GetRawFile(name); fwrite(v, sizeof(v[0]), v_length, file); } #endif } void DumpRaw(const char* name, rtc::ArrayView v) { #if WEBRTC_APM_DEBUG_DUMP == 1 if (recording_activated_) { DumpRaw(name, v.size(), v.data()); } #endif } void DumpRaw(const char* name, bool v) { #if WEBRTC_APM_DEBUG_DUMP == 1 if (recording_activated_) { DumpRaw(name, static_cast(v)); } #endif } void DumpRaw(const char* name, size_t v_length, const bool* v) { #if WEBRTC_APM_DEBUG_DUMP == 1 if (recording_activated_) { FILE* file = GetRawFile(name); for (size_t k = 0; k < v_length; ++k) { int16_t value = static_cast(v[k]); fwrite(&value, sizeof(value), 1, file); } } #endif } void DumpRaw(const char* name, rtc::ArrayView v) { #if WEBRTC_APM_DEBUG_DUMP == 1 if (recording_activated_) { DumpRaw(name, v.size(), v.data()); } #endif } void DumpRaw(const char* name, int16_t v) { #if WEBRTC_APM_DEBUG_DUMP == 1 if (recording_activated_) { FILE* file = GetRawFile(name); fwrite(&v, sizeof(v), 1, file); } #endif } void DumpRaw(const char* name, size_t v_length, const int16_t* v) { #if WEBRTC_APM_DEBUG_DUMP == 1 if (recording_activated_) { FILE* file = GetRawFile(name); fwrite(v, sizeof(v[0]), v_length, file); } #endif } void DumpRaw(const char* name, rtc::ArrayView v) { #if WEBRTC_APM_DEBUG_DUMP == 1 if (recording_activated_) { DumpRaw(name, v.size(), v.data()); } #endif } void DumpRaw(const char* name, int32_t v) { #if WEBRTC_APM_DEBUG_DUMP == 1 if (recording_activated_) { FILE* file = GetRawFile(name); fwrite(&v, sizeof(v), 1, file); } #endif } void DumpRaw(const char* name, size_t v_length, const int32_t* v) { #if WEBRTC_APM_DEBUG_DUMP == 1 if (recording_activated_) { FILE* file = GetRawFile(name); fwrite(v, sizeof(v[0]), v_length, file); } #endif } void DumpRaw(const char* name, size_t v) { #if WEBRTC_APM_DEBUG_DUMP == 1 if (recording_activated_) { FILE* file = GetRawFile(name); fwrite(&v, sizeof(v), 1, file); } #endif } void DumpRaw(const char* name, size_t v_length, const size_t* v) { #if WEBRTC_APM_DEBUG_DUMP == 1 if (recording_activated_) { FILE* file = GetRawFile(name); fwrite(v, sizeof(v[0]), v_length, file); } #endif } void DumpRaw(const char* name, rtc::ArrayView v) { #if WEBRTC_APM_DEBUG_DUMP == 1 if (recording_activated_) { DumpRaw(name, v.size(), v.data()); } #endif } void DumpRaw(const char* name, rtc::ArrayView v) { #if WEBRTC_APM_DEBUG_DUMP == 1 DumpRaw(name, v.size(), v.data()); #endif } void DumpWav(const char* name, size_t v_length, const float* v, int sample_rate_hz, int num_channels) { #if WEBRTC_APM_DEBUG_DUMP == 1 if (recording_activated_) { WavWriter* file = GetWavFile(name, sample_rate_hz, num_channels, WavFile::SampleFormat::kFloat); file->WriteSamples(v, v_length); } #endif } void DumpWav(const char* name, rtc::ArrayView v, int sample_rate_hz, int num_channels) { #if WEBRTC_APM_DEBUG_DUMP == 1 if (recording_activated_) { DumpWav(name, v.size(), v.data(), sample_rate_hz, num_channels); } #endif } private: #if WEBRTC_APM_DEBUG_DUMP == 1 static bool recording_activated_; static constexpr size_t kOutputDirMaxLength = 1024; static char output_dir_[kOutputDirMaxLength]; const int instance_index_; int recording_set_index_ = 0; std::unordered_map> raw_files_; std::unordered_map> wav_files_; FILE* GetRawFile(const char* name); WavWriter* GetWavFile(const char* name, int sample_rate_hz, int num_channels, WavFile::SampleFormat format); #endif }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_LOGGING_APM_DATA_DUMPER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/meson.build0000664000175000017500000001427414475643423025333 0ustar00arunarunapm_flags = ['-DWEBRTC_APM_DEBUG_DUMP=0'] webrtc_audio_processing_sources = [ 'aec_dump/null_aec_dump_factory.cc', 'aec3/adaptive_fir_filter.cc', 'aec3/adaptive_fir_filter_erl.cc', 'aec3/aec3_common.cc', 'aec3/aec3_fft.cc', 'aec3/aec_state.cc', 'aec3/alignment_mixer.cc', 'aec3/api_call_jitter_metrics.cc', 'aec3/block_buffer.cc', 'aec3/block_delay_buffer.cc', 'aec3/block_framer.cc', 'aec3/block_processor.cc', 'aec3/block_processor_metrics.cc', 'aec3/clockdrift_detector.cc', 'aec3/coarse_filter_update_gain.cc', 'aec3/comfort_noise_generator.cc', 'aec3/decimator.cc', 'aec3/dominant_nearend_detector.cc', 'aec3/downsampled_render_buffer.cc', 'aec3/echo_audibility.cc', 'aec3/echo_canceller3.cc', 'aec3/echo_path_delay_estimator.cc', 'aec3/echo_path_variability.cc', 'aec3/echo_remover.cc', 'aec3/echo_remover_metrics.cc', 'aec3/erle_estimator.cc', 'aec3/erl_estimator.cc', 'aec3/fft_buffer.cc', 'aec3/filter_analyzer.cc', 'aec3/frame_blocker.cc', 'aec3/fullband_erle_estimator.cc', 'aec3/matched_filter.cc', 'aec3/matched_filter_lag_aggregator.cc', 'aec3/moving_average.cc', 'aec3/refined_filter_update_gain.cc', 'aec3/render_buffer.cc', 'aec3/render_delay_buffer.cc', 'aec3/render_delay_controller.cc', 'aec3/render_delay_controller_metrics.cc', 'aec3/render_signal_analyzer.cc', 'aec3/residual_echo_estimator.cc', 'aec3/reverb_decay_estimator.cc', 'aec3/reverb_frequency_response.cc', 'aec3/reverb_model.cc', 'aec3/reverb_model_estimator.cc', 'aec3/signal_dependent_erle_estimator.cc', 'aec3/spectrum_buffer.cc', 'aec3/stationarity_estimator.cc', 'aec3/subband_erle_estimator.cc', 'aec3/subband_nearend_detector.cc', 'aec3/subtractor.cc', 'aec3/subtractor_output_analyzer.cc', 'aec3/subtractor_output.cc', 'aec3/suppression_filter.cc', 'aec3/suppression_gain.cc', 'aec3/transparent_mode.cc', 'aecm/aecm_core.cc', 'aecm/aecm_core_c.cc', 'aecm/echo_control_mobile.cc', 'agc/agc.cc', 'agc/agc_manager_direct.cc', 'agc/legacy/analog_agc.cc', 'agc/legacy/digital_agc.cc', 'agc/loudness_histogram.cc', 'agc/utility.cc', 'agc2/adaptive_agc.cc', 'agc2/adaptive_digital_gain_applier.cc', 'agc2/adaptive_mode_level_estimator_agc.cc', 'agc2/adaptive_mode_level_estimator.cc', 'agc2/agc2_testing_common.cc', 'agc2/biquad_filter.cc', 'agc2/compute_interpolated_gain_curve.cc', 'agc2/down_sampler.cc', 'agc2/fixed_digital_level_estimator.cc', 'agc2/gain_applier.cc', 'agc2/interpolated_gain_curve.cc', 'agc2/limiter.cc', 'agc2/limiter_db_gain_curve.cc', 'agc2/noise_level_estimator.cc', 'agc2/noise_spectrum_estimator.cc', 'agc2/rnn_vad/auto_correlation.cc', 'agc2/rnn_vad/common.cc', 'agc2/rnn_vad/features_extraction.cc', 'agc2/rnn_vad/lp_residual.cc', 'agc2/rnn_vad/pitch_search.cc', 'agc2/rnn_vad/pitch_search_internal.cc', 'agc2/rnn_vad/rnn.cc', 'agc2/rnn_vad/spectral_features.cc', 'agc2/rnn_vad/spectral_features_internal.cc', 'agc2/saturation_protector.cc', 'agc2/signal_classifier.cc', 'agc2/vad_with_level.cc', 'agc2/vector_float_frame.cc', 'audio_buffer.cc', 'audio_processing_builder_impl.cc', 'audio_processing_impl.cc', 'echo_control_mobile_impl.cc', 'echo_detector/circular_buffer.cc', 'echo_detector/mean_variance_estimator.cc', 'echo_detector/moving_max.cc', 'echo_detector/normalized_covariance_estimator.cc', 'gain_control_impl.cc', 'gain_controller2.cc', 'high_pass_filter.cc', 'include/aec_dump.cc', 'include/audio_frame_proxies.cc', 'include/audio_processing.cc', 'include/audio_processing_statistics.cc', 'include/config.cc', 'level_estimator.cc', 'logging/apm_data_dumper.cc', 'ns/fast_math.cc', 'ns/histograms.cc', 'ns/noise_estimator.cc', 'ns/noise_suppressor.cc', 'ns/ns_fft.cc', 'ns/prior_signal_model.cc', 'ns/prior_signal_model_estimator.cc', 'ns/quantile_noise_estimator.cc', 'ns/signal_model.cc', 'ns/signal_model_estimator.cc', 'ns/speech_probability_estimator.cc', 'ns/suppression_params.cc', 'ns/wiener_filter.cc', 'optionally_built_submodule_creators.cc', 'residual_echo_detector.cc', 'rms_level.cc', 'splitting_filter.cc', 'three_band_filter_bank.cc', 'transient/file_utils.cc', 'transient/moving_moments.cc', 'transient/transient_detector.cc', 'transient/transient_suppressor_impl.cc', 'transient/wpd_node.cc', 'transient/wpd_tree.cc', 'typing_detection.cc', 'utility/cascaded_biquad_filter.cc', 'utility/delay_estimator.cc', 'utility/delay_estimator_wrapper.cc', 'utility/pffft_wrapper.cc', 'vad/gmm.cc', 'vad/pitch_based_vad.cc', 'vad/pitch_internal.cc', 'vad/pole_zero_filter.cc', 'vad/standalone_vad.cc', 'vad/vad_audio_proc.cc', 'vad/vad_circular_buffer.cc', 'vad/voice_activity_detector.cc', 'voice_detection.cc', ] webrtc_audio_processing_include_headers = [ 'include/audio_processing.h', 'include/audio_processing_statistics.h', 'include/config.h', ] extra_libs = [] if have_x86 extra_libs += [ static_library('webrtc_audio_processing_privatearch', [ 'aec3/adaptive_fir_filter_avx2.cc', 'aec3/adaptive_fir_filter_erl_avx2.cc', 'aec3/fft_data_avx2.cc', 'aec3/matched_filter_avx2.cc', 'aec3/vector_math_avx2.cc', ], dependencies: common_deps, include_directories: webrtc_inc, c_args: common_cflags + apm_flags + ['-mavx2', '-mfma'], cpp_args: common_cxxflags + apm_flags + ['-mavx2', '-mfma'] ) ] endif if have_mips webrtc_audio_processing_sources += [ 'aecm/aecm_core_mips.cc', ] endif if have_neon webrtc_audio_processing_sources += [ 'aecm/aecm_core_neon.cc', ] endif install_headers(webrtc_audio_processing_include_headers, subdir: join_paths(include_subdir, 'modules', 'audio_processing', 'include') ) libwebrtc_audio_processing = library(apm_project_name, webrtc_audio_processing_sources, dependencies: [ base_dep, api_dep, isac_vad_dep, system_wrappers_dep, common_audio_dep, pffft_dep, rnnoise_dep, ] + common_deps, link_with: extra_libs, include_directories: webrtc_inc, c_args: common_cflags + apm_flags, cpp_args: common_cxxflags + apm_flags, soversion: apm_minor_version, install: true ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/0000775000175000017500000000000014475643423023601 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/BUILD.gn0000664000175000017500000000554214475643423024774 0ustar00arunarun# Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../../../webrtc.gni") rtc_static_library("ns") { visibility = [ "*" ] configs += [ "..:apm_debug_dump" ] sources = [ "fast_math.cc", "fast_math.h", "histograms.cc", "histograms.h", "noise_estimator.cc", "noise_estimator.h", "noise_suppressor.cc", "noise_suppressor.h", "ns_common.h", "ns_config.h", "ns_fft.cc", "ns_fft.h", "prior_signal_model.cc", "prior_signal_model.h", "prior_signal_model_estimator.cc", "prior_signal_model_estimator.h", "quantile_noise_estimator.cc", "quantile_noise_estimator.h", "signal_model.cc", "signal_model.h", "signal_model_estimator.cc", "signal_model_estimator.h", "speech_probability_estimator.cc", "speech_probability_estimator.h", "suppression_params.cc", "suppression_params.h", "wiener_filter.cc", "wiener_filter.h", ] defines = [] if (rtc_build_with_neon && current_cpu != "arm64") { suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ] cflags = [ "-mfpu=neon" ] } deps = [ "..:apm_logging", "..:audio_buffer", "..:high_pass_filter", "../../../api:array_view", "../../../common_audio:common_audio_c", "../../../common_audio/third_party/ooura:fft_size_128", "../../../common_audio/third_party/ooura:fft_size_256", "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", "../../../rtc_base:safe_minmax", "../../../rtc_base/system:arch", "../../../system_wrappers", "../../../system_wrappers:field_trial", "../../../system_wrappers:metrics", "../utility:cascaded_biquad_filter", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } if (rtc_include_tests) { rtc_source_set("ns_unittests") { testonly = true configs += [ "..:apm_debug_dump" ] sources = [ "noise_suppressor_unittest.cc" ] deps = [ ":ns", "..:apm_logging", "..:audio_buffer", "..:audio_processing", "..:audio_processing_unittests", "..:high_pass_filter", "../../../api:array_view", "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", "../../../rtc_base:safe_minmax", "../../../rtc_base/system:arch", "../../../system_wrappers", "../../../test:test_support", "../utility:cascaded_biquad_filter", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] defines = [] if (rtc_enable_protobuf) { sources += [] } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/fast_math.cc0000664000175000017500000000432014475643423026055 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/ns/fast_math.h" #include #include #include "rtc_base/checks.h" namespace webrtc { namespace { float FastLog2f(float in) { RTC_DCHECK_GT(in, .0f); // Read and interpret float as uint32_t and then cast to float. // This is done to extract the exponent (bits 30 - 23). // "Right shift" of the exponent is then performed by multiplying // with the constant (1/2^23). Finally, we subtract a constant to // remove the bias (https://en.wikipedia.org/wiki/Exponent_bias). union { float dummy; uint32_t a; } x = {in}; float out = x.a; out *= 1.1920929e-7f; // 1/2^23 out -= 126.942695f; // Remove bias. return out; } } // namespace float SqrtFastApproximation(float f) { // TODO(peah): Add fast approximate implementation. return sqrtf(f); } float Pow2Approximation(float p) { // TODO(peah): Add fast approximate implementation. return powf(2.f, p); } float PowApproximation(float x, float p) { return Pow2Approximation(p * FastLog2f(x)); } float LogApproximation(float x) { constexpr float kLogOf2 = 0.69314718056f; return FastLog2f(x) * kLogOf2; } void LogApproximation(rtc::ArrayView x, rtc::ArrayView y) { for (size_t k = 0; k < x.size(); ++k) { y[k] = LogApproximation(x[k]); } } float ExpApproximation(float x) { constexpr float kLog10Ofe = 0.4342944819f; return PowApproximation(10.f, x * kLog10Ofe); } void ExpApproximation(rtc::ArrayView x, rtc::ArrayView y) { for (size_t k = 0; k < x.size(); ++k) { y[k] = ExpApproximation(x[k]); } } void ExpApproximationSignFlip(rtc::ArrayView x, rtc::ArrayView y) { for (size_t k = 0; k < x.size(); ++k) { y[k] = ExpApproximation(-x[k]); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/fast_math.h0000664000175000017500000000232314475643423025720 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_NS_FAST_MATH_H_ #define MODULES_AUDIO_PROCESSING_NS_FAST_MATH_H_ #include "api/array_view.h" namespace webrtc { // Sqrt approximation. float SqrtFastApproximation(float f); // Log base conversion log(x) = log2(x)/log2(e). float LogApproximation(float x); void LogApproximation(rtc::ArrayView x, rtc::ArrayView y); // 2^x approximation. float Pow2Approximation(float p); // x^p approximation. float PowApproximation(float x, float p); // e^x approximation. float ExpApproximation(float x); void ExpApproximation(rtc::ArrayView x, rtc::ArrayView y); void ExpApproximationSignFlip(rtc::ArrayView x, rtc::ArrayView y); } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_NS_FAST_MATH_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/histograms.cc0000664000175000017500000000302114475643423026264 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/ns/histograms.h" namespace webrtc { Histograms::Histograms() { Clear(); } void Histograms::Clear() { lrt_.fill(0); spectral_flatness_.fill(0); spectral_diff_.fill(0); } void Histograms::Update(const SignalModel& features_) { // Update the histogram for the LRT. constexpr float kOneByBinSizeLrt = 1.f / kBinSizeLrt; if (features_.lrt < kHistogramSize * kBinSizeLrt && features_.lrt >= 0.f) { ++lrt_[kOneByBinSizeLrt * features_.lrt]; } // Update histogram for the spectral flatness. constexpr float kOneByBinSizeSpecFlat = 1.f / kBinSizeSpecFlat; if (features_.spectral_flatness < kHistogramSize * kBinSizeSpecFlat && features_.spectral_flatness >= 0.f) { ++spectral_flatness_[features_.spectral_flatness * kOneByBinSizeSpecFlat]; } // Update histogram for the spectral difference. constexpr float kOneByBinSizeSpecDiff = 1.f / kBinSizeSpecDiff; if (features_.spectral_diff < kHistogramSize * kBinSizeSpecDiff && features_.spectral_diff >= 0.f) { ++spectral_diff_[features_.spectral_diff * kOneByBinSizeSpecDiff]; } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/histograms.h0000664000175000017500000000320614475643423026133 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_NS_HISTOGRAMS_H_ #define MODULES_AUDIO_PROCESSING_NS_HISTOGRAMS_H_ #include #include "api/array_view.h" #include "modules/audio_processing/ns/ns_common.h" #include "modules/audio_processing/ns/signal_model.h" namespace webrtc { constexpr int kHistogramSize = 1000; // Class for handling the updating of histograms. class Histograms { public: Histograms(); Histograms(const Histograms&) = delete; Histograms& operator=(const Histograms&) = delete; // Clears the histograms. void Clear(); // Extracts thresholds for feature parameters and updates the corresponding // histogram. void Update(const SignalModel& features_); // Methods for accessing the histograms. rtc::ArrayView get_lrt() const { return lrt_; } rtc::ArrayView get_spectral_flatness() const { return spectral_flatness_; } rtc::ArrayView get_spectral_diff() const { return spectral_diff_; } private: std::array lrt_; std::array spectral_flatness_; std::array spectral_diff_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_NS_HISTOGRAMS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/noise_estimator.cc0000664000175000017500000001743514475643423027326 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/ns/noise_estimator.h" #include #include "modules/audio_processing/ns/fast_math.h" #include "rtc_base/checks.h" namespace webrtc { namespace { // Log(i). constexpr std::array log_table = { 0.f, 0.f, 0.f, 0.f, 0.f, 1.609438f, 1.791759f, 1.945910f, 2.079442f, 2.197225f, 2.302585f, 2.397895f, 2.484907f, 2.564949f, 2.639057f, 2.708050f, 2.772589f, 2.833213f, 2.890372f, 2.944439f, 2.995732f, 3.044522f, 3.091043f, 3.135494f, 3.178054f, 3.218876f, 3.258097f, 3.295837f, 3.332205f, 3.367296f, 3.401197f, 3.433987f, 3.465736f, 3.496507f, 3.526361f, 3.555348f, 3.583519f, 3.610918f, 3.637586f, 3.663562f, 3.688879f, 3.713572f, 3.737669f, 3.761200f, 3.784190f, 3.806663f, 3.828641f, 3.850147f, 3.871201f, 3.891820f, 3.912023f, 3.931826f, 3.951244f, 3.970292f, 3.988984f, 4.007333f, 4.025352f, 4.043051f, 4.060443f, 4.077538f, 4.094345f, 4.110874f, 4.127134f, 4.143135f, 4.158883f, 4.174387f, 4.189655f, 4.204693f, 4.219508f, 4.234107f, 4.248495f, 4.262680f, 4.276666f, 4.290460f, 4.304065f, 4.317488f, 4.330733f, 4.343805f, 4.356709f, 4.369448f, 4.382027f, 4.394449f, 4.406719f, 4.418841f, 4.430817f, 4.442651f, 4.454347f, 4.465908f, 4.477337f, 4.488636f, 4.499810f, 4.510859f, 4.521789f, 4.532599f, 4.543295f, 4.553877f, 4.564348f, 4.574711f, 4.584968f, 4.595119f, 4.605170f, 4.615121f, 4.624973f, 4.634729f, 4.644391f, 4.653960f, 4.663439f, 4.672829f, 4.682131f, 4.691348f, 4.700480f, 4.709530f, 4.718499f, 4.727388f, 4.736198f, 4.744932f, 4.753591f, 4.762174f, 4.770685f, 4.779124f, 4.787492f, 4.795791f, 4.804021f, 4.812184f, 4.820282f, 4.828314f, 4.836282f, 4.844187f, 4.852030f}; } // namespace NoiseEstimator::NoiseEstimator(const SuppressionParams& suppression_params) : suppression_params_(suppression_params) { noise_spectrum_.fill(0.f); prev_noise_spectrum_.fill(0.f); conservative_noise_spectrum_.fill(0.f); parametric_noise_spectrum_.fill(0.f); } void NoiseEstimator::PrepareAnalysis() { std::copy(noise_spectrum_.begin(), noise_spectrum_.end(), prev_noise_spectrum_.begin()); } void NoiseEstimator::PreUpdate( int32_t num_analyzed_frames, rtc::ArrayView signal_spectrum, float signal_spectral_sum) { quantile_noise_estimator_.Estimate(signal_spectrum, noise_spectrum_); if (num_analyzed_frames < kShortStartupPhaseBlocks) { // Compute simplified noise model during startup. const size_t kStartBand = 5; float sum_log_i_log_magn = 0.f; float sum_log_i = 0.f; float sum_log_i_square = 0.f; float sum_log_magn = 0.f; for (size_t i = kStartBand; i < kFftSizeBy2Plus1; ++i) { float log_i = log_table[i]; sum_log_i += log_i; sum_log_i_square += log_i * log_i; float log_signal = LogApproximation(signal_spectrum[i]); sum_log_magn += log_signal; sum_log_i_log_magn += log_i * log_signal; } // Estimate the parameter for the level of the white noise. constexpr float kOneByFftSizeBy2Plus1 = 1.f / kFftSizeBy2Plus1; white_noise_level_ += signal_spectral_sum * kOneByFftSizeBy2Plus1 * suppression_params_.over_subtraction_factor; // Estimate pink noise parameters. float denom = sum_log_i_square * (kFftSizeBy2Plus1 - kStartBand) - sum_log_i * sum_log_i; float num = sum_log_i_square * sum_log_magn - sum_log_i * sum_log_i_log_magn; RTC_DCHECK_NE(denom, 0.f); float pink_noise_adjustment = num / denom; // Constrain the estimated spectrum to be positive. pink_noise_adjustment = std::max(pink_noise_adjustment, 0.f); pink_noise_numerator_ += pink_noise_adjustment; num = sum_log_i * sum_log_magn - (kFftSizeBy2Plus1 - kStartBand) * sum_log_i_log_magn; RTC_DCHECK_NE(denom, 0.f); pink_noise_adjustment = num / denom; // Constrain the pink noise power to be in the interval [0, 1]. pink_noise_adjustment = std::max(std::min(pink_noise_adjustment, 1.f), 0.f); pink_noise_exp_ += pink_noise_adjustment; const float one_by_num_analyzed_frames_plus_1 = 1.f / (num_analyzed_frames + 1.f); // Calculate the frequency-independent parts of parametric noise estimate. float parametric_exp = 0.f; float parametric_num = 0.f; if (pink_noise_exp_ > 0.f) { // Use pink noise estimate. parametric_num = ExpApproximation(pink_noise_numerator_ * one_by_num_analyzed_frames_plus_1); parametric_num *= num_analyzed_frames + 1.f; parametric_exp = pink_noise_exp_ * one_by_num_analyzed_frames_plus_1; } constexpr float kOneByShortStartupPhaseBlocks = 1.f / kShortStartupPhaseBlocks; for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) { // Estimate the background noise using the white and pink noise // parameters. if (pink_noise_exp_ == 0.f) { // Use white noise estimate. parametric_noise_spectrum_[i] = white_noise_level_; } else { // Use pink noise estimate. float use_band = i < kStartBand ? kStartBand : i; float denom = PowApproximation(use_band, parametric_exp); RTC_DCHECK_NE(denom, 0.f); parametric_noise_spectrum_[i] = parametric_num / denom; } } // Weight quantile noise with modeled noise. for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) { noise_spectrum_[i] *= num_analyzed_frames; float tmp = parametric_noise_spectrum_[i] * (kShortStartupPhaseBlocks - num_analyzed_frames); noise_spectrum_[i] += tmp * one_by_num_analyzed_frames_plus_1; noise_spectrum_[i] *= kOneByShortStartupPhaseBlocks; } } } void NoiseEstimator::PostUpdate( rtc::ArrayView speech_probability, rtc::ArrayView signal_spectrum) { // Time-avg parameter for noise_spectrum update. constexpr float kNoiseUpdate = 0.9f; float gamma = kNoiseUpdate; for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) { const float prob_speech = speech_probability[i]; const float prob_non_speech = 1.f - prob_speech; // Temporary noise update used for speech frames if update value is less // than previous. float noise_update_tmp = gamma * prev_noise_spectrum_[i] + (1.f - gamma) * (prob_non_speech * signal_spectrum[i] + prob_speech * prev_noise_spectrum_[i]); // Time-constant based on speech/noise_spectrum state. float gamma_old = gamma; // Increase gamma for frame likely to be seech. constexpr float kProbRange = .2f; gamma = prob_speech > kProbRange ? .99f : kNoiseUpdate; // Conservative noise_spectrum update. if (prob_speech < kProbRange) { conservative_noise_spectrum_[i] += 0.05f * (signal_spectrum[i] - conservative_noise_spectrum_[i]); } // Noise_spectrum update. if (gamma == gamma_old) { noise_spectrum_[i] = noise_update_tmp; } else { noise_spectrum_[i] = gamma * prev_noise_spectrum_[i] + (1.f - gamma) * (prob_non_speech * signal_spectrum[i] + prob_speech * prev_noise_spectrum_[i]); // Allow for noise_spectrum update downwards: If noise_spectrum update // decreases the noise_spectrum, it is safe, so allow it to happen. noise_spectrum_[i] = std::min(noise_spectrum_[i], noise_update_tmp); } } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/noise_estimator.h0000664000175000017500000000521714475643423027163 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_NS_NOISE_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_NS_NOISE_ESTIMATOR_H_ #include #include "api/array_view.h" #include "modules/audio_processing/ns/ns_common.h" #include "modules/audio_processing/ns/quantile_noise_estimator.h" #include "modules/audio_processing/ns/suppression_params.h" namespace webrtc { // Class for estimating the spectral characteristics of the noise in an incoming // signal. class NoiseEstimator { public: explicit NoiseEstimator(const SuppressionParams& suppression_params); // Prepare the estimator for analysis of a new frame. void PrepareAnalysis(); // Performs the first step of the estimator update. void PreUpdate(int32_t num_analyzed_frames, rtc::ArrayView signal_spectrum, float signal_spectral_sum); // Performs the second step of the estimator update. void PostUpdate( rtc::ArrayView speech_probability, rtc::ArrayView signal_spectrum); // Returns the noise spectral estimate. rtc::ArrayView get_noise_spectrum() const { return noise_spectrum_; } // Returns the noise from the previous frame. rtc::ArrayView get_prev_noise_spectrum() const { return prev_noise_spectrum_; } // Returns a noise spectral estimate based on white and pink noise parameters. rtc::ArrayView get_parametric_noise_spectrum() const { return parametric_noise_spectrum_; } rtc::ArrayView get_conservative_noise_spectrum() const { return conservative_noise_spectrum_; } private: const SuppressionParams& suppression_params_; float white_noise_level_ = 0.f; float pink_noise_numerator_ = 0.f; float pink_noise_exp_ = 0.f; std::array prev_noise_spectrum_; std::array conservative_noise_spectrum_; std::array parametric_noise_spectrum_; std::array noise_spectrum_; QuantileNoiseEstimator quantile_noise_estimator_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_NS_NOISE_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/noise_suppressor.cc0000664000175000017500000005314414475643423027541 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/ns/noise_suppressor.h" #include #include #include #include #include "modules/audio_processing/ns/fast_math.h" #include "rtc_base/checks.h" namespace webrtc { namespace { // Maps sample rate to number of bands. size_t NumBandsForRate(size_t sample_rate_hz) { RTC_DCHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000 || sample_rate_hz == 48000); return sample_rate_hz / 16000; } // Maximum number of channels for which the channel data is stored on // the stack. If the number of channels are larger than this, they are stored // using scratch memory that is pre-allocated on the heap. The reason for this // partitioning is not to waste heap space for handling the more common numbers // of channels, while at the same time not limiting the support for higher // numbers of channels by enforcing the channel data to be stored on the // stack using a fixed maximum value. constexpr size_t kMaxNumChannelsOnStack = 2; // Chooses the number of channels to store on the heap when that is required due // to the number of channels being larger than the pre-defined number // of channels to store on the stack. size_t NumChannelsOnHeap(size_t num_channels) { return num_channels > kMaxNumChannelsOnStack ? num_channels : 0; } // Hybrib Hanning and flat window for the filterbank. constexpr std::array kBlocks160w256FirstHalf = { 0.00000000f, 0.01636173f, 0.03271908f, 0.04906767f, 0.06540313f, 0.08172107f, 0.09801714f, 0.11428696f, 0.13052619f, 0.14673047f, 0.16289547f, 0.17901686f, 0.19509032f, 0.21111155f, 0.22707626f, 0.24298018f, 0.25881905f, 0.27458862f, 0.29028468f, 0.30590302f, 0.32143947f, 0.33688985f, 0.35225005f, 0.36751594f, 0.38268343f, 0.39774847f, 0.41270703f, 0.42755509f, 0.44228869f, 0.45690388f, 0.47139674f, 0.48576339f, 0.50000000f, 0.51410274f, 0.52806785f, 0.54189158f, 0.55557023f, 0.56910015f, 0.58247770f, 0.59569930f, 0.60876143f, 0.62166057f, 0.63439328f, 0.64695615f, 0.65934582f, 0.67155895f, 0.68359230f, 0.69544264f, 0.70710678f, 0.71858162f, 0.72986407f, 0.74095113f, 0.75183981f, 0.76252720f, 0.77301045f, 0.78328675f, 0.79335334f, 0.80320753f, 0.81284668f, 0.82226822f, 0.83146961f, 0.84044840f, 0.84920218f, 0.85772861f, 0.86602540f, 0.87409034f, 0.88192126f, 0.88951608f, 0.89687274f, 0.90398929f, 0.91086382f, 0.91749450f, 0.92387953f, 0.93001722f, 0.93590593f, 0.94154407f, 0.94693013f, 0.95206268f, 0.95694034f, 0.96156180f, 0.96592583f, 0.97003125f, 0.97387698f, 0.97746197f, 0.98078528f, 0.98384601f, 0.98664333f, 0.98917651f, 0.99144486f, 0.99344778f, 0.99518473f, 0.99665524f, 0.99785892f, 0.99879546f, 0.99946459f, 0.99986614f}; // Applies the filterbank window to a buffer. void ApplyFilterBankWindow(rtc::ArrayView x) { for (size_t i = 0; i < 96; ++i) { x[i] = kBlocks160w256FirstHalf[i] * x[i]; } for (size_t i = 161, k = 95; i < kFftSize; ++i, --k) { RTC_DCHECK_NE(0, k); x[i] = kBlocks160w256FirstHalf[k] * x[i]; } } // Extends a frame with previous data. void FormExtendedFrame(rtc::ArrayView frame, rtc::ArrayView old_data, rtc::ArrayView extended_frame) { std::copy(old_data.begin(), old_data.end(), extended_frame.begin()); std::copy(frame.begin(), frame.end(), extended_frame.begin() + old_data.size()); std::copy(extended_frame.end() - old_data.size(), extended_frame.end(), old_data.begin()); } // Uses overlap-and-add to produce an output frame. void OverlapAndAdd(rtc::ArrayView extended_frame, rtc::ArrayView overlap_memory, rtc::ArrayView output_frame) { for (size_t i = 0; i < kOverlapSize; ++i) { output_frame[i] = overlap_memory[i] + extended_frame[i]; } std::copy(extended_frame.begin() + kOverlapSize, extended_frame.begin() + kNsFrameSize, output_frame.begin() + kOverlapSize); std::copy(extended_frame.begin() + kNsFrameSize, extended_frame.end(), overlap_memory.begin()); } // Produces a delayed frame. void DelaySignal(rtc::ArrayView frame, rtc::ArrayView delay_buffer, rtc::ArrayView delayed_frame) { constexpr size_t kSamplesFromFrame = kNsFrameSize - (kFftSize - kNsFrameSize); std::copy(delay_buffer.begin(), delay_buffer.end(), delayed_frame.begin()); std::copy(frame.begin(), frame.begin() + kSamplesFromFrame, delayed_frame.begin() + delay_buffer.size()); std::copy(frame.begin() + kSamplesFromFrame, frame.end(), delay_buffer.begin()); } // Computes the energy of an extended frame. float ComputeEnergyOfExtendedFrame(rtc::ArrayView x) { float energy = 0.f; for (float x_k : x) { energy += x_k * x_k; } return energy; } // Computes the energy of an extended frame based on its subcomponents. float ComputeEnergyOfExtendedFrame( rtc::ArrayView frame, rtc::ArrayView old_data) { float energy = 0.f; for (float v : old_data) { energy += v * v; } for (float v : frame) { energy += v * v; } return energy; } // Computes the magnitude spectrum based on an FFT output. void ComputeMagnitudeSpectrum( rtc::ArrayView real, rtc::ArrayView imag, rtc::ArrayView signal_spectrum) { signal_spectrum[0] = fabsf(real[0]) + 1.f; signal_spectrum[kFftSizeBy2Plus1 - 1] = fabsf(real[kFftSizeBy2Plus1 - 1]) + 1.f; for (size_t i = 1; i < kFftSizeBy2Plus1 - 1; ++i) { signal_spectrum[i] = SqrtFastApproximation(real[i] * real[i] + imag[i] * imag[i]) + 1.f; } } // Compute prior and post SNR. void ComputeSnr(rtc::ArrayView filter, rtc::ArrayView prev_signal_spectrum, rtc::ArrayView signal_spectrum, rtc::ArrayView prev_noise_spectrum, rtc::ArrayView noise_spectrum, rtc::ArrayView prior_snr, rtc::ArrayView post_snr) { for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) { // Previous post SNR. // Previous estimate: based on previous frame with gain filter. float prev_estimate = prev_signal_spectrum[i] / (prev_noise_spectrum[i] + 0.0001f) * filter[i]; // Post SNR. if (signal_spectrum[i] > noise_spectrum[i]) { post_snr[i] = signal_spectrum[i] / (noise_spectrum[i] + 0.0001f) - 1.f; } else { post_snr[i] = 0.f; } // The directed decision estimate of the prior SNR is a sum the current and // previous estimates. prior_snr[i] = 0.98f * prev_estimate + (1.f - 0.98f) * post_snr[i]; } } // Computes the attenuating gain for the noise suppression of the upper bands. float ComputeUpperBandsGain( float minimum_attenuating_gain, rtc::ArrayView filter, rtc::ArrayView speech_probability, rtc::ArrayView prev_analysis_signal_spectrum, rtc::ArrayView signal_spectrum) { // Average speech prob and filter gain for the end of the lowest band. constexpr int kNumAvgBins = 32; constexpr float kOneByNumAvgBins = 1.f / kNumAvgBins; float avg_prob_speech = 0.f; float avg_filter_gain = 0.f; for (size_t i = kFftSizeBy2Plus1 - kNumAvgBins - 1; i < kFftSizeBy2Plus1 - 1; i++) { avg_prob_speech += speech_probability[i]; avg_filter_gain += filter[i]; } avg_prob_speech = avg_prob_speech * kOneByNumAvgBins; avg_filter_gain = avg_filter_gain * kOneByNumAvgBins; // If the speech was suppressed by a component between Analyze and Process, an // example being by an AEC, it should not be considered speech for the purpose // of high band suppression. To that end, the speech probability is scaled // accordingly. float sum_analysis_spectrum = 0.f; float sum_processing_spectrum = 0.f; for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) { sum_analysis_spectrum += prev_analysis_signal_spectrum[i]; sum_processing_spectrum += signal_spectrum[i]; } // The magnitude spectrum computation enforces the spectrum to be strictly // positive. RTC_DCHECK_GT(sum_analysis_spectrum, 0.f); avg_prob_speech *= sum_processing_spectrum / sum_analysis_spectrum; // Compute gain based on speech probability. float gain = 0.5f * (1.f + static_cast(tanh(2.f * avg_prob_speech - 1.f))); // Combine gain with low band gain. if (avg_prob_speech >= 0.5f) { gain = 0.25f * gain + 0.75f * avg_filter_gain; } else { gain = 0.5f * gain + 0.5f * avg_filter_gain; } // Make sure gain is within flooring range. return std::min(std::max(gain, minimum_attenuating_gain), 1.f); } } // namespace NoiseSuppressor::ChannelState::ChannelState( const SuppressionParams& suppression_params, size_t num_bands) : wiener_filter(suppression_params), noise_estimator(suppression_params), process_delay_memory(num_bands > 1 ? num_bands - 1 : 0) { analyze_analysis_memory.fill(0.f); prev_analysis_signal_spectrum.fill(1.f); process_analysis_memory.fill(0.f); process_synthesis_memory.fill(0.f); for (auto& d : process_delay_memory) { d.fill(0.f); } } NoiseSuppressor::NoiseSuppressor(const NsConfig& config, size_t sample_rate_hz, size_t num_channels) : num_bands_(NumBandsForRate(sample_rate_hz)), num_channels_(num_channels), suppression_params_(config.target_level), filter_bank_states_heap_(NumChannelsOnHeap(num_channels_)), upper_band_gains_heap_(NumChannelsOnHeap(num_channels_)), energies_before_filtering_heap_(NumChannelsOnHeap(num_channels_)), gain_adjustments_heap_(NumChannelsOnHeap(num_channels_)), channels_(num_channels_) { for (size_t ch = 0; ch < num_channels_; ++ch) { channels_[ch] = std::make_unique(suppression_params_, num_bands_); } } void NoiseSuppressor::AggregateWienerFilters( rtc::ArrayView filter) const { rtc::ArrayView filter0 = channels_[0]->wiener_filter.get_filter(); std::copy(filter0.begin(), filter0.end(), filter.begin()); for (size_t ch = 1; ch < num_channels_; ++ch) { rtc::ArrayView filter_ch = channels_[ch]->wiener_filter.get_filter(); for (size_t k = 0; k < kFftSizeBy2Plus1; ++k) { filter[k] = std::min(filter[k], filter_ch[k]); } } } void NoiseSuppressor::Analyze(const AudioBuffer& audio) { // Prepare the noise estimator for the analysis stage. for (size_t ch = 0; ch < num_channels_; ++ch) { channels_[ch]->noise_estimator.PrepareAnalysis(); } // Check for zero frames. bool zero_frame = true; for (size_t ch = 0; ch < num_channels_; ++ch) { rtc::ArrayView y_band0( &audio.split_bands_const(ch)[0][0], kNsFrameSize); float energy = ComputeEnergyOfExtendedFrame( y_band0, channels_[ch]->analyze_analysis_memory); if (energy > 0.f) { zero_frame = false; break; } } if (zero_frame) { // We want to avoid updating statistics in this case: // Updating feature statistics when we have zeros only will cause // thresholds to move towards zero signal situations. This in turn has the // effect that once the signal is "turned on" (non-zero values) everything // will be treated as speech and there is no noise suppression effect. // Depending on the duration of the inactive signal it takes a // considerable amount of time for the system to learn what is noise and // what is speech. return; } // Only update analysis counter for frames that are properly analyzed. if (++num_analyzed_frames_ < 0) { num_analyzed_frames_ = 0; } // Analyze all channels. for (size_t ch = 0; ch < num_channels_; ++ch) { std::unique_ptr& ch_p = channels_[ch]; rtc::ArrayView y_band0( &audio.split_bands_const(ch)[0][0], kNsFrameSize); // Form an extended frame and apply analysis filter bank windowing. std::array extended_frame; FormExtendedFrame(y_band0, ch_p->analyze_analysis_memory, extended_frame); ApplyFilterBankWindow(extended_frame); // Compute the magnitude spectrum. std::array real; std::array imag; fft_.Fft(extended_frame, real, imag); std::array signal_spectrum; ComputeMagnitudeSpectrum(real, imag, signal_spectrum); // Compute energies. float signal_energy = 0.f; for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) { signal_energy += real[i] * real[i] + imag[i] * imag[i]; } signal_energy /= kFftSizeBy2Plus1; float signal_spectral_sum = 0.f; for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) { signal_spectral_sum += signal_spectrum[i]; } // Estimate the noise spectra and the probability estimates of speech // presence. ch_p->noise_estimator.PreUpdate(num_analyzed_frames_, signal_spectrum, signal_spectral_sum); std::array post_snr; std::array prior_snr; ComputeSnr(ch_p->wiener_filter.get_filter(), ch_p->prev_analysis_signal_spectrum, signal_spectrum, ch_p->noise_estimator.get_prev_noise_spectrum(), ch_p->noise_estimator.get_noise_spectrum(), prior_snr, post_snr); ch_p->speech_probability_estimator.Update( num_analyzed_frames_, prior_snr, post_snr, ch_p->noise_estimator.get_conservative_noise_spectrum(), signal_spectrum, signal_spectral_sum, signal_energy); ch_p->noise_estimator.PostUpdate( ch_p->speech_probability_estimator.get_probability(), signal_spectrum); // Store the magnitude spectrum to make it avalilable for the process // method. std::copy(signal_spectrum.begin(), signal_spectrum.end(), ch_p->prev_analysis_signal_spectrum.begin()); } } void NoiseSuppressor::Process(AudioBuffer* audio) { // Select the space for storing data during the processing. std::array filter_bank_states_stack; rtc::ArrayView filter_bank_states( filter_bank_states_stack.data(), num_channels_); std::array upper_band_gains_stack; rtc::ArrayView upper_band_gains(upper_band_gains_stack.data(), num_channels_); std::array energies_before_filtering_stack; rtc::ArrayView energies_before_filtering( energies_before_filtering_stack.data(), num_channels_); std::array gain_adjustments_stack; rtc::ArrayView gain_adjustments(gain_adjustments_stack.data(), num_channels_); if (NumChannelsOnHeap(num_channels_) > 0) { // If the stack-allocated space is too small, use the heap for storing the // data. filter_bank_states = rtc::ArrayView( filter_bank_states_heap_.data(), num_channels_); upper_band_gains = rtc::ArrayView(upper_band_gains_heap_.data(), num_channels_); energies_before_filtering = rtc::ArrayView( energies_before_filtering_heap_.data(), num_channels_); gain_adjustments = rtc::ArrayView(gain_adjustments_heap_.data(), num_channels_); } // Compute the suppression filters for all channels. for (size_t ch = 0; ch < num_channels_; ++ch) { // Form an extended frame and apply analysis filter bank windowing. rtc::ArrayView y_band0(&audio->split_bands(ch)[0][0], kNsFrameSize); FormExtendedFrame(y_band0, channels_[ch]->process_analysis_memory, filter_bank_states[ch].extended_frame); ApplyFilterBankWindow(filter_bank_states[ch].extended_frame); energies_before_filtering[ch] = ComputeEnergyOfExtendedFrame(filter_bank_states[ch].extended_frame); // Perform filter bank analysis and compute the magnitude spectrum. fft_.Fft(filter_bank_states[ch].extended_frame, filter_bank_states[ch].real, filter_bank_states[ch].imag); std::array signal_spectrum; ComputeMagnitudeSpectrum(filter_bank_states[ch].real, filter_bank_states[ch].imag, signal_spectrum); // Compute the frequency domain gain filter for noise attenuation. channels_[ch]->wiener_filter.Update( num_analyzed_frames_, channels_[ch]->noise_estimator.get_noise_spectrum(), channels_[ch]->noise_estimator.get_prev_noise_spectrum(), channels_[ch]->noise_estimator.get_parametric_noise_spectrum(), signal_spectrum); if (num_bands_ > 1) { // Compute the time-domain gain for attenuating the noise in the upper // bands. upper_band_gains[ch] = ComputeUpperBandsGain( suppression_params_.minimum_attenuating_gain, channels_[ch]->wiener_filter.get_filter(), channels_[ch]->speech_probability_estimator.get_probability(), channels_[ch]->prev_analysis_signal_spectrum, signal_spectrum); } } // Aggregate the Wiener filters for all channels. std::array filter_data; rtc::ArrayView filter = filter_data; if (num_channels_ == 1) { filter = channels_[0]->wiener_filter.get_filter(); } else { AggregateWienerFilters(filter_data); } for (size_t ch = 0; ch < num_channels_; ++ch) { // Apply the filter to the lower band. for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) { filter_bank_states[ch].real[i] *= filter[i]; filter_bank_states[ch].imag[i] *= filter[i]; } } // Perform filter bank synthesis for (size_t ch = 0; ch < num_channels_; ++ch) { fft_.Ifft(filter_bank_states[ch].real, filter_bank_states[ch].imag, filter_bank_states[ch].extended_frame); } for (size_t ch = 0; ch < num_channels_; ++ch) { const float energy_after_filtering = ComputeEnergyOfExtendedFrame(filter_bank_states[ch].extended_frame); // Apply synthesis window. ApplyFilterBankWindow(filter_bank_states[ch].extended_frame); // Compute the adjustment of the noise attenuation filter based on the // effect of the attenuation. gain_adjustments[ch] = channels_[ch]->wiener_filter.ComputeOverallScalingFactor( num_analyzed_frames_, channels_[ch]->speech_probability_estimator.get_prior_probability(), energies_before_filtering[ch], energy_after_filtering); } // Select and apply adjustment of the noise attenuation filter based on the // effect of the attenuation. float gain_adjustment = gain_adjustments[0]; for (size_t ch = 1; ch < num_channels_; ++ch) { gain_adjustment = std::min(gain_adjustment, gain_adjustments[ch]); } for (size_t ch = 0; ch < num_channels_; ++ch) { for (size_t i = 0; i < kFftSize; ++i) { filter_bank_states[ch].extended_frame[i] = gain_adjustment * filter_bank_states[ch].extended_frame[i]; } } // Use overlap-and-add to form the output frame of the lowest band. for (size_t ch = 0; ch < num_channels_; ++ch) { rtc::ArrayView y_band0(&audio->split_bands(ch)[0][0], kNsFrameSize); OverlapAndAdd(filter_bank_states[ch].extended_frame, channels_[ch]->process_synthesis_memory, y_band0); } if (num_bands_ > 1) { // Select the noise attenuating gain to apply to the upper band. float upper_band_gain = upper_band_gains[0]; for (size_t ch = 1; ch < num_channels_; ++ch) { upper_band_gain = std::min(upper_band_gain, upper_band_gains[ch]); } // Process the upper bands. for (size_t ch = 0; ch < num_channels_; ++ch) { for (size_t b = 1; b < num_bands_; ++b) { // Delay the upper bands to match the delay of the filterbank applied to // the lowest band. rtc::ArrayView y_band( &audio->split_bands(ch)[b][0], kNsFrameSize); std::array delayed_frame; DelaySignal(y_band, channels_[ch]->process_delay_memory[b - 1], delayed_frame); // Apply the time-domain noise-attenuating gain. for (size_t j = 0; j < kNsFrameSize; j++) { y_band[j] = upper_band_gain * delayed_frame[j]; } } } } // Limit the output the allowed range. for (size_t ch = 0; ch < num_channels_; ++ch) { for (size_t b = 0; b < num_bands_; ++b) { rtc::ArrayView y_band(&audio->split_bands(ch)[b][0], kNsFrameSize); for (size_t j = 0; j < kNsFrameSize; j++) { y_band[j] = std::min(std::max(y_band[j], -32768.f), 32767.f); } } } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/noise_suppressor.h0000664000175000017500000000557014475643423027403 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_NS_NOISE_SUPPRESSOR_H_ #define MODULES_AUDIO_PROCESSING_NS_NOISE_SUPPRESSOR_H_ #include #include #include "api/array_view.h" #include "modules/audio_processing/audio_buffer.h" #include "modules/audio_processing/ns/noise_estimator.h" #include "modules/audio_processing/ns/ns_common.h" #include "modules/audio_processing/ns/ns_config.h" #include "modules/audio_processing/ns/ns_fft.h" #include "modules/audio_processing/ns/speech_probability_estimator.h" #include "modules/audio_processing/ns/wiener_filter.h" namespace webrtc { // Class for suppressing noise in a signal. class NoiseSuppressor { public: NoiseSuppressor(const NsConfig& config, size_t sample_rate_hz, size_t num_channels); NoiseSuppressor(const NoiseSuppressor&) = delete; NoiseSuppressor& operator=(const NoiseSuppressor&) = delete; // Analyses the signal (typically applied before the AEC to avoid analyzing // any comfort noise signal). void Analyze(const AudioBuffer& audio); // Applies noise suppression. void Process(AudioBuffer* audio); private: const size_t num_bands_; const size_t num_channels_; const SuppressionParams suppression_params_; int32_t num_analyzed_frames_ = -1; NrFft fft_; struct ChannelState { ChannelState(const SuppressionParams& suppression_params, size_t num_bands); SpeechProbabilityEstimator speech_probability_estimator; WienerFilter wiener_filter; NoiseEstimator noise_estimator; std::array prev_analysis_signal_spectrum; std::array analyze_analysis_memory; std::array process_analysis_memory; std::array process_synthesis_memory; std::vector> process_delay_memory; }; struct FilterBankState { std::array real; std::array imag; std::array extended_frame; }; std::vector filter_bank_states_heap_; std::vector upper_band_gains_heap_; std::vector energies_before_filtering_heap_; std::vector gain_adjustments_heap_; std::vector> channels_; // Aggregates the Wiener filters into a single filter to use. void AggregateWienerFilters( rtc::ArrayView filter) const; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_NS_NOISE_SUPPRESSOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/ns_common.h0000664000175000017500000000212314475643423025740 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_NS_NS_COMMON_H_ #define MODULES_AUDIO_PROCESSING_NS_NS_COMMON_H_ #include namespace webrtc { constexpr size_t kFftSize = 256; constexpr size_t kFftSizeBy2Plus1 = kFftSize / 2 + 1; constexpr size_t kNsFrameSize = 160; constexpr size_t kOverlapSize = kFftSize - kNsFrameSize; constexpr int kShortStartupPhaseBlocks = 50; constexpr int kLongStartupPhaseBlocks = 200; constexpr int kFeatureUpdateWindowSize = 500; constexpr float kLtrFeatureThr = 0.5f; constexpr float kBinSizeLrt = 0.1f; constexpr float kBinSizeSpecFlat = 0.05f; constexpr float kBinSizeSpecDiff = 0.1f; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_NS_NS_COMMON_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/ns_config.h0000664000175000017500000000143114475643423025716 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_NS_NS_CONFIG_H_ #define MODULES_AUDIO_PROCESSING_NS_NS_CONFIG_H_ namespace webrtc { // Config struct for the noise suppressor struct NsConfig { enum class SuppressionLevel { k6dB, k12dB, k18dB, k21dB }; SuppressionLevel target_level = SuppressionLevel::k12dB; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_NS_NS_CONFIG_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/ns_fft.cc0000664000175000017500000000400514475643423025366 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/ns/ns_fft.h" #include "common_audio/third_party/ooura/fft_size_256/fft4g.h" namespace webrtc { NrFft::NrFft() : bit_reversal_state_(kFftSize / 2), tables_(kFftSize / 2) { // Initialize WebRtc_rdt (setting (bit_reversal_state_[0] to 0 triggers // initialization) bit_reversal_state_[0] = 0.f; std::array tmp_buffer; tmp_buffer.fill(0.f); WebRtc_rdft(kFftSize, 1, tmp_buffer.data(), bit_reversal_state_.data(), tables_.data()); } void NrFft::Fft(rtc::ArrayView time_data, rtc::ArrayView real, rtc::ArrayView imag) { WebRtc_rdft(kFftSize, 1, time_data.data(), bit_reversal_state_.data(), tables_.data()); imag[0] = 0; real[0] = time_data[0]; imag[kFftSizeBy2Plus1 - 1] = 0; real[kFftSizeBy2Plus1 - 1] = time_data[1]; for (size_t i = 1; i < kFftSizeBy2Plus1 - 1; ++i) { real[i] = time_data[2 * i]; imag[i] = time_data[2 * i + 1]; } } void NrFft::Ifft(rtc::ArrayView real, rtc::ArrayView imag, rtc::ArrayView time_data) { time_data[0] = real[0]; time_data[1] = real[kFftSizeBy2Plus1 - 1]; for (size_t i = 1; i < kFftSizeBy2Plus1 - 1; ++i) { time_data[2 * i] = real[i]; time_data[2 * i + 1] = imag[i]; } WebRtc_rdft(kFftSize, -1, time_data.data(), bit_reversal_state_.data(), tables_.data()); // Scale the output constexpr float kScaling = 2.f / kFftSize; for (float& d : time_data) { d *= kScaling; } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/ns_fft.h0000664000175000017500000000252114475643423025231 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_NS_NS_FFT_H_ #define MODULES_AUDIO_PROCESSING_NS_NS_FFT_H_ #include #include "api/array_view.h" #include "modules/audio_processing/ns/ns_common.h" namespace webrtc { // Wrapper class providing 256 point FFT functionality. class NrFft { public: NrFft(); NrFft(const NrFft&) = delete; NrFft& operator=(const NrFft&) = delete; // Transforms the signal from time to frequency domain. void Fft(rtc::ArrayView time_data, rtc::ArrayView real, rtc::ArrayView imag); // Transforms the signal from frequency to time domain. void Ifft(rtc::ArrayView real, rtc::ArrayView imag, rtc::ArrayView time_data); private: std::vector bit_reversal_state_; std::vector tables_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_NS_NS_FFT_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/prior_signal_model.cc0000664000175000017500000000114314475643423027757 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/ns/prior_signal_model.h" namespace webrtc { PriorSignalModel::PriorSignalModel(float lrt_initial_value) : lrt(lrt_initial_value) {} } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/prior_signal_model.h0000664000175000017500000000207214475643423027623 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_NS_PRIOR_SIGNAL_MODEL_H_ #define MODULES_AUDIO_PROCESSING_NS_PRIOR_SIGNAL_MODEL_H_ namespace webrtc { // Struct for storing the prior signal model parameters. struct PriorSignalModel { explicit PriorSignalModel(float lrt_initial_value); PriorSignalModel(const PriorSignalModel&) = delete; PriorSignalModel& operator=(const PriorSignalModel&) = delete; float lrt; float flatness_threshold = .5f; float template_diff_threshold = .5f; float lrt_weighting = 1.f; float flatness_weighting = 0.f; float difference_weighting = 0.f; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_NS_PRIOR_SIGNAL_MODEL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/prior_signal_model_estimator.cc0000664000175000017500000001352214475643423032052 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/ns/prior_signal_model_estimator.h" #include #include #include "modules/audio_processing/ns/fast_math.h" #include "rtc_base/checks.h" namespace webrtc { namespace { // Identifies the first of the two largest peaks in the histogram. void FindFirstOfTwoLargestPeaks( float bin_size, rtc::ArrayView spectral_flatness, float* peak_position, int* peak_weight) { RTC_DCHECK(peak_position); RTC_DCHECK(peak_weight); int peak_value = 0; int secondary_peak_value = 0; *peak_position = 0.f; float secondary_peak_position = 0.f; *peak_weight = 0; int secondary_peak_weight = 0; // Identify the two largest peaks. for (int i = 0; i < kHistogramSize; ++i) { const float bin_mid = (i + 0.5f) * bin_size; if (spectral_flatness[i] > peak_value) { // Found new "first" peak candidate. secondary_peak_value = peak_value; secondary_peak_weight = *peak_weight; secondary_peak_position = *peak_position; peak_value = spectral_flatness[i]; *peak_weight = spectral_flatness[i]; *peak_position = bin_mid; } else if (spectral_flatness[i] > secondary_peak_value) { // Found new "second" peak candidate. secondary_peak_value = spectral_flatness[i]; secondary_peak_weight = spectral_flatness[i]; secondary_peak_position = bin_mid; } } // Merge the peaks if they are close. if ((fabs(secondary_peak_position - *peak_position) < 2 * bin_size) && (secondary_peak_weight > 0.5f * (*peak_weight))) { *peak_weight += secondary_peak_weight; *peak_position = 0.5f * (*peak_position + secondary_peak_position); } } void UpdateLrt(rtc::ArrayView lrt_histogram, float* prior_model_lrt, bool* low_lrt_fluctuations) { RTC_DCHECK(prior_model_lrt); RTC_DCHECK(low_lrt_fluctuations); float average = 0.f; float average_compl = 0.f; float average_squared = 0.f; int count = 0; for (int i = 0; i < 10; ++i) { float bin_mid = (i + 0.5f) * kBinSizeLrt; average += lrt_histogram[i] * bin_mid; count += lrt_histogram[i]; } if (count > 0) { average = average / count; } for (int i = 0; i < kHistogramSize; ++i) { float bin_mid = (i + 0.5f) * kBinSizeLrt; average_squared += lrt_histogram[i] * bin_mid * bin_mid; average_compl += lrt_histogram[i] * bin_mid; } constexpr float kOneFeatureUpdateWindowSize = 1.f / kFeatureUpdateWindowSize; average_squared = average_squared * kOneFeatureUpdateWindowSize; average_compl = average_compl * kOneFeatureUpdateWindowSize; // Fluctuation limit of LRT feature. *low_lrt_fluctuations = average_squared - average * average_compl < 0.05f; // Get threshold for LRT feature. constexpr float kMaxLrt = 1.f; constexpr float kMinLrt = .2f; if (*low_lrt_fluctuations) { // Very low fluctuation, so likely noise. *prior_model_lrt = kMaxLrt; } else { *prior_model_lrt = std::min(kMaxLrt, std::max(kMinLrt, 1.2f * average)); } } } // namespace PriorSignalModelEstimator::PriorSignalModelEstimator(float lrt_initial_value) : prior_model_(lrt_initial_value) {} // Extract thresholds for feature parameters and computes the threshold/weights. void PriorSignalModelEstimator::Update(const Histograms& histograms) { bool low_lrt_fluctuations; UpdateLrt(histograms.get_lrt(), &prior_model_.lrt, &low_lrt_fluctuations); // For spectral flatness and spectral difference: compute the main peaks of // the histograms. float spectral_flatness_peak_position; int spectral_flatness_peak_weight; FindFirstOfTwoLargestPeaks( kBinSizeSpecFlat, histograms.get_spectral_flatness(), &spectral_flatness_peak_position, &spectral_flatness_peak_weight); float spectral_diff_peak_position = 0.f; int spectral_diff_peak_weight = 0; FindFirstOfTwoLargestPeaks(kBinSizeSpecDiff, histograms.get_spectral_diff(), &spectral_diff_peak_position, &spectral_diff_peak_weight); // Reject if weight of peaks is not large enough, or peak value too small. // Peak limit for spectral flatness (varies between 0 and 1). const int use_spec_flat = spectral_flatness_peak_weight < 0.3f * 500 || spectral_flatness_peak_position < 0.6f ? 0 : 1; // Reject if weight of peaks is not large enough or if fluctuation of the LRT // feature are very low, indicating a noise state. const int use_spec_diff = spectral_diff_peak_weight < 0.3f * 500 || low_lrt_fluctuations ? 0 : 1; // Update the model. prior_model_.template_diff_threshold = 1.2f * spectral_diff_peak_position; prior_model_.template_diff_threshold = std::min(1.f, std::max(0.16f, prior_model_.template_diff_threshold)); float one_by_feature_sum = 1.f / (1.f + use_spec_flat + use_spec_diff); prior_model_.lrt_weighting = one_by_feature_sum; if (use_spec_flat == 1) { prior_model_.flatness_threshold = 0.9f * spectral_flatness_peak_position; prior_model_.flatness_threshold = std::min(.95f, std::max(0.1f, prior_model_.flatness_threshold)); prior_model_.flatness_weighting = one_by_feature_sum; } else { prior_model_.flatness_weighting = 0.f; } if (use_spec_diff == 1) { prior_model_.difference_weighting = one_by_feature_sum; } else { prior_model_.difference_weighting = 0.f; } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/prior_signal_model_estimator.h0000664000175000017500000000245514475643423031717 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_NS_PRIOR_SIGNAL_MODEL_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_NS_PRIOR_SIGNAL_MODEL_ESTIMATOR_H_ #include "modules/audio_processing/ns/histograms.h" #include "modules/audio_processing/ns/prior_signal_model.h" namespace webrtc { // Estimator of the prior signal model parameters. class PriorSignalModelEstimator { public: explicit PriorSignalModelEstimator(float lrt_initial_value); PriorSignalModelEstimator(const PriorSignalModelEstimator&) = delete; PriorSignalModelEstimator& operator=(const PriorSignalModelEstimator&) = delete; // Updates the model estimate. void Update(const Histograms& h); // Returns the estimated model. const PriorSignalModel& get_prior_model() const { return prior_model_; } private: PriorSignalModel prior_model_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_NS_PRIOR_SIGNAL_MODEL_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/quantile_noise_estimator.cc0000664000175000017500000000554514475643423031227 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/ns/quantile_noise_estimator.h" #include #include "modules/audio_processing/ns/fast_math.h" namespace webrtc { QuantileNoiseEstimator::QuantileNoiseEstimator() { quantile_.fill(0.f); density_.fill(0.3f); log_quantile_.fill(8.f); constexpr float kOneBySimult = 1.f / kSimult; for (size_t i = 0; i < kSimult; ++i) { counter_[i] = floor(kLongStartupPhaseBlocks * (i + 1.f) * kOneBySimult); } } void QuantileNoiseEstimator::Estimate( rtc::ArrayView signal_spectrum, rtc::ArrayView noise_spectrum) { std::array log_spectrum; LogApproximation(signal_spectrum, log_spectrum); int quantile_index_to_return = -1; // Loop over simultaneous estimates. for (int s = 0, k = 0; s < kSimult; ++s, k += static_cast(kFftSizeBy2Plus1)) { const float one_by_counter_plus_1 = 1.f / (counter_[s] + 1.f); for (int i = 0, j = k; i < static_cast(kFftSizeBy2Plus1); ++i, ++j) { // Update log quantile estimate. const float delta = density_[j] > 1.f ? 40.f / density_[j] : 40.f; const float multiplier = delta * one_by_counter_plus_1; if (log_spectrum[i] > log_quantile_[j]) { log_quantile_[j] += 0.25f * multiplier; } else { log_quantile_[j] -= 0.75f * multiplier; } // Update density estimate. constexpr float kWidth = 0.01f; constexpr float kOneByWidthPlus2 = 1.f / (2.f * kWidth); if (fabs(log_spectrum[i] - log_quantile_[j]) < kWidth) { density_[j] = (counter_[s] * density_[j] + kOneByWidthPlus2) * one_by_counter_plus_1; } } if (counter_[s] >= kLongStartupPhaseBlocks) { counter_[s] = 0; if (num_updates_ >= kLongStartupPhaseBlocks) { quantile_index_to_return = k; } } ++counter_[s]; } // Sequentially update the noise during startup. if (num_updates_ < kLongStartupPhaseBlocks) { // Use the last "s" to get noise during startup that differ from zero. quantile_index_to_return = kFftSizeBy2Plus1 * (kSimult - 1); ++num_updates_; } if (quantile_index_to_return >= 0) { ExpApproximation( rtc::ArrayView(&log_quantile_[quantile_index_to_return], kFftSizeBy2Plus1), quantile_); } std::copy(quantile_.begin(), quantile_.end(), noise_spectrum.begin()); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/quantile_noise_estimator.h0000664000175000017500000000266714475643423031073 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_NS_QUANTILE_NOISE_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_NS_QUANTILE_NOISE_ESTIMATOR_H_ #include #include #include "api/array_view.h" #include "modules/audio_processing/ns/ns_common.h" namespace webrtc { constexpr int kSimult = 3; // For quantile noise estimation. class QuantileNoiseEstimator { public: QuantileNoiseEstimator(); QuantileNoiseEstimator(const QuantileNoiseEstimator&) = delete; QuantileNoiseEstimator& operator=(const QuantileNoiseEstimator&) = delete; // Estimate noise. void Estimate(rtc::ArrayView signal_spectrum, rtc::ArrayView noise_spectrum); private: std::array density_; std::array log_quantile_; std::array quantile_; std::array counter_; int num_updates_ = 1; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_NS_QUANTILE_NOISE_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/signal_model.cc0000664000175000017500000000131314475643423026543 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/ns/signal_model.h" namespace webrtc { SignalModel::SignalModel() { constexpr float kSfFeatureThr = 0.5f; lrt = kLtrFeatureThr; spectral_flatness = kSfFeatureThr; spectral_diff = kSfFeatureThr; avg_log_lrt.fill(kLtrFeatureThr); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/signal_model.h0000664000175000017500000000173114475643423026411 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_NS_SIGNAL_MODEL_H_ #define MODULES_AUDIO_PROCESSING_NS_SIGNAL_MODEL_H_ #include #include "modules/audio_processing/ns/ns_common.h" namespace webrtc { struct SignalModel { SignalModel(); SignalModel(const SignalModel&) = delete; SignalModel& operator=(const SignalModel&) = delete; float lrt; float spectral_diff; float spectral_flatness; // Log LRT factor with time-smoothing. std::array avg_log_lrt; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_NS_SIGNAL_MODEL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/signal_model_estimator.cc0000664000175000017500000001451314475643423030640 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/ns/signal_model_estimator.h" #include "modules/audio_processing/ns/fast_math.h" namespace webrtc { namespace { constexpr float kOneByFftSizeBy2Plus1 = 1.f / kFftSizeBy2Plus1; // Computes the difference measure between input spectrum and a template/learned // noise spectrum. float ComputeSpectralDiff( rtc::ArrayView conservative_noise_spectrum, rtc::ArrayView signal_spectrum, float signal_spectral_sum, float diff_normalization) { // spectral_diff = var(signal_spectrum) - cov(signal_spectrum, magnAvgPause)^2 // / var(magnAvgPause) // Compute average quantities. float noise_average = 0.f; for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) { // Conservative smooth noise spectrum from pause frames. noise_average += conservative_noise_spectrum[i]; } noise_average = noise_average * kOneByFftSizeBy2Plus1; float signal_average = signal_spectral_sum * kOneByFftSizeBy2Plus1; // Compute variance and covariance quantities. float covariance = 0.f; float noise_variance = 0.f; float signal_variance = 0.f; for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) { float signal_diff = signal_spectrum[i] - signal_average; float noise_diff = conservative_noise_spectrum[i] - noise_average; covariance += signal_diff * noise_diff; noise_variance += noise_diff * noise_diff; signal_variance += signal_diff * signal_diff; } covariance *= kOneByFftSizeBy2Plus1; noise_variance *= kOneByFftSizeBy2Plus1; signal_variance *= kOneByFftSizeBy2Plus1; // Update of average magnitude spectrum. float spectral_diff = signal_variance - (covariance * covariance) / (noise_variance + 0.0001f); // Normalize. return spectral_diff / (diff_normalization + 0.0001f); } // Updates the spectral flatness based on the input spectrum. void UpdateSpectralFlatness( rtc::ArrayView signal_spectrum, float signal_spectral_sum, float* spectral_flatness) { RTC_DCHECK(spectral_flatness); // Compute log of ratio of the geometric to arithmetic mean (handle the log(0) // separately). constexpr float kAveraging = 0.3f; float avg_spect_flatness_num = 0.f; for (size_t i = 1; i < kFftSizeBy2Plus1; ++i) { if (signal_spectrum[i] == 0.f) { *spectral_flatness -= kAveraging * (*spectral_flatness); return; } } for (size_t i = 1; i < kFftSizeBy2Plus1; ++i) { avg_spect_flatness_num += LogApproximation(signal_spectrum[i]); } float avg_spect_flatness_denom = signal_spectral_sum - signal_spectrum[0]; avg_spect_flatness_denom = avg_spect_flatness_denom * kOneByFftSizeBy2Plus1; avg_spect_flatness_num = avg_spect_flatness_num * kOneByFftSizeBy2Plus1; float spectral_tmp = ExpApproximation(avg_spect_flatness_num) / avg_spect_flatness_denom; // Time-avg update of spectral flatness feature. *spectral_flatness += kAveraging * (spectral_tmp - *spectral_flatness); } // Updates the log LRT measures. void UpdateSpectralLrt(rtc::ArrayView prior_snr, rtc::ArrayView post_snr, rtc::ArrayView avg_log_lrt, float* lrt) { RTC_DCHECK(lrt); for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) { float tmp1 = 1.f + 2.f * prior_snr[i]; float tmp2 = 2.f * prior_snr[i] / (tmp1 + 0.0001f); float bessel_tmp = (post_snr[i] + 1.f) * tmp2; avg_log_lrt[i] += .5f * (bessel_tmp - LogApproximation(tmp1) - avg_log_lrt[i]); } float log_lrt_time_avg_k_sum = 0.f; for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) { log_lrt_time_avg_k_sum += avg_log_lrt[i]; } *lrt = log_lrt_time_avg_k_sum * kOneByFftSizeBy2Plus1; } } // namespace SignalModelEstimator::SignalModelEstimator() : prior_model_estimator_(kLtrFeatureThr) {} void SignalModelEstimator::AdjustNormalization(int32_t num_analyzed_frames, float signal_energy) { diff_normalization_ *= num_analyzed_frames; diff_normalization_ += signal_energy; diff_normalization_ /= (num_analyzed_frames + 1); } // Update the noise features. void SignalModelEstimator::Update( rtc::ArrayView prior_snr, rtc::ArrayView post_snr, rtc::ArrayView conservative_noise_spectrum, rtc::ArrayView signal_spectrum, float signal_spectral_sum, float signal_energy) { // Compute spectral flatness on input spectrum. UpdateSpectralFlatness(signal_spectrum, signal_spectral_sum, &features_.spectral_flatness); // Compute difference of input spectrum with learned/estimated noise spectrum. float spectral_diff = ComputeSpectralDiff(conservative_noise_spectrum, signal_spectrum, signal_spectral_sum, diff_normalization_); // Compute time-avg update of difference feature. features_.spectral_diff += 0.3f * (spectral_diff - features_.spectral_diff); signal_energy_sum_ += signal_energy; // Compute histograms for parameter decisions (thresholds and weights for // features). Parameters are extracted periodically. if (--histogram_analysis_counter_ > 0) { histograms_.Update(features_); } else { // Compute model parameters. prior_model_estimator_.Update(histograms_); // Clear histograms for next update. histograms_.Clear(); histogram_analysis_counter_ = kFeatureUpdateWindowSize; // Update every window: // Compute normalization for the spectral difference for next estimation. signal_energy_sum_ = signal_energy_sum_ / kFeatureUpdateWindowSize; diff_normalization_ = 0.5f * (signal_energy_sum_ + diff_normalization_); signal_energy_sum_ = 0.f; } // Compute the LRT. UpdateSpectralLrt(prior_snr, post_snr, features_.avg_log_lrt, &features_.lrt); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/signal_model_estimator.h0000664000175000017500000000403114475643423030474 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_NS_SIGNAL_MODEL_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_NS_SIGNAL_MODEL_ESTIMATOR_H_ #include #include "api/array_view.h" #include "modules/audio_processing/ns/histograms.h" #include "modules/audio_processing/ns/ns_common.h" #include "modules/audio_processing/ns/prior_signal_model.h" #include "modules/audio_processing/ns/prior_signal_model_estimator.h" #include "modules/audio_processing/ns/signal_model.h" namespace webrtc { class SignalModelEstimator { public: SignalModelEstimator(); SignalModelEstimator(const SignalModelEstimator&) = delete; SignalModelEstimator& operator=(const SignalModelEstimator&) = delete; // Compute signal normalization during the initial startup phase. void AdjustNormalization(int32_t num_analyzed_frames, float signal_energy); void Update( rtc::ArrayView prior_snr, rtc::ArrayView post_snr, rtc::ArrayView conservative_noise_spectrum, rtc::ArrayView signal_spectrum, float signal_spectral_sum, float signal_energy); const PriorSignalModel& get_prior_model() const { return prior_model_estimator_.get_prior_model(); } const SignalModel& get_model() { return features_; } private: float diff_normalization_ = 0.f; float signal_energy_sum_ = 0.f; Histograms histograms_; int histogram_analysis_counter_ = 500; PriorSignalModelEstimator prior_model_estimator_; SignalModel features_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_NS_SIGNAL_MODEL_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/speech_probability_estimator.cc0000664000175000017500000000764614475643423032063 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/ns/speech_probability_estimator.h" #include #include #include "modules/audio_processing/ns/fast_math.h" #include "rtc_base/checks.h" namespace webrtc { SpeechProbabilityEstimator::SpeechProbabilityEstimator() { speech_probability_.fill(0.f); } void SpeechProbabilityEstimator::Update( int32_t num_analyzed_frames, rtc::ArrayView prior_snr, rtc::ArrayView post_snr, rtc::ArrayView conservative_noise_spectrum, rtc::ArrayView signal_spectrum, float signal_spectral_sum, float signal_energy) { // Update models. if (num_analyzed_frames < kLongStartupPhaseBlocks) { signal_model_estimator_.AdjustNormalization(num_analyzed_frames, signal_energy); } signal_model_estimator_.Update(prior_snr, post_snr, conservative_noise_spectrum, signal_spectrum, signal_spectral_sum, signal_energy); const SignalModel& model = signal_model_estimator_.get_model(); const PriorSignalModel& prior_model = signal_model_estimator_.get_prior_model(); // Width parameter in sigmoid map for prior model. constexpr float kWidthPrior0 = 4.f; // Width for pause region: lower range, so increase width in tanh map. constexpr float kWidthPrior1 = 2.f * kWidthPrior0; // Average LRT feature: use larger width in tanh map for pause regions. float width_prior = model.lrt < prior_model.lrt ? kWidthPrior1 : kWidthPrior0; // Compute indicator function: sigmoid map. float indicator0 = 0.5f * (tanh(width_prior * (model.lrt - prior_model.lrt)) + 1.f); // Spectral flatness feature: use larger width in tanh map for pause regions. width_prior = model.spectral_flatness > prior_model.flatness_threshold ? kWidthPrior1 : kWidthPrior0; // Compute indicator function: sigmoid map. float indicator1 = 0.5f * (tanh(1.f * width_prior * (prior_model.flatness_threshold - model.spectral_flatness)) + 1.f); // For template spectrum-difference : use larger width in tanh map for pause // regions. width_prior = model.spectral_diff < prior_model.template_diff_threshold ? kWidthPrior1 : kWidthPrior0; // Compute indicator function: sigmoid map. float indicator2 = 0.5f * (tanh(width_prior * (model.spectral_diff - prior_model.template_diff_threshold)) + 1.f); // Combine the indicator function with the feature weights. float ind_prior = prior_model.lrt_weighting * indicator0 + prior_model.flatness_weighting * indicator1 + prior_model.difference_weighting * indicator2; // Compute the prior probability. prior_speech_prob_ += 0.1f * (ind_prior - prior_speech_prob_); // Make sure probabilities are within range: keep floor to 0.01. prior_speech_prob_ = std::max(std::min(prior_speech_prob_, 1.f), 0.01f); // Final speech probability: combine prior model with LR factor:. float gain_prior = (1.f - prior_speech_prob_) / (prior_speech_prob_ + 0.0001f); std::array inv_lrt; ExpApproximationSignFlip(model.avg_log_lrt, inv_lrt); for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) { speech_probability_[i] = 1.f / (1.f + gain_prior * inv_lrt[i]); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/speech_probability_estimator.h0000664000175000017500000000346614475643423031721 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_NS_SPEECH_PROBABILITY_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_NS_SPEECH_PROBABILITY_ESTIMATOR_H_ #include #include "api/array_view.h" #include "modules/audio_processing/ns/ns_common.h" #include "modules/audio_processing/ns/signal_model_estimator.h" namespace webrtc { // Class for estimating the probability of speech. class SpeechProbabilityEstimator { public: SpeechProbabilityEstimator(); SpeechProbabilityEstimator(const SpeechProbabilityEstimator&) = delete; SpeechProbabilityEstimator& operator=(const SpeechProbabilityEstimator&) = delete; // Compute speech probability. void Update( int32_t num_analyzed_frames, rtc::ArrayView prior_snr, rtc::ArrayView post_snr, rtc::ArrayView conservative_noise_spectrum, rtc::ArrayView signal_spectrum, float signal_spectral_sum, float signal_energy); float get_prior_probability() const { return prior_speech_prob_; } rtc::ArrayView get_probability() { return speech_probability_; } private: SignalModelEstimator signal_model_estimator_; float prior_speech_prob_ = .5f; std::array speech_probability_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_NS_SPEECH_PROBABILITY_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/suppression_params.cc0000664000175000017500000000277114475643423030054 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/ns/suppression_params.h" #include "rtc_base/checks.h" namespace webrtc { SuppressionParams::SuppressionParams( NsConfig::SuppressionLevel suppression_level) { switch (suppression_level) { case NsConfig::SuppressionLevel::k6dB: over_subtraction_factor = 1.f; // 6 dB attenuation. minimum_attenuating_gain = 0.5f; use_attenuation_adjustment = false; break; case NsConfig::SuppressionLevel::k12dB: over_subtraction_factor = 1.f; // 12 dB attenuation. minimum_attenuating_gain = 0.25f; use_attenuation_adjustment = true; break; case NsConfig::SuppressionLevel::k18dB: over_subtraction_factor = 1.1f; // 18 dB attenuation. minimum_attenuating_gain = 0.125f; use_attenuation_adjustment = true; break; case NsConfig::SuppressionLevel::k21dB: over_subtraction_factor = 1.25f; // 20.9 dB attenuation. minimum_attenuating_gain = 0.09f; use_attenuation_adjustment = true; break; default: RTC_NOTREACHED(); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/suppression_params.h0000664000175000017500000000177514475643423027721 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_NS_SUPPRESSION_PARAMS_H_ #define MODULES_AUDIO_PROCESSING_NS_SUPPRESSION_PARAMS_H_ #include "modules/audio_processing/ns/ns_config.h" namespace webrtc { struct SuppressionParams { explicit SuppressionParams(NsConfig::SuppressionLevel suppression_level); SuppressionParams(const SuppressionParams&) = delete; SuppressionParams& operator=(const SuppressionParams&) = delete; float over_subtraction_factor; float minimum_attenuating_gain; bool use_attenuation_adjustment; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_NS_SUPPRESSION_PARAMS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/wiener_filter.cc0000664000175000017500000001047514475643423026755 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/ns/wiener_filter.h" #include #include #include #include #include "modules/audio_processing/ns/fast_math.h" #include "rtc_base/checks.h" namespace webrtc { WienerFilter::WienerFilter(const SuppressionParams& suppression_params) : suppression_params_(suppression_params) { filter_.fill(1.f); initial_spectral_estimate_.fill(0.f); spectrum_prev_process_.fill(0.f); } void WienerFilter::Update( int32_t num_analyzed_frames, rtc::ArrayView noise_spectrum, rtc::ArrayView prev_noise_spectrum, rtc::ArrayView parametric_noise_spectrum, rtc::ArrayView signal_spectrum) { for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) { // Previous estimate based on previous frame with gain filter. float prev_tsa = spectrum_prev_process_[i] / (prev_noise_spectrum[i] + 0.0001f) * filter_[i]; // Current estimate. float current_tsa; if (signal_spectrum[i] > noise_spectrum[i]) { current_tsa = signal_spectrum[i] / (noise_spectrum[i] + 0.0001f) - 1.f; } else { current_tsa = 0.f; } // Directed decision estimate is sum of two terms: current estimate and // previous estimate. float snr_prior = 0.98f * prev_tsa + (1.f - 0.98f) * current_tsa; filter_[i] = snr_prior / (suppression_params_.over_subtraction_factor + snr_prior); filter_[i] = std::max(std::min(filter_[i], 1.f), suppression_params_.minimum_attenuating_gain); } if (num_analyzed_frames < kShortStartupPhaseBlocks) { for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) { initial_spectral_estimate_[i] += signal_spectrum[i]; float filter_initial = initial_spectral_estimate_[i] - suppression_params_.over_subtraction_factor * parametric_noise_spectrum[i]; filter_initial /= initial_spectral_estimate_[i] + 0.0001f; filter_initial = std::max(std::min(filter_initial, 1.f), suppression_params_.minimum_attenuating_gain); // Weight the two suppression filters. constexpr float kOnyByShortStartupPhaseBlocks = 1.f / kShortStartupPhaseBlocks; filter_initial *= kShortStartupPhaseBlocks - num_analyzed_frames; filter_[i] *= num_analyzed_frames; filter_[i] += filter_initial; filter_[i] *= kOnyByShortStartupPhaseBlocks; } } std::copy(signal_spectrum.begin(), signal_spectrum.end(), spectrum_prev_process_.begin()); } float WienerFilter::ComputeOverallScalingFactor( int32_t num_analyzed_frames, float prior_speech_probability, float energy_before_filtering, float energy_after_filtering) const { if (!suppression_params_.use_attenuation_adjustment || num_analyzed_frames <= kLongStartupPhaseBlocks) { return 1.f; } float gain = SqrtFastApproximation(energy_after_filtering / (energy_before_filtering + 1.f)); // Scaling for new version. Threshold in final energy gain factor calculation. constexpr float kBLim = 0.5f; float scale_factor1 = 1.f; if (gain > kBLim) { scale_factor1 = 1.f + 1.3f * (gain - kBLim); if (gain * scale_factor1 > 1.f) { scale_factor1 = 1.f / gain; } } float scale_factor2 = 1.f; if (gain < kBLim) { // Do not reduce scale too much for pause regions: attenuation here should // be controlled by flooring. gain = std::max(gain, suppression_params_.minimum_attenuating_gain); scale_factor2 = 1.f - 0.3f * (kBLim - gain); } // Combine both scales with speech/noise prob: note prior // (prior_speech_probability) is not frequency dependent. return prior_speech_probability * scale_factor1 + (1.f - prior_speech_probability) * scale_factor2; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/ns/wiener_filter.h0000664000175000017500000000407514475643423026616 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_NS_WIENER_FILTER_H_ #define MODULES_AUDIO_PROCESSING_NS_WIENER_FILTER_H_ #include #include "api/array_view.h" #include "modules/audio_processing/ns/ns_common.h" #include "modules/audio_processing/ns/suppression_params.h" namespace webrtc { // Estimates a Wiener-filter based frequency domain noise reduction filter. class WienerFilter { public: explicit WienerFilter(const SuppressionParams& suppression_params); WienerFilter(const WienerFilter&) = delete; WienerFilter& operator=(const WienerFilter&) = delete; // Updates the filter estimate. void Update( int32_t num_analyzed_frames, rtc::ArrayView noise_spectrum, rtc::ArrayView prev_noise_spectrum, rtc::ArrayView parametric_noise_spectrum, rtc::ArrayView signal_spectrum); // Compute an overall gain scaling factor. float ComputeOverallScalingFactor(int32_t num_analyzed_frames, float prior_speech_probability, float energy_before_filtering, float energy_after_filtering) const; // Returns the filter. rtc::ArrayView get_filter() const { return filter_; } private: const SuppressionParams& suppression_params_; std::array spectrum_prev_process_; std::array initial_spectral_estimate_; std::array filter_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_NS_WIENER_FILTER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/optionally_built_submodule_creators.cc0000664000175000017500000000165414475643423033050 0ustar00arunarun/* * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/optionally_built_submodule_creators.h" #include #include "modules/audio_processing/transient/transient_suppressor_impl.h" namespace webrtc { std::unique_ptr CreateTransientSuppressor( const ApmSubmoduleCreationOverrides& overrides) { #ifdef WEBRTC_EXCLUDE_TRANSIENT_SUPPRESSOR return nullptr; #else if (overrides.transient_suppression) { return nullptr; } return std::make_unique(); #endif } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/optionally_built_submodule_creators.h0000664000175000017500000000301014475643423032676 0ustar00arunarun/* * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_OPTIONALLY_BUILT_SUBMODULE_CREATORS_H_ #define MODULES_AUDIO_PROCESSING_OPTIONALLY_BUILT_SUBMODULE_CREATORS_H_ #include #include "modules/audio_processing/transient/transient_suppressor.h" namespace webrtc { // These overrides are only to be used for testing purposes. // Each flag emulates a preprocessor macro to exclude a submodule of APM from // the build, e.g. WEBRTC_EXCLUDE_TRANSIENT_SUPPRESSOR. If the corresponding // flag |transient_suppression| is enabled, then the creators will return // nullptr instead of a submodule instance, as if the macro had been defined. struct ApmSubmoduleCreationOverrides { bool transient_suppression = false; }; // Creates a transient suppressor. // Will instead return nullptr if one of the following is true: // * WEBRTC_EXCLUDE_TRANSIENT_SUPPRESSOR is defined // * The corresponding override in |overrides| is enabled. std::unique_ptr CreateTransientSuppressor( const ApmSubmoduleCreationOverrides& overrides); } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_OPTIONALLY_BUILT_SUBMODULE_CREATORS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/render_queue_item_verifier.h0000664000175000017500000000206214475643423030726 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_RENDER_QUEUE_ITEM_VERIFIER_H_ #define MODULES_AUDIO_PROCESSING_RENDER_QUEUE_ITEM_VERIFIER_H_ #include namespace webrtc { // Functor to use when supplying a verifier function for the queue item // verifcation. template class RenderQueueItemVerifier { public: explicit RenderQueueItemVerifier(size_t minimum_capacity) : minimum_capacity_(minimum_capacity) {} bool operator()(const std::vector& v) const { return v.capacity() >= minimum_capacity_; } private: size_t minimum_capacity_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_RENDER_QUEUE_ITEM_VERIFIER_H__ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/residual_echo_detector.cc0000664000175000017500000002127714475643423030200 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/residual_echo_detector.h" #include #include #include "absl/types/optional.h" #include "modules/audio_processing/audio_buffer.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/atomic_ops.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "system_wrappers/include/metrics.h" namespace { float Power(rtc::ArrayView input) { if (input.empty()) { return 0.f; } return std::inner_product(input.begin(), input.end(), input.begin(), 0.f) / input.size(); } constexpr size_t kLookbackFrames = 650; // TODO(ivoc): Verify the size of this buffer. constexpr size_t kRenderBufferSize = 30; constexpr float kAlpha = 0.001f; // 10 seconds of data, updated every 10 ms. constexpr size_t kAggregationBufferSize = 10 * 100; } // namespace namespace webrtc { int ResidualEchoDetector::instance_count_ = 0; ResidualEchoDetector::ResidualEchoDetector() : data_dumper_( new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), render_buffer_(kRenderBufferSize), render_power_(kLookbackFrames), render_power_mean_(kLookbackFrames), render_power_std_dev_(kLookbackFrames), covariances_(kLookbackFrames), recent_likelihood_max_(kAggregationBufferSize) {} ResidualEchoDetector::~ResidualEchoDetector() = default; void ResidualEchoDetector::AnalyzeRenderAudio( rtc::ArrayView render_audio) { // Dump debug data assuming 48 kHz sample rate (if this assumption is not // valid the dumped audio will need to be converted offline accordingly). data_dumper_->DumpWav("ed_render", render_audio.size(), render_audio.data(), 48000, 1); if (render_buffer_.Size() == 0) { frames_since_zero_buffer_size_ = 0; } else if (frames_since_zero_buffer_size_ >= kRenderBufferSize) { // This can happen in a few cases: at the start of a call, due to a glitch // or due to clock drift. The excess capture value will be ignored. // TODO(ivoc): Include how often this happens in APM stats. render_buffer_.Pop(); frames_since_zero_buffer_size_ = 0; } ++frames_since_zero_buffer_size_; float power = Power(render_audio); render_buffer_.Push(power); } void ResidualEchoDetector::AnalyzeCaptureAudio( rtc::ArrayView capture_audio) { // Dump debug data assuming 48 kHz sample rate (if this assumption is not // valid the dumped audio will need to be converted offline accordingly). data_dumper_->DumpWav("ed_capture", capture_audio.size(), capture_audio.data(), 48000, 1); if (first_process_call_) { // On the first process call (so the start of a call), we must flush the // render buffer, otherwise the render data will be delayed. render_buffer_.Clear(); first_process_call_ = false; } // Get the next render value. const absl::optional buffered_render_power = render_buffer_.Pop(); if (!buffered_render_power) { // This can happen in a few cases: at the start of a call, due to a glitch // or due to clock drift. The excess capture value will be ignored. // TODO(ivoc): Include how often this happens in APM stats. return; } // Update the render statistics, and store the statistics in circular buffers. render_statistics_.Update(*buffered_render_power); RTC_DCHECK_LT(next_insertion_index_, kLookbackFrames); render_power_[next_insertion_index_] = *buffered_render_power; render_power_mean_[next_insertion_index_] = render_statistics_.mean(); render_power_std_dev_[next_insertion_index_] = render_statistics_.std_deviation(); // Get the next capture value, update capture statistics and add the relevant // values to the buffers. const float capture_power = Power(capture_audio); capture_statistics_.Update(capture_power); const float capture_mean = capture_statistics_.mean(); const float capture_std_deviation = capture_statistics_.std_deviation(); // Update the covariance values and determine the new echo likelihood. echo_likelihood_ = 0.f; size_t read_index = next_insertion_index_; int best_delay = -1; for (size_t delay = 0; delay < covariances_.size(); ++delay) { RTC_DCHECK_LT(read_index, render_power_.size()); covariances_[delay].Update(capture_power, capture_mean, capture_std_deviation, render_power_[read_index], render_power_mean_[read_index], render_power_std_dev_[read_index]); read_index = read_index > 0 ? read_index - 1 : kLookbackFrames - 1; if (covariances_[delay].normalized_cross_correlation() > echo_likelihood_) { echo_likelihood_ = covariances_[delay].normalized_cross_correlation(); best_delay = static_cast(delay); } } // This is a temporary log message to help find the underlying cause for echo // likelihoods > 1.0. // TODO(ivoc): Remove once the issue is resolved. if (echo_likelihood_ > 1.1f) { // Make sure we don't spam the log. if (log_counter_ < 5 && best_delay != -1) { size_t read_index = kLookbackFrames + next_insertion_index_ - best_delay; if (read_index >= kLookbackFrames) { read_index -= kLookbackFrames; } RTC_DCHECK_LT(read_index, render_power_.size()); RTC_LOG_F(LS_ERROR) << "Echo detector internal state: {" "Echo likelihood: " << echo_likelihood_ << ", Best Delay: " << best_delay << ", Covariance: " << covariances_[best_delay].covariance() << ", Last capture power: " << capture_power << ", Capture mean: " << capture_mean << ", Capture_standard deviation: " << capture_std_deviation << ", Last render power: " << render_power_[read_index] << ", Render mean: " << render_power_mean_[read_index] << ", Render standard deviation: " << render_power_std_dev_[read_index] << ", Reliability: " << reliability_ << "}"; log_counter_++; } } RTC_DCHECK_LT(echo_likelihood_, 1.1f); reliability_ = (1.0f - kAlpha) * reliability_ + kAlpha * 1.0f; echo_likelihood_ *= reliability_; // This is a temporary fix to prevent echo likelihood values > 1.0. // TODO(ivoc): Find the root cause of this issue and fix it. echo_likelihood_ = std::min(echo_likelihood_, 1.0f); int echo_percentage = static_cast(echo_likelihood_ * 100); RTC_HISTOGRAM_COUNTS("WebRTC.Audio.ResidualEchoDetector.EchoLikelihood", echo_percentage, 0, 100, 100 /* number of bins */); // Update the buffer of recent likelihood values. recent_likelihood_max_.Update(echo_likelihood_); // Update the next insertion index. next_insertion_index_ = next_insertion_index_ < (kLookbackFrames - 1) ? next_insertion_index_ + 1 : 0; } void ResidualEchoDetector::Initialize(int /*capture_sample_rate_hz*/, int /*num_capture_channels*/, int /*render_sample_rate_hz*/, int /*num_render_channels*/) { render_buffer_.Clear(); std::fill(render_power_.begin(), render_power_.end(), 0.f); std::fill(render_power_mean_.begin(), render_power_mean_.end(), 0.f); std::fill(render_power_std_dev_.begin(), render_power_std_dev_.end(), 0.f); render_statistics_.Clear(); capture_statistics_.Clear(); recent_likelihood_max_.Clear(); for (auto& cov : covariances_) { cov.Clear(); } echo_likelihood_ = 0.f; next_insertion_index_ = 0; reliability_ = 0.f; } void EchoDetector::PackRenderAudioBuffer(AudioBuffer* audio, std::vector* packed_buffer) { packed_buffer->clear(); packed_buffer->insert(packed_buffer->end(), audio->channels()[0], audio->channels()[0] + audio->num_frames()); } EchoDetector::Metrics ResidualEchoDetector::GetMetrics() const { EchoDetector::Metrics metrics; metrics.echo_likelihood = echo_likelihood_; metrics.echo_likelihood_recent_max = recent_likelihood_max_.max(); return metrics; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/residual_echo_detector.h0000664000175000017500000000672714475643423030045 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_RESIDUAL_ECHO_DETECTOR_H_ #define MODULES_AUDIO_PROCESSING_RESIDUAL_ECHO_DETECTOR_H_ #include #include "api/array_view.h" #include "modules/audio_processing/echo_detector/circular_buffer.h" #include "modules/audio_processing/echo_detector/mean_variance_estimator.h" #include "modules/audio_processing/echo_detector/moving_max.h" #include "modules/audio_processing/echo_detector/normalized_covariance_estimator.h" #include "modules/audio_processing/include/audio_processing.h" namespace webrtc { class ApmDataDumper; class AudioBuffer; class ResidualEchoDetector : public EchoDetector { public: ResidualEchoDetector(); ~ResidualEchoDetector() override; // This function should be called while holding the render lock. void AnalyzeRenderAudio(rtc::ArrayView render_audio) override; // This function should be called while holding the capture lock. void AnalyzeCaptureAudio(rtc::ArrayView capture_audio) override; // This function should be called while holding the capture lock. void Initialize(int capture_sample_rate_hz, int num_capture_channels, int render_sample_rate_hz, int num_render_channels) override; // This function is for testing purposes only. void SetReliabilityForTest(float value) { reliability_ = value; } // This function should be called while holding the capture lock. EchoDetector::Metrics GetMetrics() const override; private: static int instance_count_; std::unique_ptr data_dumper_; // Keep track if the |Process| function has been previously called. bool first_process_call_ = true; // Buffer for storing the power of incoming farend buffers. This is needed for // cases where calls to BufferFarend and Process are jittery. CircularBuffer render_buffer_; // Count how long ago it was that the size of |render_buffer_| was zero. This // value is also reset to zero when clock drift is detected and a value from // the renderbuffer is discarded, even though the buffer is not actually zero // at that point. This is done to avoid repeatedly removing elements in this // situation. size_t frames_since_zero_buffer_size_ = 0; // Circular buffers containing delayed versions of the power, mean and // standard deviation, for calculating the delayed covariance values. std::vector render_power_; std::vector render_power_mean_; std::vector render_power_std_dev_; // Covariance estimates for different delay values. std::vector covariances_; // Index where next element should be inserted in all of the above circular // buffers. size_t next_insertion_index_ = 0; MeanVarianceEstimator render_statistics_; MeanVarianceEstimator capture_statistics_; // Current echo likelihood. float echo_likelihood_ = 0.f; // Reliability of the current likelihood. float reliability_ = 0.f; MovingMax recent_likelihood_max_; int log_counter_ = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_RESIDUAL_ECHO_DETECTOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/rms_level.cc0000664000175000017500000000722714475643423025470 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/rms_level.h" #include #include #include #include "rtc_base/checks.h" namespace webrtc { namespace { static constexpr float kMaxSquaredLevel = 32768 * 32768; // kMinLevel is the level corresponding to kMinLevelDb, that is 10^(-127/10). static constexpr float kMinLevel = 1.995262314968883e-13f; // Calculates the normalized RMS value from a mean square value. The input // should be the sum of squared samples divided by the number of samples. The // value will be normalized to full range before computing the RMS, wich is // returned as a negated dBfs. That is, 0 is full amplitude while 127 is very // faint. int ComputeRms(float mean_square) { if (mean_square <= kMinLevel * kMaxSquaredLevel) { // Very faint; simply return the minimum value. return RmsLevel::kMinLevelDb; } // Normalize by the max level. const float mean_square_norm = mean_square / kMaxSquaredLevel; RTC_DCHECK_GT(mean_square_norm, kMinLevel); // 20log_10(x^0.5) = 10log_10(x) const float rms = 10.f * std::log10(mean_square_norm); RTC_DCHECK_LE(rms, 0.f); RTC_DCHECK_GT(rms, -RmsLevel::kMinLevelDb); // Return the negated value. return static_cast(-rms + 0.5f); } } // namespace RmsLevel::RmsLevel() { Reset(); } RmsLevel::~RmsLevel() = default; void RmsLevel::Reset() { sum_square_ = 0.f; sample_count_ = 0; max_sum_square_ = 0.f; block_size_ = absl::nullopt; } void RmsLevel::Analyze(rtc::ArrayView data) { if (data.empty()) { return; } CheckBlockSize(data.size()); const float sum_square = std::accumulate(data.begin(), data.end(), 0.f, [](float a, int16_t b) { return a + b * b; }); RTC_DCHECK_GE(sum_square, 0.f); sum_square_ += sum_square; sample_count_ += data.size(); max_sum_square_ = std::max(max_sum_square_, sum_square); } void RmsLevel::Analyze(rtc::ArrayView data) { if (data.empty()) { return; } CheckBlockSize(data.size()); float sum_square = 0.f; for (float data_k : data) { int16_t tmp = static_cast(std::min(std::max(data_k, -32768.f), 32767.f)); sum_square += tmp * tmp; } RTC_DCHECK_GE(sum_square, 0.f); sum_square_ += sum_square; sample_count_ += data.size(); max_sum_square_ = std::max(max_sum_square_, sum_square); } void RmsLevel::AnalyzeMuted(size_t length) { CheckBlockSize(length); sample_count_ += length; } int RmsLevel::Average() { int rms = (sample_count_ == 0) ? RmsLevel::kMinLevelDb : ComputeRms(sum_square_ / sample_count_); Reset(); return rms; } RmsLevel::Levels RmsLevel::AverageAndPeak() { // Note that block_size_ should by design always be non-empty when // sample_count_ != 0. Also, the * operator of absl::optional enforces this // with a DCHECK. Levels levels = (sample_count_ == 0) ? Levels{RmsLevel::kMinLevelDb, RmsLevel::kMinLevelDb} : Levels{ComputeRms(sum_square_ / sample_count_), ComputeRms(max_sum_square_ / *block_size_)}; Reset(); return levels; } void RmsLevel::CheckBlockSize(size_t block_size) { if (block_size_ != block_size) { Reset(); block_size_ = block_size; } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/rms_level.h0000664000175000017500000000471114475643423025325 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_RMS_LEVEL_H_ #define MODULES_AUDIO_PROCESSING_RMS_LEVEL_H_ #include #include #include "absl/types/optional.h" #include "api/array_view.h" namespace webrtc { // Computes the root mean square (RMS) level in dBFs (decibels from digital // full-scale) of audio data. The computation follows RFC 6465: // https://tools.ietf.org/html/rfc6465 // with the intent that it can provide the RTP audio level indication. // // The expected approach is to provide constant-sized chunks of audio to // Analyze(). When enough chunks have been accumulated to form a packet, call // Average() to get the audio level indicator for the RTP header. class RmsLevel { public: struct Levels { int average; int peak; }; enum : int { kMinLevelDb = 127 }; RmsLevel(); ~RmsLevel(); // Can be called to reset internal states, but is not required during normal // operation. void Reset(); // Pass each chunk of audio to Analyze() to accumulate the level. void Analyze(rtc::ArrayView data); void Analyze(rtc::ArrayView data); // If all samples with the given |length| have a magnitude of zero, this is // a shortcut to avoid some computation. void AnalyzeMuted(size_t length); // Computes the RMS level over all data passed to Analyze() since the last // call to Average(). The returned value is positive but should be interpreted // as negative as per the RFC. It is constrained to [0, 127]. Resets the // internal state to start a new measurement period. int Average(); // Like Average() above, but also returns the RMS peak value. Resets the // internal state to start a new measurement period. Levels AverageAndPeak(); private: // Compares |block_size| with |block_size_|. If they are different, calls // Reset() and stores the new size. void CheckBlockSize(size_t block_size); float sum_square_; size_t sample_count_; float max_sum_square_; absl::optional block_size_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_RMS_LEVEL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/splitting_filter.cc0000664000175000017500000001447114475643423027061 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/splitting_filter.h" #include #include "api/array_view.h" #include "common_audio/channel_buffer.h" #include "common_audio/signal_processing/include/signal_processing_library.h" #include "rtc_base/checks.h" namespace webrtc { namespace { constexpr size_t kSamplesPerBand = 160; constexpr size_t kTwoBandFilterSamplesPerFrame = 320; } // namespace SplittingFilter::SplittingFilter(size_t num_channels, size_t num_bands, size_t num_frames) : num_bands_(num_bands), two_bands_states_(num_bands_ == 2 ? num_channels : 0), three_band_filter_banks_(num_bands_ == 3 ? num_channels : 0) { RTC_CHECK(num_bands_ == 2 || num_bands_ == 3); } SplittingFilter::~SplittingFilter() = default; void SplittingFilter::Analysis(const ChannelBuffer* data, ChannelBuffer* bands) { RTC_DCHECK_EQ(num_bands_, bands->num_bands()); RTC_DCHECK_EQ(data->num_channels(), bands->num_channels()); RTC_DCHECK_EQ(data->num_frames(), bands->num_frames_per_band() * bands->num_bands()); if (bands->num_bands() == 2) { TwoBandsAnalysis(data, bands); } else if (bands->num_bands() == 3) { ThreeBandsAnalysis(data, bands); } } void SplittingFilter::Synthesis(const ChannelBuffer* bands, ChannelBuffer* data) { RTC_DCHECK_EQ(num_bands_, bands->num_bands()); RTC_DCHECK_EQ(data->num_channels(), bands->num_channels()); RTC_DCHECK_EQ(data->num_frames(), bands->num_frames_per_band() * bands->num_bands()); if (bands->num_bands() == 2) { TwoBandsSynthesis(bands, data); } else if (bands->num_bands() == 3) { ThreeBandsSynthesis(bands, data); } } void SplittingFilter::TwoBandsAnalysis(const ChannelBuffer* data, ChannelBuffer* bands) { RTC_DCHECK_EQ(two_bands_states_.size(), data->num_channels()); RTC_DCHECK_EQ(data->num_frames(), kTwoBandFilterSamplesPerFrame); for (size_t i = 0; i < two_bands_states_.size(); ++i) { std::array, 2> bands16; std::array full_band16; FloatS16ToS16(data->channels(0)[i], full_band16.size(), full_band16.data()); WebRtcSpl_AnalysisQMF(full_band16.data(), data->num_frames(), bands16[0].data(), bands16[1].data(), two_bands_states_[i].analysis_state1, two_bands_states_[i].analysis_state2); S16ToFloatS16(bands16[0].data(), bands16[0].size(), bands->channels(0)[i]); S16ToFloatS16(bands16[1].data(), bands16[1].size(), bands->channels(1)[i]); } } void SplittingFilter::TwoBandsSynthesis(const ChannelBuffer* bands, ChannelBuffer* data) { RTC_DCHECK_LE(data->num_channels(), two_bands_states_.size()); RTC_DCHECK_EQ(data->num_frames(), kTwoBandFilterSamplesPerFrame); for (size_t i = 0; i < data->num_channels(); ++i) { std::array, 2> bands16; std::array full_band16; FloatS16ToS16(bands->channels(0)[i], bands16[0].size(), bands16[0].data()); FloatS16ToS16(bands->channels(1)[i], bands16[1].size(), bands16[1].data()); WebRtcSpl_SynthesisQMF(bands16[0].data(), bands16[1].data(), bands->num_frames_per_band(), full_band16.data(), two_bands_states_[i].synthesis_state1, two_bands_states_[i].synthesis_state2); S16ToFloatS16(full_band16.data(), full_band16.size(), data->channels(0)[i]); } } void SplittingFilter::ThreeBandsAnalysis(const ChannelBuffer* data, ChannelBuffer* bands) { RTC_DCHECK_EQ(three_band_filter_banks_.size(), data->num_channels()); RTC_DCHECK_LE(data->num_channels(), three_band_filter_banks_.size()); RTC_DCHECK_LE(data->num_channels(), bands->num_channels()); RTC_DCHECK_EQ(data->num_frames(), ThreeBandFilterBank::kFullBandSize); RTC_DCHECK_EQ(bands->num_frames(), ThreeBandFilterBank::kFullBandSize); RTC_DCHECK_EQ(bands->num_bands(), ThreeBandFilterBank::kNumBands); RTC_DCHECK_EQ(bands->num_frames_per_band(), ThreeBandFilterBank::kSplitBandSize); for (size_t i = 0; i < three_band_filter_banks_.size(); ++i) { three_band_filter_banks_[i].Analysis( rtc::ArrayView( data->channels_view()[i].data(), ThreeBandFilterBank::kFullBandSize), rtc::ArrayView, ThreeBandFilterBank::kNumBands>( bands->bands_view(i).data(), ThreeBandFilterBank::kNumBands)); } } void SplittingFilter::ThreeBandsSynthesis(const ChannelBuffer* bands, ChannelBuffer* data) { RTC_DCHECK_LE(data->num_channels(), three_band_filter_banks_.size()); RTC_DCHECK_LE(data->num_channels(), bands->num_channels()); RTC_DCHECK_LE(data->num_channels(), three_band_filter_banks_.size()); RTC_DCHECK_EQ(data->num_frames(), ThreeBandFilterBank::kFullBandSize); RTC_DCHECK_EQ(bands->num_frames(), ThreeBandFilterBank::kFullBandSize); RTC_DCHECK_EQ(bands->num_bands(), ThreeBandFilterBank::kNumBands); RTC_DCHECK_EQ(bands->num_frames_per_band(), ThreeBandFilterBank::kSplitBandSize); for (size_t i = 0; i < data->num_channels(); ++i) { three_band_filter_banks_[i].Synthesis( rtc::ArrayView, ThreeBandFilterBank::kNumBands>( bands->bands_view(i).data(), ThreeBandFilterBank::kNumBands), rtc::ArrayView( data->channels_view()[i].data(), ThreeBandFilterBank::kFullBandSize)); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/splitting_filter.h0000664000175000017500000000512114475643423026713 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_SPLITTING_FILTER_H_ #define MODULES_AUDIO_PROCESSING_SPLITTING_FILTER_H_ #include #include #include #include "common_audio/channel_buffer.h" #include "modules/audio_processing/three_band_filter_bank.h" namespace webrtc { struct TwoBandsStates { TwoBandsStates() { memset(analysis_state1, 0, sizeof(analysis_state1)); memset(analysis_state2, 0, sizeof(analysis_state2)); memset(synthesis_state1, 0, sizeof(synthesis_state1)); memset(synthesis_state2, 0, sizeof(synthesis_state2)); } static const int kStateSize = 6; int analysis_state1[kStateSize]; int analysis_state2[kStateSize]; int synthesis_state1[kStateSize]; int synthesis_state2[kStateSize]; }; // Splitting filter which is able to split into and merge from 2 or 3 frequency // bands. The number of channels needs to be provided at construction time. // // For each block, Analysis() is called to split into bands and then Synthesis() // to merge these bands again. The input and output signals are contained in // ChannelBuffers and for the different bands an array of ChannelBuffers is // used. class SplittingFilter { public: SplittingFilter(size_t num_channels, size_t num_bands, size_t num_frames); ~SplittingFilter(); void Analysis(const ChannelBuffer* data, ChannelBuffer* bands); void Synthesis(const ChannelBuffer* bands, ChannelBuffer* data); private: // Two-band analysis and synthesis work for 640 samples or less. void TwoBandsAnalysis(const ChannelBuffer* data, ChannelBuffer* bands); void TwoBandsSynthesis(const ChannelBuffer* bands, ChannelBuffer* data); void ThreeBandsAnalysis(const ChannelBuffer* data, ChannelBuffer* bands); void ThreeBandsSynthesis(const ChannelBuffer* bands, ChannelBuffer* data); void InitBuffers(); const size_t num_bands_; std::vector two_bands_states_; std::vector three_band_filter_banks_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_SPLITTING_FILTER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/three_band_filter_bank.cc0000664000175000017500000002601714475643423030131 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // An implementation of a 3-band FIR filter-bank with DCT modulation, similar to // the proposed in "Multirate Signal Processing for Communication Systems" by // Fredric J Harris. // // The idea is to take a heterodyne system and change the order of the // components to get something which is efficient to implement digitally. // // It is possible to separate the filter using the noble identity as follows: // // H(z) = H0(z^3) + z^-1 * H1(z^3) + z^-2 * H2(z^3) // // This is used in the analysis stage to first downsample serial to parallel // and then filter each branch with one of these polyphase decompositions of the // lowpass prototype. Because each filter is only a modulation of the prototype, // it is enough to multiply each coefficient by the respective cosine value to // shift it to the desired band. But because the cosine period is 12 samples, // it requires separating the prototype even further using the noble identity. // After filtering and modulating for each band, the output of all filters is // accumulated to get the downsampled bands. // // A similar logic can be applied to the synthesis stage. #include "modules/audio_processing/three_band_filter_bank.h" #include #include "rtc_base/checks.h" namespace webrtc { namespace { // Factors to take into account when choosing |kFilterSize|: // 1. Higher |kFilterSize|, means faster transition, which ensures less // aliasing. This is especially important when there is non-linear // processing between the splitting and merging. // 2. The delay that this filter bank introduces is // |kNumBands| * |kSparsity| * |kFilterSize| / 2, so it increases linearly // with |kFilterSize|. // 3. The computation complexity also increases linearly with |kFilterSize|. // The Matlab code to generate these |kFilterCoeffs| is: // // N = kNumBands * kSparsity * kFilterSize - 1; // h = fir1(N, 1 / (2 * kNumBands), kaiser(N + 1, 3.5)); // reshape(h, kNumBands * kSparsity, kFilterSize); // // The code below uses the values of kFilterSize, kNumBands and kSparsity // specified in the header. // Because the total bandwidth of the lower and higher band is double the middle // one (because of the spectrum parity), the low-pass prototype is half the // bandwidth of 1 / (2 * |kNumBands|) and is then shifted with cosine modulation // to the right places. // A Kaiser window is used because of its flexibility and the alpha is set to // 3.5, since that sets a stop band attenuation of 40dB ensuring a fast // transition. constexpr int kSubSampling = ThreeBandFilterBank::kNumBands; constexpr int kDctSize = ThreeBandFilterBank::kNumBands; static_assert(ThreeBandFilterBank::kNumBands * ThreeBandFilterBank::kSplitBandSize == ThreeBandFilterBank::kFullBandSize, "The full band must be split in equally sized subbands"); const float kFilterCoeffs[ThreeBandFilterBank::kNumNonZeroFilters][kFilterSize] = { {-0.00047749f, -0.00496888f, +0.16547118f, +0.00425496f}, {-0.00173287f, -0.01585778f, +0.14989004f, +0.00994113f}, {-0.00304815f, -0.02536082f, +0.12154542f, +0.01157993f}, {-0.00346946f, -0.02587886f, +0.04760441f, +0.00607594f}, {-0.00154717f, -0.01136076f, +0.01387458f, +0.00186353f}, {+0.00186353f, +0.01387458f, -0.01136076f, -0.00154717f}, {+0.00607594f, +0.04760441f, -0.02587886f, -0.00346946f}, {+0.00983212f, +0.08543175f, -0.02982767f, -0.00383509f}, {+0.00994113f, +0.14989004f, -0.01585778f, -0.00173287f}, {+0.00425496f, +0.16547118f, -0.00496888f, -0.00047749f}}; constexpr int kZeroFilterIndex1 = 3; constexpr int kZeroFilterIndex2 = 9; const float kDctModulation[ThreeBandFilterBank::kNumNonZeroFilters][kDctSize] = {{2.f, 2.f, 2.f}, {1.73205077f, 0.f, -1.73205077f}, {1.f, -2.f, 1.f}, {-1.f, 2.f, -1.f}, {-1.73205077f, 0.f, 1.73205077f}, {-2.f, -2.f, -2.f}, {-1.73205077f, 0.f, 1.73205077f}, {-1.f, 2.f, -1.f}, {1.f, -2.f, 1.f}, {1.73205077f, 0.f, -1.73205077f}}; // Filters the input signal |in| with the filter |filter| using a shift by // |in_shift|, taking into account the previous state. void FilterCore( rtc::ArrayView filter, rtc::ArrayView in, const int in_shift, rtc::ArrayView out, rtc::ArrayView state) { constexpr int kMaxInShift = (kStride - 1); RTC_DCHECK_GE(in_shift, 0); RTC_DCHECK_LE(in_shift, kMaxInShift); std::fill(out.begin(), out.end(), 0.f); for (int k = 0; k < in_shift; ++k) { for (int i = 0, j = kMemorySize + k - in_shift; i < kFilterSize; ++i, j -= kStride) { out[k] += state[j] * filter[i]; } } for (int k = in_shift, shift = 0; k < kFilterSize * kStride; ++k, ++shift) { RTC_DCHECK_GE(shift, 0); const int loop_limit = std::min(kFilterSize, 1 + (shift >> kStrideLog2)); for (int i = 0, j = shift; i < loop_limit; ++i, j -= kStride) { out[k] += in[j] * filter[i]; } for (int i = loop_limit, j = kMemorySize + shift - loop_limit * kStride; i < kFilterSize; ++i, j -= kStride) { out[k] += state[j] * filter[i]; } } for (int k = kFilterSize * kStride, shift = kFilterSize * kStride - in_shift; k < ThreeBandFilterBank::kSplitBandSize; ++k, ++shift) { for (int i = 0, j = shift; i < kFilterSize; ++i, j -= kStride) { out[k] += in[j] * filter[i]; } } // Update current state. std::copy(in.begin() + ThreeBandFilterBank::kSplitBandSize - kMemorySize, in.end(), state.begin()); } } // namespace // Because the low-pass filter prototype has half bandwidth it is possible to // use a DCT to shift it in both directions at the same time, to the center // frequencies [1 / 12, 3 / 12, 5 / 12]. ThreeBandFilterBank::ThreeBandFilterBank() { RTC_DCHECK_EQ(state_analysis_.size(), kNumNonZeroFilters); RTC_DCHECK_EQ(state_synthesis_.size(), kNumNonZeroFilters); for (int k = 0; k < kNumNonZeroFilters; ++k) { RTC_DCHECK_EQ(state_analysis_[k].size(), kMemorySize); RTC_DCHECK_EQ(state_synthesis_[k].size(), kMemorySize); state_analysis_[k].fill(0.f); state_synthesis_[k].fill(0.f); } } ThreeBandFilterBank::~ThreeBandFilterBank() = default; // The analysis can be separated in these steps: // 1. Serial to parallel downsampling by a factor of |kNumBands|. // 2. Filtering of |kSparsity| different delayed signals with polyphase // decomposition of the low-pass prototype filter and upsampled by a factor // of |kSparsity|. // 3. Modulating with cosines and accumulating to get the desired band. void ThreeBandFilterBank::Analysis( rtc::ArrayView in, rtc::ArrayView, ThreeBandFilterBank::kNumBands> out) { // Initialize the output to zero. for (int band = 0; band < ThreeBandFilterBank::kNumBands; ++band) { RTC_DCHECK_EQ(out[band].size(), kSplitBandSize); std::fill(out[band].begin(), out[band].end(), 0); } for (int downsampling_index = 0; downsampling_index < kSubSampling; ++downsampling_index) { // Downsample to form the filter input. std::array in_subsampled; for (int k = 0; k < kSplitBandSize; ++k) { in_subsampled[k] = in[(kSubSampling - 1) - downsampling_index + kSubSampling * k]; } for (int in_shift = 0; in_shift < kStride; ++in_shift) { // Choose filter, skip zero filters. const int index = downsampling_index + in_shift * kSubSampling; if (index == kZeroFilterIndex1 || index == kZeroFilterIndex2) { continue; } const int filter_index = index < kZeroFilterIndex1 ? index : (index < kZeroFilterIndex2 ? index - 1 : index - 2); rtc::ArrayView filter( kFilterCoeffs[filter_index]); rtc::ArrayView dct_modulation( kDctModulation[filter_index]); rtc::ArrayView state(state_analysis_[filter_index]); // Filter. std::array out_subsampled; FilterCore(filter, in_subsampled, in_shift, out_subsampled, state); // Band and modulate the output. for (int band = 0; band < ThreeBandFilterBank::kNumBands; ++band) { for (int n = 0; n < kSplitBandSize; ++n) { out[band][n] += dct_modulation[band] * out_subsampled[n]; } } } } } // The synthesis can be separated in these steps: // 1. Modulating with cosines. // 2. Filtering each one with a polyphase decomposition of the low-pass // prototype filter upsampled by a factor of |kSparsity| and accumulating // |kSparsity| signals with different delays. // 3. Parallel to serial upsampling by a factor of |kNumBands|. void ThreeBandFilterBank::Synthesis( rtc::ArrayView, ThreeBandFilterBank::kNumBands> in, rtc::ArrayView out) { std::fill(out.begin(), out.end(), 0); for (int upsampling_index = 0; upsampling_index < kSubSampling; ++upsampling_index) { for (int in_shift = 0; in_shift < kStride; ++in_shift) { // Choose filter, skip zero filters. const int index = upsampling_index + in_shift * kSubSampling; if (index == kZeroFilterIndex1 || index == kZeroFilterIndex2) { continue; } const int filter_index = index < kZeroFilterIndex1 ? index : (index < kZeroFilterIndex2 ? index - 1 : index - 2); rtc::ArrayView filter( kFilterCoeffs[filter_index]); rtc::ArrayView dct_modulation( kDctModulation[filter_index]); rtc::ArrayView state(state_synthesis_[filter_index]); // Prepare filter input by modulating the banded input. std::array in_subsampled; std::fill(in_subsampled.begin(), in_subsampled.end(), 0.f); for (int band = 0; band < ThreeBandFilterBank::kNumBands; ++band) { RTC_DCHECK_EQ(in[band].size(), kSplitBandSize); for (int n = 0; n < kSplitBandSize; ++n) { in_subsampled[n] += dct_modulation[band] * in[band][n]; } } // Filter. std::array out_subsampled; FilterCore(filter, in_subsampled, in_shift, out_subsampled, state); // Upsample. constexpr float kUpsamplingScaling = kSubSampling; for (int k = 0; k < kSplitBandSize; ++k) { out[upsampling_index + kSubSampling * k] += kUpsamplingScaling * out_subsampled[k]; } } } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/three_band_filter_bank.h0000664000175000017500000000550314475643423027770 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_THREE_BAND_FILTER_BANK_H_ #define MODULES_AUDIO_PROCESSING_THREE_BAND_FILTER_BANK_H_ #include #include #include #include #include "api/array_view.h" namespace webrtc { constexpr int kSparsity = 4; constexpr int kStrideLog2 = 2; constexpr int kStride = 1 << kStrideLog2; constexpr int kNumZeroFilters = 2; constexpr int kFilterSize = 4; constexpr int kMemorySize = kFilterSize * kStride - 1; static_assert(kMemorySize == 15, "The memory size must be sufficient to provide memory for the " "shifted filters"); // An implementation of a 3-band FIR filter-bank with DCT modulation, similar to // the proposed in "Multirate Signal Processing for Communication Systems" by // Fredric J Harris. // The low-pass filter prototype has these characteristics: // * Pass-band ripple = 0.3dB // * Pass-band frequency = 0.147 (7kHz at 48kHz) // * Stop-band attenuation = 40dB // * Stop-band frequency = 0.192 (9.2kHz at 48kHz) // * Delay = 24 samples (500us at 48kHz) // * Linear phase // This filter bank does not satisfy perfect reconstruction. The SNR after // analysis and synthesis (with no processing in between) is approximately 9.5dB // depending on the input signal after compensating for the delay. class ThreeBandFilterBank final { public: static const int kNumBands = 3; static const int kFullBandSize = 480; static const int kSplitBandSize = ThreeBandFilterBank::kFullBandSize / ThreeBandFilterBank::kNumBands; static const int kNumNonZeroFilters = kSparsity * ThreeBandFilterBank::kNumBands - kNumZeroFilters; ThreeBandFilterBank(); ~ThreeBandFilterBank(); // Splits |in| of size kFullBandSize into 3 downsampled frequency bands in // |out|, each of size 160. void Analysis(rtc::ArrayView in, rtc::ArrayView, kNumBands> out); // Merges the 3 downsampled frequency bands in |in|, each of size 160, into // |out|, which is of size kFullBandSize. void Synthesis(rtc::ArrayView, kNumBands> in, rtc::ArrayView out); private: std::array, kNumNonZeroFilters> state_analysis_; std::array, kNumNonZeroFilters> state_synthesis_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_THREE_BAND_FILTER_BANK_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/0000775000175000017500000000000014475643423025170 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/BUILD.gn0000664000175000017500000000603714475643423026363 0ustar00arunarun# Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../../../webrtc.gni") rtc_source_set("transient_suppressor_api") { sources = [ "transient_suppressor.h" ] } rtc_library("transient_suppressor_impl") { visibility = [ "..:optionally_built_submodule_creators", ":transient_suppression_test", ":transient_suppression_unittests", ":click_annotate", ] sources = [ "common.h", "daubechies_8_wavelet_coeffs.h", "dyadic_decimator.h", "moving_moments.cc", "moving_moments.h", "transient_detector.cc", "transient_detector.h", "transient_suppressor_impl.cc", "transient_suppressor_impl.h", "windows_private.h", "wpd_node.cc", "wpd_node.h", "wpd_tree.cc", "wpd_tree.h", ] deps = [ ":transient_suppressor_api", "../../../common_audio:common_audio", "../../../common_audio:common_audio_c", "../../../common_audio:fir_filter", "../../../common_audio:fir_filter_factory", "../../../common_audio/third_party/ooura:fft_size_256", "../../../rtc_base:checks", "../../../rtc_base:gtest_prod", "../../../rtc_base:logging", ] } if (rtc_include_tests) { rtc_executable("click_annotate") { testonly = true sources = [ "click_annotate.cc", "file_utils.cc", "file_utils.h", ] deps = [ ":transient_suppressor_impl", "..:audio_processing", "../../../rtc_base/system:file_wrapper", "../../../system_wrappers", ] } rtc_executable("transient_suppression_test") { testonly = true sources = [ "file_utils.cc", "file_utils.h", "transient_suppression_test.cc", ] deps = [ ":transient_suppressor_impl", "..:audio_processing", "../../../common_audio", "../../../rtc_base:rtc_base_approved", "../../../rtc_base/system:file_wrapper", "../../../system_wrappers", "../../../test:fileutils", "../../../test:test_support", "../agc:level_estimation", "//testing/gtest", "//third_party/abseil-cpp/absl/flags:flag", "//third_party/abseil-cpp/absl/flags:parse", ] } rtc_library("transient_suppression_unittests") { testonly = true sources = [ "dyadic_decimator_unittest.cc", "file_utils.cc", "file_utils.h", "file_utils_unittest.cc", "moving_moments_unittest.cc", "transient_detector_unittest.cc", "transient_suppressor_unittest.cc", "wpd_node_unittest.cc", "wpd_tree_unittest.cc", ] deps = [ ":transient_suppressor_impl", "../../../rtc_base:stringutils", "../../../rtc_base/system:file_wrapper", "../../../test:fileutils", "../../../test:test_support", "//testing/gtest", ] } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/click_annotate.cc0000664000175000017500000000673114475643423030464 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include #include #include #include #include #include "modules/audio_processing/transient/file_utils.h" #include "modules/audio_processing/transient/transient_detector.h" #include "rtc_base/system/file_wrapper.h" using webrtc::FileWrapper; using webrtc::TransientDetector; // Application to generate a RTP timing file. // Opens the PCM file and divides the signal in frames. // Creates a send times array, one for each step. // Each block that contains a transient, has an infinite send time. // The resultant array is written to a DAT file // Returns -1 on error or |lost_packets| otherwise. int main(int argc, char* argv[]) { if (argc != 5) { printf("\n%s - Application to generate a RTP timing file.\n\n", argv[0]); printf("%s PCMfile DATfile chunkSize sampleRate\n\n", argv[0]); printf("Opens the PCMfile with sampleRate in Hertz.\n"); printf("Creates a send times array, one for each chunkSize "); printf("milliseconds step.\n"); printf("Each block that contains a transient, has an infinite send time. "); printf("The resultant array is written to a DATfile.\n\n"); return 0; } FileWrapper pcm_file = FileWrapper::OpenReadOnly(argv[1]); if (!pcm_file.is_open()) { printf("\nThe %s could not be opened.\n\n", argv[1]); return -1; } FileWrapper dat_file = FileWrapper::OpenWriteOnly(argv[2]); if (!dat_file.is_open()) { printf("\nThe %s could not be opened.\n\n", argv[2]); return -1; } int chunk_size_ms = atoi(argv[3]); if (chunk_size_ms <= 0) { printf("\nThe chunkSize must be a positive integer\n\n"); return -1; } int sample_rate_hz = atoi(argv[4]); if (sample_rate_hz <= 0) { printf("\nThe sampleRate must be a positive integer\n\n"); return -1; } TransientDetector detector(sample_rate_hz); int lost_packets = 0; size_t audio_buffer_length = chunk_size_ms * sample_rate_hz / 1000; std::unique_ptr audio_buffer(new float[audio_buffer_length]); std::vector send_times; // Read first buffer from the PCM test file. size_t file_samples_read = ReadInt16FromFileToFloatBuffer( &pcm_file, audio_buffer_length, audio_buffer.get()); for (int time = 0; file_samples_read > 0; time += chunk_size_ms) { // Pad the rest of the buffer with zeros. for (size_t i = file_samples_read; i < audio_buffer_length; ++i) { audio_buffer[i] = 0.0; } float value = detector.Detect(audio_buffer.get(), audio_buffer_length, NULL, 0); if (value < 0.5f) { value = time; } else { value = FLT_MAX; ++lost_packets; } send_times.push_back(value); // Read next buffer from the PCM test file. file_samples_read = ReadInt16FromFileToFloatBuffer( &pcm_file, audio_buffer_length, audio_buffer.get()); } size_t floats_written = WriteFloatBufferToFile(&dat_file, send_times.size(), &send_times[0]); if (floats_written == 0) { printf("\nThe send times could not be written to DAT file\n\n"); return -1; } pcm_file.Close(); dat_file.Close(); return lost_packets; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/common.h0000664000175000017500000000153314475643423026633 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_COMMON_H_ #define MODULES_AUDIO_PROCESSING_TRANSIENT_COMMON_H_ namespace webrtc { namespace ts { static const float kPi = 3.14159265358979323846f; static const int kChunkSizeMs = 10; enum { kSampleRate8kHz = 8000, kSampleRate16kHz = 16000, kSampleRate32kHz = 32000, kSampleRate48kHz = 48000 }; } // namespace ts } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_TRANSIENT_COMMON_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h0000664000175000017500000000401114475643423032734 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // This header file defines the coefficients of the FIR based approximation of // the Meyer Wavelet #ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_DAUBECHIES_8_WAVELET_COEFFS_H_ #define MODULES_AUDIO_PROCESSING_TRANSIENT_DAUBECHIES_8_WAVELET_COEFFS_H_ // Decomposition coefficients Daubechies 8. namespace webrtc { const int kDaubechies8CoefficientsLength = 16; const float kDaubechies8HighPassCoefficients[kDaubechies8CoefficientsLength] = { -5.44158422430816093862e-02f, 3.12871590914465924627e-01f, -6.75630736298012846142e-01f, 5.85354683654869090148e-01f, 1.58291052560238926228e-02f, -2.84015542962428091389e-01f, -4.72484573997972536787e-04f, 1.28747426620186011803e-01f, 1.73693010020221083600e-02f, -4.40882539310647192377e-02f, -1.39810279170155156436e-02f, 8.74609404701565465445e-03f, 4.87035299301066034600e-03f, -3.91740372995977108837e-04f, -6.75449405998556772109e-04f, -1.17476784002281916305e-04f}; const float kDaubechies8LowPassCoefficients[kDaubechies8CoefficientsLength] = { -1.17476784002281916305e-04f, 6.75449405998556772109e-04f, -3.91740372995977108837e-04f, -4.87035299301066034600e-03f, 8.74609404701565465445e-03f, 1.39810279170155156436e-02f, -4.40882539310647192377e-02f, -1.73693010020221083600e-02f, 1.28747426620186011803e-01f, 4.72484573997972536787e-04f, -2.84015542962428091389e-01f, -1.58291052560238926228e-02f, 5.85354683654869090148e-01f, 6.75630736298012846142e-01f, 3.12871590914465924627e-01f, 5.44158422430816093862e-02f}; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_TRANSIENT_DAUBECHIES_8_WAVELET_COEFFS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/dyadic_decimator.h0000664000175000017500000000455514475643423030636 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_DYADIC_DECIMATOR_H_ #define MODULES_AUDIO_PROCESSING_TRANSIENT_DYADIC_DECIMATOR_H_ #include // Provides a set of static methods to perform dyadic decimations. namespace webrtc { // Returns the proper length of the output buffer that you should use for the // given |in_length| and decimation |odd_sequence|. // Return -1 on error. inline size_t GetOutLengthToDyadicDecimate(size_t in_length, bool odd_sequence) { size_t out_length = in_length / 2; if (in_length % 2 == 1 && !odd_sequence) { ++out_length; } return out_length; } // Performs a dyadic decimation: removes every odd/even member of a sequence // halving its overall length. // Arguments: // in: array of |in_length|. // odd_sequence: If false, the odd members will be removed (1, 3, 5, ...); // if true, the even members will be removed (0, 2, 4, ...). // out: array of |out_length|. |out_length| must be large enough to // hold the decimated output. The necessary length can be provided by // GetOutLengthToDyadicDecimate(). // Must be previously allocated. // Returns the number of output samples, -1 on error. template static size_t DyadicDecimate(const T* in, size_t in_length, bool odd_sequence, T* out, size_t out_length) { size_t half_length = GetOutLengthToDyadicDecimate(in_length, odd_sequence); if (!in || !out || in_length <= 0 || out_length < half_length) { return 0; } size_t output_samples = 0; size_t index_adjustment = odd_sequence ? 1 : 0; for (output_samples = 0; output_samples < half_length; ++output_samples) { out[output_samples] = in[output_samples * 2 + index_adjustment]; } return output_samples; } } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_TRANSIENT_DYADIC_DECIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/file_utils.cc0000664000175000017500000001410514475643423027637 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/transient/file_utils.h" #include #include "rtc_base/system/file_wrapper.h" namespace webrtc { int ConvertByteArrayToFloat(const uint8_t bytes[4], float* out) { if (!bytes || !out) { return -1; } uint32_t binary_value = 0; for (int i = 3; i >= 0; --i) { binary_value <<= 8; binary_value += bytes[i]; } *out = bit_cast(binary_value); return 0; } int ConvertByteArrayToDouble(const uint8_t bytes[8], double* out) { if (!bytes || !out) { return -1; } uint64_t binary_value = 0; for (int i = 7; i >= 0; --i) { binary_value <<= 8; binary_value += bytes[i]; } *out = bit_cast(binary_value); return 0; } int ConvertFloatToByteArray(float value, uint8_t out_bytes[4]) { if (!out_bytes) { return -1; } uint32_t binary_value = bit_cast(value); for (size_t i = 0; i < 4; ++i) { out_bytes[i] = binary_value; binary_value >>= 8; } return 0; } int ConvertDoubleToByteArray(double value, uint8_t out_bytes[8]) { if (!out_bytes) { return -1; } uint64_t binary_value = bit_cast(value); for (size_t i = 0; i < 8; ++i) { out_bytes[i] = binary_value; binary_value >>= 8; } return 0; } size_t ReadInt16BufferFromFile(FileWrapper* file, size_t length, int16_t* buffer) { if (!file || !file->is_open() || !buffer || length <= 0) { return 0; } std::unique_ptr byte_array(new uint8_t[2]); size_t int16s_read = 0; while (int16s_read < length) { size_t bytes_read = file->Read(byte_array.get(), 2); if (bytes_read < 2) { break; } int16_t value = byte_array[1]; value <<= 8; value += byte_array[0]; buffer[int16s_read] = value; ++int16s_read; } return int16s_read; } size_t ReadInt16FromFileToFloatBuffer(FileWrapper* file, size_t length, float* buffer) { if (!file || !file->is_open() || !buffer || length <= 0) { return 0; } std::unique_ptr buffer16(new int16_t[length]); size_t int16s_read = ReadInt16BufferFromFile(file, length, buffer16.get()); for (size_t i = 0; i < int16s_read; ++i) { buffer[i] = buffer16[i]; } return int16s_read; } size_t ReadInt16FromFileToDoubleBuffer(FileWrapper* file, size_t length, double* buffer) { if (!file || !file->is_open() || !buffer || length <= 0) { return 0; } std::unique_ptr buffer16(new int16_t[length]); size_t int16s_read = ReadInt16BufferFromFile(file, length, buffer16.get()); for (size_t i = 0; i < int16s_read; ++i) { buffer[i] = buffer16[i]; } return int16s_read; } size_t ReadFloatBufferFromFile(FileWrapper* file, size_t length, float* buffer) { if (!file || !file->is_open() || !buffer || length <= 0) { return 0; } std::unique_ptr byte_array(new uint8_t[4]); size_t floats_read = 0; while (floats_read < length) { size_t bytes_read = file->Read(byte_array.get(), 4); if (bytes_read < 4) { break; } ConvertByteArrayToFloat(byte_array.get(), &buffer[floats_read]); ++floats_read; } return floats_read; } size_t ReadDoubleBufferFromFile(FileWrapper* file, size_t length, double* buffer) { if (!file || !file->is_open() || !buffer || length <= 0) { return 0; } std::unique_ptr byte_array(new uint8_t[8]); size_t doubles_read = 0; while (doubles_read < length) { size_t bytes_read = file->Read(byte_array.get(), 8); if (bytes_read < 8) { break; } ConvertByteArrayToDouble(byte_array.get(), &buffer[doubles_read]); ++doubles_read; } return doubles_read; } size_t WriteInt16BufferToFile(FileWrapper* file, size_t length, const int16_t* buffer) { if (!file || !file->is_open() || !buffer || length <= 0) { return 0; } std::unique_ptr byte_array(new uint8_t[2]); size_t int16s_written = 0; for (int16s_written = 0; int16s_written < length; ++int16s_written) { // Get byte representation. byte_array[0] = buffer[int16s_written] & 0xFF; byte_array[1] = (buffer[int16s_written] >> 8) & 0xFF; file->Write(byte_array.get(), 2); } file->Flush(); return int16s_written; } size_t WriteFloatBufferToFile(FileWrapper* file, size_t length, const float* buffer) { if (!file || !file->is_open() || !buffer || length <= 0) { return 0; } std::unique_ptr byte_array(new uint8_t[4]); size_t floats_written = 0; for (floats_written = 0; floats_written < length; ++floats_written) { // Get byte representation. ConvertFloatToByteArray(buffer[floats_written], byte_array.get()); file->Write(byte_array.get(), 4); } file->Flush(); return floats_written; } size_t WriteDoubleBufferToFile(FileWrapper* file, size_t length, const double* buffer) { if (!file || !file->is_open() || !buffer || length <= 0) { return 0; } std::unique_ptr byte_array(new uint8_t[8]); size_t doubles_written = 0; for (doubles_written = 0; doubles_written < length; ++doubles_written) { // Get byte representation. ConvertDoubleToByteArray(buffer[doubles_written], byte_array.get()); file->Write(byte_array.get(), 8); } file->Flush(); return doubles_written; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/file_utils.h0000664000175000017500000001143514475643423027504 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_FILE_UTILS_H_ #define MODULES_AUDIO_PROCESSING_TRANSIENT_FILE_UTILS_H_ #include #include #include "rtc_base/system/file_wrapper.h" namespace webrtc { // This is a copy of the cast included in the Chromium codebase here: // http://cs.chromium.org/src/third_party/cld/base/casts.h template inline Dest bit_cast(const Source& source) { // A compile error here means your Dest and Source have different sizes. static_assert(sizeof(Dest) == sizeof(Source), "Dest and Source have different sizes"); Dest dest; memcpy(&dest, &source, sizeof(dest)); return dest; } // Converts the byte array with binary float representation to float. // Bytes must be in little-endian order. // Returns 0 if correct, -1 on error. int ConvertByteArrayToFloat(const uint8_t bytes[4], float* out); // Converts the byte array with binary double representation to double. // Bytes must be in little-endian order. // Returns 0 if correct, -1 on error. int ConvertByteArrayToDouble(const uint8_t bytes[8], double* out); // Converts a float to a byte array with binary float representation. // Bytes will be in little-endian order. // Returns 0 if correct, -1 on error. int ConvertFloatToByteArray(float value, uint8_t out_bytes[4]); // Converts a double to a byte array with binary double representation. // Bytes will be in little-endian order. // Returns 0 if correct, -1 on error. int ConvertDoubleToByteArray(double value, uint8_t out_bytes[8]); // Reads |length| 16-bit integers from |file| to |buffer|. // |file| must be previously opened. // Returns the number of 16-bit integers read or -1 on error. size_t ReadInt16BufferFromFile(FileWrapper* file, size_t length, int16_t* buffer); // Reads |length| 16-bit integers from |file| and stores those values // (converting them) in |buffer|. // |file| must be previously opened. // Returns the number of 16-bit integers read or -1 on error. size_t ReadInt16FromFileToFloatBuffer(FileWrapper* file, size_t length, float* buffer); // Reads |length| 16-bit integers from |file| and stores those values // (converting them) in |buffer|. // |file| must be previously opened. // Returns the number of 16-bit integers read or -1 on error. size_t ReadInt16FromFileToDoubleBuffer(FileWrapper* file, size_t length, double* buffer); // Reads |length| floats in binary representation (4 bytes) from |file| to // |buffer|. // |file| must be previously opened. // Returns the number of floats read or -1 on error. size_t ReadFloatBufferFromFile(FileWrapper* file, size_t length, float* buffer); // Reads |length| doubles in binary representation (8 bytes) from |file| to // |buffer|. // |file| must be previously opened. // Returns the number of doubles read or -1 on error. size_t ReadDoubleBufferFromFile(FileWrapper* file, size_t length, double* buffer); // Writes |length| 16-bit integers from |buffer| in binary representation (2 // bytes) to |file|. It flushes |file|, so after this call there are no // writings pending. // |file| must be previously opened. // Returns the number of doubles written or -1 on error. size_t WriteInt16BufferToFile(FileWrapper* file, size_t length, const int16_t* buffer); // Writes |length| floats from |buffer| in binary representation (4 bytes) to // |file|. It flushes |file|, so after this call there are no writtings pending. // |file| must be previously opened. // Returns the number of doubles written or -1 on error. size_t WriteFloatBufferToFile(FileWrapper* file, size_t length, const float* buffer); // Writes |length| doubles from |buffer| in binary representation (8 bytes) to // |file|. It flushes |file|, so after this call there are no writings pending. // |file| must be previously opened. // Returns the number of doubles written or -1 on error. size_t WriteDoubleBufferToFile(FileWrapper* file, size_t length, const double* buffer); } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_TRANSIENT_FILE_UTILS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/moving_moments.cc0000664000175000017500000000264314475643423030545 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/transient/moving_moments.h" #include #include "rtc_base/checks.h" namespace webrtc { MovingMoments::MovingMoments(size_t length) : length_(length), queue_(), sum_(0.0), sum_of_squares_(0.0) { RTC_DCHECK_GT(length, 0); for (size_t i = 0; i < length; ++i) { queue_.push(0.0); } } MovingMoments::~MovingMoments() {} void MovingMoments::CalculateMoments(const float* in, size_t in_length, float* first, float* second) { RTC_DCHECK(in); RTC_DCHECK_GT(in_length, 0); RTC_DCHECK(first); RTC_DCHECK(second); for (size_t i = 0; i < in_length; ++i) { const float old_value = queue_.front(); queue_.pop(); queue_.push(in[i]); sum_ += in[i] - old_value; sum_of_squares_ += in[i] * in[i] - old_value * old_value; first[i] = sum_ / length_; second[i] = std::max(0.f, sum_of_squares_ / length_); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/moving_moments.h0000664000175000017500000000362314475643423030406 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_MOVING_MOMENTS_H_ #define MODULES_AUDIO_PROCESSING_TRANSIENT_MOVING_MOMENTS_H_ #include #include namespace webrtc { // Calculates the first and second moments for each value of a buffer taking // into account a given number of previous values. // It preserves its state, so it can be multiple-called. // TODO(chadan): Implement a function that takes a buffer of first moments and a // buffer of second moments; and calculates the variances. When needed. // TODO(chadan): Add functionality to update with a buffer but only output are // the last values of the moments. When needed. class MovingMoments { public: // Creates a Moving Moments object, that uses the last |length| values // (including the new value introduced in every new calculation). explicit MovingMoments(size_t length); ~MovingMoments(); // Calculates the new values using |in|. Results will be in the out buffers. // |first| and |second| must be allocated with at least |in_length|. void CalculateMoments(const float* in, size_t in_length, float* first, float* second); private: size_t length_; // A queue holding the |length_| latest input values. std::queue queue_; // Sum of the values of the queue. float sum_; // Sum of the squares of the values of the queue. float sum_of_squares_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_TRANSIENT_MOVING_MOMENTS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/transient_detector.cc0000664000175000017500000001445614475643423031411 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/transient/transient_detector.h" #include #include #include #include #include "modules/audio_processing/transient/common.h" #include "modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h" #include "modules/audio_processing/transient/moving_moments.h" #include "modules/audio_processing/transient/wpd_node.h" #include "modules/audio_processing/transient/wpd_tree.h" #include "rtc_base/checks.h" namespace webrtc { static const int kTransientLengthMs = 30; static const int kChunksAtStartupLeftToDelete = kTransientLengthMs / ts::kChunkSizeMs; static const float kDetectThreshold = 16.f; TransientDetector::TransientDetector(int sample_rate_hz) : samples_per_chunk_(sample_rate_hz * ts::kChunkSizeMs / 1000), last_first_moment_(), last_second_moment_(), chunks_at_startup_left_to_delete_(kChunksAtStartupLeftToDelete), reference_energy_(1.f), using_reference_(false) { RTC_DCHECK(sample_rate_hz == ts::kSampleRate8kHz || sample_rate_hz == ts::kSampleRate16kHz || sample_rate_hz == ts::kSampleRate32kHz || sample_rate_hz == ts::kSampleRate48kHz); int samples_per_transient = sample_rate_hz * kTransientLengthMs / 1000; // Adjustment to avoid data loss while downsampling, making // |samples_per_chunk_| and |samples_per_transient| always divisible by // |kLeaves|. samples_per_chunk_ -= samples_per_chunk_ % kLeaves; samples_per_transient -= samples_per_transient % kLeaves; tree_leaves_data_length_ = samples_per_chunk_ / kLeaves; wpd_tree_.reset(new WPDTree(samples_per_chunk_, kDaubechies8HighPassCoefficients, kDaubechies8LowPassCoefficients, kDaubechies8CoefficientsLength, kLevels)); for (size_t i = 0; i < kLeaves; ++i) { moving_moments_[i].reset( new MovingMoments(samples_per_transient / kLeaves)); } first_moments_.reset(new float[tree_leaves_data_length_]); second_moments_.reset(new float[tree_leaves_data_length_]); for (int i = 0; i < kChunksAtStartupLeftToDelete; ++i) { previous_results_.push_back(0.f); } } TransientDetector::~TransientDetector() {} float TransientDetector::Detect(const float* data, size_t data_length, const float* reference_data, size_t reference_length) { RTC_DCHECK(data); RTC_DCHECK_EQ(samples_per_chunk_, data_length); // TODO(aluebs): Check if these errors can logically happen and if not assert // on them. if (wpd_tree_->Update(data, samples_per_chunk_) != 0) { return -1.f; } float result = 0.f; for (size_t i = 0; i < kLeaves; ++i) { WPDNode* leaf = wpd_tree_->NodeAt(kLevels, i); moving_moments_[i]->CalculateMoments(leaf->data(), tree_leaves_data_length_, first_moments_.get(), second_moments_.get()); // Add value delayed (Use the last moments from the last call to Detect). float unbiased_data = leaf->data()[0] - last_first_moment_[i]; result += unbiased_data * unbiased_data / (last_second_moment_[i] + FLT_MIN); // Add new values. for (size_t j = 1; j < tree_leaves_data_length_; ++j) { unbiased_data = leaf->data()[j] - first_moments_[j - 1]; result += unbiased_data * unbiased_data / (second_moments_[j - 1] + FLT_MIN); } last_first_moment_[i] = first_moments_[tree_leaves_data_length_ - 1]; last_second_moment_[i] = second_moments_[tree_leaves_data_length_ - 1]; } result /= tree_leaves_data_length_; result *= ReferenceDetectionValue(reference_data, reference_length); if (chunks_at_startup_left_to_delete_ > 0) { chunks_at_startup_left_to_delete_--; result = 0.f; } if (result >= kDetectThreshold) { result = 1.f; } else { // Get proportional value. // Proportion achieved with a squared raised cosine function with domain // [0, kDetectThreshold) and image [0, 1), it's always increasing. const float horizontal_scaling = ts::kPi / kDetectThreshold; const float kHorizontalShift = ts::kPi; const float kVerticalScaling = 0.5f; const float kVerticalShift = 1.f; result = (std::cos(result * horizontal_scaling + kHorizontalShift) + kVerticalShift) * kVerticalScaling; result *= result; } previous_results_.pop_front(); previous_results_.push_back(result); // In the current implementation we return the max of the current result and // the previous results, so the high results have a width equals to // |transient_length|. return *std::max_element(previous_results_.begin(), previous_results_.end()); } // Looks for the highest slope and compares it with the previous ones. // An exponential transformation takes this to the [0, 1] range. This value is // multiplied by the detection result to avoid false positives. float TransientDetector::ReferenceDetectionValue(const float* data, size_t length) { if (data == NULL) { using_reference_ = false; return 1.f; } static const float kEnergyRatioThreshold = 0.2f; static const float kReferenceNonLinearity = 20.f; static const float kMemory = 0.99f; float reference_energy = 0.f; for (size_t i = 1; i < length; ++i) { reference_energy += data[i] * data[i]; } if (reference_energy == 0.f) { using_reference_ = false; return 1.f; } RTC_DCHECK_NE(0, reference_energy_); float result = 1.f / (1.f + std::exp(kReferenceNonLinearity * (kEnergyRatioThreshold - reference_energy / reference_energy_))); reference_energy_ = kMemory * reference_energy_ + (1.f - kMemory) * reference_energy; using_reference_ = true; return result; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/transient_detector.h0000664000175000017500000000602414475643423031243 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_DETECTOR_H_ #define MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_DETECTOR_H_ #include #include #include #include "modules/audio_processing/transient/moving_moments.h" #include "modules/audio_processing/transient/wpd_tree.h" namespace webrtc { // This is an implementation of the transient detector described in "Causal // Wavelet based transient detector". // Calculates the log-likelihood of a transient to happen on a signal at any // given time based on the previous samples; it uses a WPD tree to analyze the // signal. It preserves its state, so it can be multiple-called. class TransientDetector { public: // TODO(chadan): The only supported wavelet is Daubechies 8 using a WPD tree // of 3 levels. Make an overloaded constructor to allow different wavelets and // depths of the tree. When needed. // Creates a wavelet based transient detector. TransientDetector(int sample_rate_hz); ~TransientDetector(); // Calculates the log-likelihood of the existence of a transient in |data|. // |data_length| has to be equal to |samples_per_chunk_|. // Returns a value between 0 and 1, as a non linear representation of this // likelihood. // Returns a negative value on error. float Detect(const float* data, size_t data_length, const float* reference_data, size_t reference_length); bool using_reference() { return using_reference_; } private: float ReferenceDetectionValue(const float* data, size_t length); static const size_t kLevels = 3; static const size_t kLeaves = 1 << kLevels; size_t samples_per_chunk_; std::unique_ptr wpd_tree_; size_t tree_leaves_data_length_; // A MovingMoments object is needed for each leaf in the WPD tree. std::unique_ptr moving_moments_[kLeaves]; std::unique_ptr first_moments_; std::unique_ptr second_moments_; // Stores the last calculated moments from the previous detection. float last_first_moment_[kLeaves]; float last_second_moment_[kLeaves]; // We keep track of the previous results from the previous chunks, so it can // be used to effectively give results according to the |transient_length|. std::deque previous_results_; // Number of chunks that are going to return only zeros at the beginning of // the detection. It helps to avoid infs and nans due to the lack of // information. int chunks_at_startup_left_to_delete_; float reference_energy_; bool using_reference_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_DETECTOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/transient_suppressor.h0000664000175000017500000000506114475643423031657 0ustar00arunarun/* * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_H_ #define MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_H_ #include #include #include namespace webrtc { // Detects transients in an audio stream and suppress them using a simple // restoration algorithm that attenuates unexpected spikes in the spectrum. class TransientSuppressor { public: virtual ~TransientSuppressor() {} virtual int Initialize(int sample_rate_hz, int detector_rate_hz, int num_channels) = 0; // Processes a |data| chunk, and returns it with keystrokes suppressed from // it. The float format is assumed to be int16 ranged. If there are more than // one channel, the chunks are concatenated one after the other in |data|. // |data_length| must be equal to |data_length_|. // |num_channels| must be equal to |num_channels_|. // A sub-band, ideally the higher, can be used as |detection_data|. If it is // NULL, |data| is used for the detection too. The |detection_data| is always // assumed mono. // If a reference signal (e.g. keyboard microphone) is available, it can be // passed in as |reference_data|. It is assumed mono and must have the same // length as |data|. NULL is accepted if unavailable. // This suppressor performs better if voice information is available. // |voice_probability| is the probability of voice being present in this chunk // of audio. If voice information is not available, |voice_probability| must // always be set to 1. // |key_pressed| determines if a key was pressed on this audio chunk. // Returns 0 on success and -1 otherwise. virtual int Suppress(float* data, size_t data_length, int num_channels, const float* detection_data, size_t detection_length, const float* reference_data, size_t reference_length, float voice_probability, bool key_pressed) = 0; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/transient_suppressor_impl.cc0000664000175000017500000003603114475643423033037 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/transient/transient_suppressor_impl.h" #include #include #include #include #include #include #include #include "common_audio/include/audio_util.h" #include "common_audio/signal_processing/include/signal_processing_library.h" #include "common_audio/third_party/ooura/fft_size_256/fft4g.h" #include "modules/audio_processing/transient/common.h" #include "modules/audio_processing/transient/transient_detector.h" #include "modules/audio_processing/transient/transient_suppressor.h" #include "modules/audio_processing/transient/windows_private.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" namespace webrtc { static const float kMeanIIRCoefficient = 0.5f; static const float kVoiceThreshold = 0.02f; // TODO(aluebs): Check if these values work also for 48kHz. static const size_t kMinVoiceBin = 3; static const size_t kMaxVoiceBin = 60; namespace { float ComplexMagnitude(float a, float b) { return std::abs(a) + std::abs(b); } } // namespace TransientSuppressorImpl::TransientSuppressorImpl() : data_length_(0), detection_length_(0), analysis_length_(0), buffer_delay_(0), complex_analysis_length_(0), num_channels_(0), window_(NULL), detector_smoothed_(0.f), keypress_counter_(0), chunks_since_keypress_(0), detection_enabled_(false), suppression_enabled_(false), use_hard_restoration_(false), chunks_since_voice_change_(0), seed_(182), using_reference_(false) {} TransientSuppressorImpl::~TransientSuppressorImpl() {} int TransientSuppressorImpl::Initialize(int sample_rate_hz, int detection_rate_hz, int num_channels) { switch (sample_rate_hz) { case ts::kSampleRate8kHz: analysis_length_ = 128u; window_ = kBlocks80w128; break; case ts::kSampleRate16kHz: analysis_length_ = 256u; window_ = kBlocks160w256; break; case ts::kSampleRate32kHz: analysis_length_ = 512u; window_ = kBlocks320w512; break; case ts::kSampleRate48kHz: analysis_length_ = 1024u; window_ = kBlocks480w1024; break; default: return -1; } if (detection_rate_hz != ts::kSampleRate8kHz && detection_rate_hz != ts::kSampleRate16kHz && detection_rate_hz != ts::kSampleRate32kHz && detection_rate_hz != ts::kSampleRate48kHz) { return -1; } if (num_channels <= 0) { return -1; } detector_.reset(new TransientDetector(detection_rate_hz)); data_length_ = sample_rate_hz * ts::kChunkSizeMs / 1000; if (data_length_ > analysis_length_) { RTC_NOTREACHED(); return -1; } buffer_delay_ = analysis_length_ - data_length_; complex_analysis_length_ = analysis_length_ / 2 + 1; RTC_DCHECK_GE(complex_analysis_length_, kMaxVoiceBin); num_channels_ = num_channels; in_buffer_.reset(new float[analysis_length_ * num_channels_]); memset(in_buffer_.get(), 0, analysis_length_ * num_channels_ * sizeof(in_buffer_[0])); detection_length_ = detection_rate_hz * ts::kChunkSizeMs / 1000; detection_buffer_.reset(new float[detection_length_]); memset(detection_buffer_.get(), 0, detection_length_ * sizeof(detection_buffer_[0])); out_buffer_.reset(new float[analysis_length_ * num_channels_]); memset(out_buffer_.get(), 0, analysis_length_ * num_channels_ * sizeof(out_buffer_[0])); // ip[0] must be zero to trigger initialization using rdft(). size_t ip_length = 2 + sqrtf(analysis_length_); ip_.reset(new size_t[ip_length]()); memset(ip_.get(), 0, ip_length * sizeof(ip_[0])); wfft_.reset(new float[complex_analysis_length_ - 1]); memset(wfft_.get(), 0, (complex_analysis_length_ - 1) * sizeof(wfft_[0])); spectral_mean_.reset(new float[complex_analysis_length_ * num_channels_]); memset(spectral_mean_.get(), 0, complex_analysis_length_ * num_channels_ * sizeof(spectral_mean_[0])); fft_buffer_.reset(new float[analysis_length_ + 2]); memset(fft_buffer_.get(), 0, (analysis_length_ + 2) * sizeof(fft_buffer_[0])); magnitudes_.reset(new float[complex_analysis_length_]); memset(magnitudes_.get(), 0, complex_analysis_length_ * sizeof(magnitudes_[0])); mean_factor_.reset(new float[complex_analysis_length_]); static const float kFactorHeight = 10.f; static const float kLowSlope = 1.f; static const float kHighSlope = 0.3f; for (size_t i = 0; i < complex_analysis_length_; ++i) { mean_factor_[i] = kFactorHeight / (1.f + std::exp(kLowSlope * static_cast(i - kMinVoiceBin))) + kFactorHeight / (1.f + std::exp(kHighSlope * static_cast(kMaxVoiceBin - i))); } detector_smoothed_ = 0.f; keypress_counter_ = 0; chunks_since_keypress_ = 0; detection_enabled_ = false; suppression_enabled_ = false; use_hard_restoration_ = false; chunks_since_voice_change_ = 0; seed_ = 182; using_reference_ = false; return 0; } int TransientSuppressorImpl::Suppress(float* data, size_t data_length, int num_channels, const float* detection_data, size_t detection_length, const float* reference_data, size_t reference_length, float voice_probability, bool key_pressed) { if (!data || data_length != data_length_ || num_channels != num_channels_ || detection_length != detection_length_ || voice_probability < 0 || voice_probability > 1) { return -1; } UpdateKeypress(key_pressed); UpdateBuffers(data); int result = 0; if (detection_enabled_) { UpdateRestoration(voice_probability); if (!detection_data) { // Use the input data of the first channel if special detection data is // not supplied. detection_data = &in_buffer_[buffer_delay_]; } float detector_result = detector_->Detect(detection_data, detection_length, reference_data, reference_length); if (detector_result < 0) { return -1; } using_reference_ = detector_->using_reference(); // |detector_smoothed_| follows the |detector_result| when this last one is // increasing, but has an exponential decaying tail to be able to suppress // the ringing of keyclicks. float smooth_factor = using_reference_ ? 0.6 : 0.1; detector_smoothed_ = detector_result >= detector_smoothed_ ? detector_result : smooth_factor * detector_smoothed_ + (1 - smooth_factor) * detector_result; for (int i = 0; i < num_channels_; ++i) { Suppress(&in_buffer_[i * analysis_length_], &spectral_mean_[i * complex_analysis_length_], &out_buffer_[i * analysis_length_]); } } // If the suppression isn't enabled, we use the in buffer to delay the signal // appropriately. This also gives time for the out buffer to be refreshed with // new data between detection and suppression getting enabled. for (int i = 0; i < num_channels_; ++i) { memcpy(&data[i * data_length_], suppression_enabled_ ? &out_buffer_[i * analysis_length_] : &in_buffer_[i * analysis_length_], data_length_ * sizeof(*data)); } return result; } // This should only be called when detection is enabled. UpdateBuffers() must // have been called. At return, |out_buffer_| will be filled with the // processed output. void TransientSuppressorImpl::Suppress(float* in_ptr, float* spectral_mean, float* out_ptr) { // Go to frequency domain. for (size_t i = 0; i < analysis_length_; ++i) { // TODO(aluebs): Rename windows fft_buffer_[i] = in_ptr[i] * window_[i]; } WebRtc_rdft(analysis_length_, 1, fft_buffer_.get(), ip_.get(), wfft_.get()); // Since WebRtc_rdft puts R[n/2] in fft_buffer_[1], we move it to the end // for convenience. fft_buffer_[analysis_length_] = fft_buffer_[1]; fft_buffer_[analysis_length_ + 1] = 0.f; fft_buffer_[1] = 0.f; for (size_t i = 0; i < complex_analysis_length_; ++i) { magnitudes_[i] = ComplexMagnitude(fft_buffer_[i * 2], fft_buffer_[i * 2 + 1]); } // Restore audio if necessary. if (suppression_enabled_) { if (use_hard_restoration_) { HardRestoration(spectral_mean); } else { SoftRestoration(spectral_mean); } } // Update the spectral mean. for (size_t i = 0; i < complex_analysis_length_; ++i) { spectral_mean[i] = (1 - kMeanIIRCoefficient) * spectral_mean[i] + kMeanIIRCoefficient * magnitudes_[i]; } // Back to time domain. // Put R[n/2] back in fft_buffer_[1]. fft_buffer_[1] = fft_buffer_[analysis_length_]; WebRtc_rdft(analysis_length_, -1, fft_buffer_.get(), ip_.get(), wfft_.get()); const float fft_scaling = 2.f / analysis_length_; for (size_t i = 0; i < analysis_length_; ++i) { out_ptr[i] += fft_buffer_[i] * window_[i] * fft_scaling; } } void TransientSuppressorImpl::UpdateKeypress(bool key_pressed) { const int kKeypressPenalty = 1000 / ts::kChunkSizeMs; const int kIsTypingThreshold = 1000 / ts::kChunkSizeMs; const int kChunksUntilNotTyping = 4000 / ts::kChunkSizeMs; // 4 seconds. if (key_pressed) { keypress_counter_ += kKeypressPenalty; chunks_since_keypress_ = 0; detection_enabled_ = true; } keypress_counter_ = std::max(0, keypress_counter_ - 1); if (keypress_counter_ > kIsTypingThreshold) { if (!suppression_enabled_) { RTC_LOG(LS_INFO) << "[ts] Transient suppression is now enabled."; } suppression_enabled_ = true; keypress_counter_ = 0; } if (detection_enabled_ && ++chunks_since_keypress_ > kChunksUntilNotTyping) { if (suppression_enabled_) { RTC_LOG(LS_INFO) << "[ts] Transient suppression is now disabled."; } detection_enabled_ = false; suppression_enabled_ = false; keypress_counter_ = 0; } } void TransientSuppressorImpl::UpdateRestoration(float voice_probability) { const int kHardRestorationOffsetDelay = 3; const int kHardRestorationOnsetDelay = 80; bool not_voiced = voice_probability < kVoiceThreshold; if (not_voiced == use_hard_restoration_) { chunks_since_voice_change_ = 0; } else { ++chunks_since_voice_change_; if ((use_hard_restoration_ && chunks_since_voice_change_ > kHardRestorationOffsetDelay) || (!use_hard_restoration_ && chunks_since_voice_change_ > kHardRestorationOnsetDelay)) { use_hard_restoration_ = not_voiced; chunks_since_voice_change_ = 0; } } } // Shift buffers to make way for new data. Must be called after // |detection_enabled_| is updated by UpdateKeypress(). void TransientSuppressorImpl::UpdateBuffers(float* data) { // TODO(aluebs): Change to ring buffer. memmove(in_buffer_.get(), &in_buffer_[data_length_], (buffer_delay_ + (num_channels_ - 1) * analysis_length_) * sizeof(in_buffer_[0])); // Copy new chunk to buffer. for (int i = 0; i < num_channels_; ++i) { memcpy(&in_buffer_[buffer_delay_ + i * analysis_length_], &data[i * data_length_], data_length_ * sizeof(*data)); } if (detection_enabled_) { // Shift previous chunk in out buffer. memmove(out_buffer_.get(), &out_buffer_[data_length_], (buffer_delay_ + (num_channels_ - 1) * analysis_length_) * sizeof(out_buffer_[0])); // Initialize new chunk in out buffer. for (int i = 0; i < num_channels_; ++i) { memset(&out_buffer_[buffer_delay_ + i * analysis_length_], 0, data_length_ * sizeof(out_buffer_[0])); } } } // Restores the unvoiced signal if a click is present. // Attenuates by a certain factor every peak in the |fft_buffer_| that exceeds // the spectral mean. The attenuation depends on |detector_smoothed_|. // If a restoration takes place, the |magnitudes_| are updated to the new value. void TransientSuppressorImpl::HardRestoration(float* spectral_mean) { const float detector_result = 1.f - std::pow(1.f - detector_smoothed_, using_reference_ ? 200.f : 50.f); // To restore, we get the peaks in the spectrum. If higher than the previous // spectral mean we adjust them. for (size_t i = 0; i < complex_analysis_length_; ++i) { if (magnitudes_[i] > spectral_mean[i] && magnitudes_[i] > 0) { // RandU() generates values on [0, int16::max()] const float phase = 2 * ts::kPi * WebRtcSpl_RandU(&seed_) / std::numeric_limits::max(); const float scaled_mean = detector_result * spectral_mean[i]; fft_buffer_[i * 2] = (1 - detector_result) * fft_buffer_[i * 2] + scaled_mean * cosf(phase); fft_buffer_[i * 2 + 1] = (1 - detector_result) * fft_buffer_[i * 2 + 1] + scaled_mean * sinf(phase); magnitudes_[i] = magnitudes_[i] - detector_result * (magnitudes_[i] - spectral_mean[i]); } } } // Restores the voiced signal if a click is present. // Attenuates by a certain factor every peak in the |fft_buffer_| that exceeds // the spectral mean and that is lower than some function of the current block // frequency mean. The attenuation depends on |detector_smoothed_|. // If a restoration takes place, the |magnitudes_| are updated to the new value. void TransientSuppressorImpl::SoftRestoration(float* spectral_mean) { // Get the spectral magnitude mean of the current block. float block_frequency_mean = 0; for (size_t i = kMinVoiceBin; i < kMaxVoiceBin; ++i) { block_frequency_mean += magnitudes_[i]; } block_frequency_mean /= (kMaxVoiceBin - kMinVoiceBin); // To restore, we get the peaks in the spectrum. If higher than the // previous spectral mean and lower than a factor of the block mean // we adjust them. The factor is a double sigmoid that has a minimum in the // voice frequency range (300Hz - 3kHz). for (size_t i = 0; i < complex_analysis_length_; ++i) { if (magnitudes_[i] > spectral_mean[i] && magnitudes_[i] > 0 && (using_reference_ || magnitudes_[i] < block_frequency_mean * mean_factor_[i])) { const float new_magnitude = magnitudes_[i] - detector_smoothed_ * (magnitudes_[i] - spectral_mean[i]); const float magnitude_ratio = new_magnitude / magnitudes_[i]; fft_buffer_[i * 2] *= magnitude_ratio; fft_buffer_[i * 2 + 1] *= magnitude_ratio; magnitudes_[i] = new_magnitude; } } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/transient_suppressor_impl.h0000664000175000017500000001013014475643423032671 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_IMPL_H_ #define MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_IMPL_H_ #include #include #include #include "modules/audio_processing/transient/transient_suppressor.h" #include "rtc_base/gtest_prod_util.h" namespace webrtc { class TransientDetector; // Detects transients in an audio stream and suppress them using a simple // restoration algorithm that attenuates unexpected spikes in the spectrum. class TransientSuppressorImpl : public TransientSuppressor { public: TransientSuppressorImpl(); ~TransientSuppressorImpl() override; int Initialize(int sample_rate_hz, int detector_rate_hz, int num_channels) override; // Processes a |data| chunk, and returns it with keystrokes suppressed from // it. The float format is assumed to be int16 ranged. If there are more than // one channel, the chunks are concatenated one after the other in |data|. // |data_length| must be equal to |data_length_|. // |num_channels| must be equal to |num_channels_|. // A sub-band, ideally the higher, can be used as |detection_data|. If it is // NULL, |data| is used for the detection too. The |detection_data| is always // assumed mono. // If a reference signal (e.g. keyboard microphone) is available, it can be // passed in as |reference_data|. It is assumed mono and must have the same // length as |data|. NULL is accepted if unavailable. // This suppressor performs better if voice information is available. // |voice_probability| is the probability of voice being present in this chunk // of audio. If voice information is not available, |voice_probability| must // always be set to 1. // |key_pressed| determines if a key was pressed on this audio chunk. // Returns 0 on success and -1 otherwise. int Suppress(float* data, size_t data_length, int num_channels, const float* detection_data, size_t detection_length, const float* reference_data, size_t reference_length, float voice_probability, bool key_pressed) override; private: FRIEND_TEST_ALL_PREFIXES(TransientSuppressorImplTest, TypingDetectionLogicWorksAsExpectedForMono); void Suppress(float* in_ptr, float* spectral_mean, float* out_ptr); void UpdateKeypress(bool key_pressed); void UpdateRestoration(float voice_probability); void UpdateBuffers(float* data); void HardRestoration(float* spectral_mean); void SoftRestoration(float* spectral_mean); std::unique_ptr detector_; size_t data_length_; size_t detection_length_; size_t analysis_length_; size_t buffer_delay_; size_t complex_analysis_length_; int num_channels_; // Input buffer where the original samples are stored. std::unique_ptr in_buffer_; std::unique_ptr detection_buffer_; // Output buffer where the restored samples are stored. std::unique_ptr out_buffer_; // Arrays for fft. std::unique_ptr ip_; std::unique_ptr wfft_; std::unique_ptr spectral_mean_; // Stores the data for the fft. std::unique_ptr fft_buffer_; std::unique_ptr magnitudes_; const float* window_; std::unique_ptr mean_factor_; float detector_smoothed_; int keypress_counter_; int chunks_since_keypress_; bool detection_enabled_; bool suppression_enabled_; bool use_hard_restoration_; int chunks_since_voice_change_; uint32_t seed_; bool using_reference_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_IMPL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/windows_private.h0000664000175000017500000011070714475643423030573 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_WINDOWS_PRIVATE_H_ #define MODULES_AUDIO_PROCESSING_TRANSIENT_WINDOWS_PRIVATE_H_ namespace webrtc { // Hanning window for 4ms 16kHz static const float kHanning64w128[128] = { 0.00000000000000f, 0.02454122852291f, 0.04906767432742f, 0.07356456359967f, 0.09801714032956f, 0.12241067519922f, 0.14673047445536f, 0.17096188876030f, 0.19509032201613f, 0.21910124015687f, 0.24298017990326f, 0.26671275747490f, 0.29028467725446f, 0.31368174039889f, 0.33688985339222f, 0.35989503653499f, 0.38268343236509f, 0.40524131400499f, 0.42755509343028f, 0.44961132965461f, 0.47139673682600f, 0.49289819222978f, 0.51410274419322f, 0.53499761988710f, 0.55557023301960f, 0.57580819141785f, 0.59569930449243f, 0.61523159058063f, 0.63439328416365f, 0.65317284295378f, 0.67155895484702f, 0.68954054473707f, 0.70710678118655f, 0.72424708295147f, 0.74095112535496f, 0.75720884650648f, 0.77301045336274f, 0.78834642762661f, 0.80320753148064f, 0.81758481315158f, 0.83146961230255f, 0.84485356524971f, 0.85772861000027f, 0.87008699110871f, 0.88192126434835f, 0.89322430119552f, 0.90398929312344f, 0.91420975570353f, 0.92387953251129f, 0.93299279883474f, 0.94154406518302f, 0.94952818059304f, 0.95694033573221f, 0.96377606579544f, 0.97003125319454f, 0.97570213003853f, 0.98078528040323f, 0.98527764238894f, 0.98917650996478f, 0.99247953459871f, 0.99518472667220f, 0.99729045667869f, 0.99879545620517f, 0.99969881869620f, 1.00000000000000f, 0.99969881869620f, 0.99879545620517f, 0.99729045667869f, 0.99518472667220f, 0.99247953459871f, 0.98917650996478f, 0.98527764238894f, 0.98078528040323f, 0.97570213003853f, 0.97003125319454f, 0.96377606579544f, 0.95694033573221f, 0.94952818059304f, 0.94154406518302f, 0.93299279883474f, 0.92387953251129f, 0.91420975570353f, 0.90398929312344f, 0.89322430119552f, 0.88192126434835f, 0.87008699110871f, 0.85772861000027f, 0.84485356524971f, 0.83146961230255f, 0.81758481315158f, 0.80320753148064f, 0.78834642762661f, 0.77301045336274f, 0.75720884650648f, 0.74095112535496f, 0.72424708295147f, 0.70710678118655f, 0.68954054473707f, 0.67155895484702f, 0.65317284295378f, 0.63439328416365f, 0.61523159058063f, 0.59569930449243f, 0.57580819141785f, 0.55557023301960f, 0.53499761988710f, 0.51410274419322f, 0.49289819222978f, 0.47139673682600f, 0.44961132965461f, 0.42755509343028f, 0.40524131400499f, 0.38268343236509f, 0.35989503653499f, 0.33688985339222f, 0.31368174039889f, 0.29028467725446f, 0.26671275747490f, 0.24298017990326f, 0.21910124015687f, 0.19509032201613f, 0.17096188876030f, 0.14673047445536f, 0.12241067519922f, 0.09801714032956f, 0.07356456359967f, 0.04906767432742f, 0.02454122852291f}; // hybrib Hanning & flat window static const float kBlocks80w128[128] = { 0.00000000f, 0.03271908f, 0.06540313f, 0.09801714f, 0.13052619f, 0.16289547f, 0.19509032f, 0.22707626f, 0.25881905f, 0.29028468f, 0.32143947f, 0.35225005f, 0.38268343f, 0.41270703f, 0.44228869f, 0.47139674f, 0.50000000f, 0.52806785f, 0.55557023f, 0.58247770f, 0.60876143f, 0.63439328f, 0.65934582f, 0.68359230f, 0.70710678f, 0.72986407f, 0.75183981f, 0.77301045f, 0.79335334f, 0.81284668f, 0.83146961f, 0.84920218f, 0.86602540f, 0.88192126f, 0.89687274f, 0.91086382f, 0.92387953f, 0.93590593f, 0.94693013f, 0.95694034f, 0.96592583f, 0.97387698f, 0.98078528f, 0.98664333f, 0.99144486f, 0.99518473f, 0.99785892f, 0.99946459f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 0.99946459f, 0.99785892f, 0.99518473f, 0.99144486f, 0.98664333f, 0.98078528f, 0.97387698f, 0.96592583f, 0.95694034f, 0.94693013f, 0.93590593f, 0.92387953f, 0.91086382f, 0.89687274f, 0.88192126f, 0.86602540f, 0.84920218f, 0.83146961f, 0.81284668f, 0.79335334f, 0.77301045f, 0.75183981f, 0.72986407f, 0.70710678f, 0.68359230f, 0.65934582f, 0.63439328f, 0.60876143f, 0.58247770f, 0.55557023f, 0.52806785f, 0.50000000f, 0.47139674f, 0.44228869f, 0.41270703f, 0.38268343f, 0.35225005f, 0.32143947f, 0.29028468f, 0.25881905f, 0.22707626f, 0.19509032f, 0.16289547f, 0.13052619f, 0.09801714f, 0.06540313f, 0.03271908f}; // hybrib Hanning & flat window static const float kBlocks160w256[256] = { 0.00000000f, 0.01636173f, 0.03271908f, 0.04906767f, 0.06540313f, 0.08172107f, 0.09801714f, 0.11428696f, 0.13052619f, 0.14673047f, 0.16289547f, 0.17901686f, 0.19509032f, 0.21111155f, 0.22707626f, 0.24298018f, 0.25881905f, 0.27458862f, 0.29028468f, 0.30590302f, 0.32143947f, 0.33688985f, 0.35225005f, 0.36751594f, 0.38268343f, 0.39774847f, 0.41270703f, 0.42755509f, 0.44228869f, 0.45690388f, 0.47139674f, 0.48576339f, 0.50000000f, 0.51410274f, 0.52806785f, 0.54189158f, 0.55557023f, 0.56910015f, 0.58247770f, 0.59569930f, 0.60876143f, 0.62166057f, 0.63439328f, 0.64695615f, 0.65934582f, 0.67155895f, 0.68359230f, 0.69544264f, 0.70710678f, 0.71858162f, 0.72986407f, 0.74095113f, 0.75183981f, 0.76252720f, 0.77301045f, 0.78328675f, 0.79335334f, 0.80320753f, 0.81284668f, 0.82226822f, 0.83146961f, 0.84044840f, 0.84920218f, 0.85772861f, 0.86602540f, 0.87409034f, 0.88192126f, 0.88951608f, 0.89687274f, 0.90398929f, 0.91086382f, 0.91749450f, 0.92387953f, 0.93001722f, 0.93590593f, 0.94154407f, 0.94693013f, 0.95206268f, 0.95694034f, 0.96156180f, 0.96592583f, 0.97003125f, 0.97387698f, 0.97746197f, 0.98078528f, 0.98384601f, 0.98664333f, 0.98917651f, 0.99144486f, 0.99344778f, 0.99518473f, 0.99665524f, 0.99785892f, 0.99879546f, 0.99946459f, 0.99986614f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 0.99986614f, 0.99946459f, 0.99879546f, 0.99785892f, 0.99665524f, 0.99518473f, 0.99344778f, 0.99144486f, 0.98917651f, 0.98664333f, 0.98384601f, 0.98078528f, 0.97746197f, 0.97387698f, 0.97003125f, 0.96592583f, 0.96156180f, 0.95694034f, 0.95206268f, 0.94693013f, 0.94154407f, 0.93590593f, 0.93001722f, 0.92387953f, 0.91749450f, 0.91086382f, 0.90398929f, 0.89687274f, 0.88951608f, 0.88192126f, 0.87409034f, 0.86602540f, 0.85772861f, 0.84920218f, 0.84044840f, 0.83146961f, 0.82226822f, 0.81284668f, 0.80320753f, 0.79335334f, 0.78328675f, 0.77301045f, 0.76252720f, 0.75183981f, 0.74095113f, 0.72986407f, 0.71858162f, 0.70710678f, 0.69544264f, 0.68359230f, 0.67155895f, 0.65934582f, 0.64695615f, 0.63439328f, 0.62166057f, 0.60876143f, 0.59569930f, 0.58247770f, 0.56910015f, 0.55557023f, 0.54189158f, 0.52806785f, 0.51410274f, 0.50000000f, 0.48576339f, 0.47139674f, 0.45690388f, 0.44228869f, 0.42755509f, 0.41270703f, 0.39774847f, 0.38268343f, 0.36751594f, 0.35225005f, 0.33688985f, 0.32143947f, 0.30590302f, 0.29028468f, 0.27458862f, 0.25881905f, 0.24298018f, 0.22707626f, 0.21111155f, 0.19509032f, 0.17901686f, 0.16289547f, 0.14673047f, 0.13052619f, 0.11428696f, 0.09801714f, 0.08172107f, 0.06540313f, 0.04906767f, 0.03271908f, 0.01636173f}; // hybrib Hanning & flat window: for 20ms static const float kBlocks320w512[512] = { 0.00000000f, 0.00818114f, 0.01636173f, 0.02454123f, 0.03271908f, 0.04089475f, 0.04906767f, 0.05723732f, 0.06540313f, 0.07356456f, 0.08172107f, 0.08987211f, 0.09801714f, 0.10615561f, 0.11428696f, 0.12241068f, 0.13052619f, 0.13863297f, 0.14673047f, 0.15481816f, 0.16289547f, 0.17096189f, 0.17901686f, 0.18705985f, 0.19509032f, 0.20310773f, 0.21111155f, 0.21910124f, 0.22707626f, 0.23503609f, 0.24298018f, 0.25090801f, 0.25881905f, 0.26671276f, 0.27458862f, 0.28244610f, 0.29028468f, 0.29810383f, 0.30590302f, 0.31368174f, 0.32143947f, 0.32917568f, 0.33688985f, 0.34458148f, 0.35225005f, 0.35989504f, 0.36751594f, 0.37511224f, 0.38268343f, 0.39022901f, 0.39774847f, 0.40524131f, 0.41270703f, 0.42014512f, 0.42755509f, 0.43493645f, 0.44228869f, 0.44961133f, 0.45690388f, 0.46416584f, 0.47139674f, 0.47859608f, 0.48576339f, 0.49289819f, 0.50000000f, 0.50706834f, 0.51410274f, 0.52110274f, 0.52806785f, 0.53499762f, 0.54189158f, 0.54874927f, 0.55557023f, 0.56235401f, 0.56910015f, 0.57580819f, 0.58247770f, 0.58910822f, 0.59569930f, 0.60225052f, 0.60876143f, 0.61523159f, 0.62166057f, 0.62804795f, 0.63439328f, 0.64069616f, 0.64695615f, 0.65317284f, 0.65934582f, 0.66547466f, 0.67155895f, 0.67759830f, 0.68359230f, 0.68954054f, 0.69544264f, 0.70129818f, 0.70710678f, 0.71286806f, 0.71858162f, 0.72424708f, 0.72986407f, 0.73543221f, 0.74095113f, 0.74642045f, 0.75183981f, 0.75720885f, 0.76252720f, 0.76779452f, 0.77301045f, 0.77817464f, 0.78328675f, 0.78834643f, 0.79335334f, 0.79830715f, 0.80320753f, 0.80805415f, 0.81284668f, 0.81758481f, 0.82226822f, 0.82689659f, 0.83146961f, 0.83598698f, 0.84044840f, 0.84485357f, 0.84920218f, 0.85349396f, 0.85772861f, 0.86190585f, 0.86602540f, 0.87008699f, 0.87409034f, 0.87803519f, 0.88192126f, 0.88574831f, 0.88951608f, 0.89322430f, 0.89687274f, 0.90046115f, 0.90398929f, 0.90745693f, 0.91086382f, 0.91420976f, 0.91749450f, 0.92071783f, 0.92387953f, 0.92697940f, 0.93001722f, 0.93299280f, 0.93590593f, 0.93875641f, 0.94154407f, 0.94426870f, 0.94693013f, 0.94952818f, 0.95206268f, 0.95453345f, 0.95694034f, 0.95928317f, 0.96156180f, 0.96377607f, 0.96592583f, 0.96801094f, 0.97003125f, 0.97198664f, 0.97387698f, 0.97570213f, 0.97746197f, 0.97915640f, 0.98078528f, 0.98234852f, 0.98384601f, 0.98527764f, 0.98664333f, 0.98794298f, 0.98917651f, 0.99034383f, 0.99144486f, 0.99247953f, 0.99344778f, 0.99434953f, 0.99518473f, 0.99595331f, 0.99665524f, 0.99729046f, 0.99785892f, 0.99836060f, 0.99879546f, 0.99916346f, 0.99946459f, 0.99969882f, 0.99986614f, 0.99996653f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 0.99996653f, 0.99986614f, 0.99969882f, 0.99946459f, 0.99916346f, 0.99879546f, 0.99836060f, 0.99785892f, 0.99729046f, 0.99665524f, 0.99595331f, 0.99518473f, 0.99434953f, 0.99344778f, 0.99247953f, 0.99144486f, 0.99034383f, 0.98917651f, 0.98794298f, 0.98664333f, 0.98527764f, 0.98384601f, 0.98234852f, 0.98078528f, 0.97915640f, 0.97746197f, 0.97570213f, 0.97387698f, 0.97198664f, 0.97003125f, 0.96801094f, 0.96592583f, 0.96377607f, 0.96156180f, 0.95928317f, 0.95694034f, 0.95453345f, 0.95206268f, 0.94952818f, 0.94693013f, 0.94426870f, 0.94154407f, 0.93875641f, 0.93590593f, 0.93299280f, 0.93001722f, 0.92697940f, 0.92387953f, 0.92071783f, 0.91749450f, 0.91420976f, 0.91086382f, 0.90745693f, 0.90398929f, 0.90046115f, 0.89687274f, 0.89322430f, 0.88951608f, 0.88574831f, 0.88192126f, 0.87803519f, 0.87409034f, 0.87008699f, 0.86602540f, 0.86190585f, 0.85772861f, 0.85349396f, 0.84920218f, 0.84485357f, 0.84044840f, 0.83598698f, 0.83146961f, 0.82689659f, 0.82226822f, 0.81758481f, 0.81284668f, 0.80805415f, 0.80320753f, 0.79830715f, 0.79335334f, 0.78834643f, 0.78328675f, 0.77817464f, 0.77301045f, 0.76779452f, 0.76252720f, 0.75720885f, 0.75183981f, 0.74642045f, 0.74095113f, 0.73543221f, 0.72986407f, 0.72424708f, 0.71858162f, 0.71286806f, 0.70710678f, 0.70129818f, 0.69544264f, 0.68954054f, 0.68359230f, 0.67759830f, 0.67155895f, 0.66547466f, 0.65934582f, 0.65317284f, 0.64695615f, 0.64069616f, 0.63439328f, 0.62804795f, 0.62166057f, 0.61523159f, 0.60876143f, 0.60225052f, 0.59569930f, 0.58910822f, 0.58247770f, 0.57580819f, 0.56910015f, 0.56235401f, 0.55557023f, 0.54874927f, 0.54189158f, 0.53499762f, 0.52806785f, 0.52110274f, 0.51410274f, 0.50706834f, 0.50000000f, 0.49289819f, 0.48576339f, 0.47859608f, 0.47139674f, 0.46416584f, 0.45690388f, 0.44961133f, 0.44228869f, 0.43493645f, 0.42755509f, 0.42014512f, 0.41270703f, 0.40524131f, 0.39774847f, 0.39022901f, 0.38268343f, 0.37511224f, 0.36751594f, 0.35989504f, 0.35225005f, 0.34458148f, 0.33688985f, 0.32917568f, 0.32143947f, 0.31368174f, 0.30590302f, 0.29810383f, 0.29028468f, 0.28244610f, 0.27458862f, 0.26671276f, 0.25881905f, 0.25090801f, 0.24298018f, 0.23503609f, 0.22707626f, 0.21910124f, 0.21111155f, 0.20310773f, 0.19509032f, 0.18705985f, 0.17901686f, 0.17096189f, 0.16289547f, 0.15481816f, 0.14673047f, 0.13863297f, 0.13052619f, 0.12241068f, 0.11428696f, 0.10615561f, 0.09801714f, 0.08987211f, 0.08172107f, 0.07356456f, 0.06540313f, 0.05723732f, 0.04906767f, 0.04089475f, 0.03271908f, 0.02454123f, 0.01636173f, 0.00818114f}; // Hanning window: for 15ms at 16kHz with symmetric zeros static const float kBlocks240w512[512] = { 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00654494f, 0.01308960f, 0.01963369f, 0.02617695f, 0.03271908f, 0.03925982f, 0.04579887f, 0.05233596f, 0.05887080f, 0.06540313f, 0.07193266f, 0.07845910f, 0.08498218f, 0.09150162f, 0.09801714f, 0.10452846f, 0.11103531f, 0.11753740f, 0.12403446f, 0.13052620f, 0.13701233f, 0.14349262f, 0.14996676f, 0.15643448f, 0.16289547f, 0.16934951f, 0.17579629f, 0.18223552f, 0.18866697f, 0.19509032f, 0.20150533f, 0.20791170f, 0.21430916f, 0.22069745f, 0.22707628f, 0.23344538f, 0.23980446f, 0.24615330f, 0.25249159f, 0.25881904f, 0.26513544f, 0.27144045f, 0.27773386f, 0.28401536f, 0.29028466f, 0.29654160f, 0.30278578f, 0.30901700f, 0.31523499f, 0.32143945f, 0.32763019f, 0.33380687f, 0.33996925f, 0.34611708f, 0.35225007f, 0.35836795f, 0.36447051f, 0.37055743f, 0.37662852f, 0.38268346f, 0.38872197f, 0.39474389f, 0.40074885f, 0.40673664f, 0.41270703f, 0.41865975f, 0.42459452f, 0.43051112f, 0.43640924f, 0.44228873f, 0.44814920f, 0.45399052f, 0.45981237f, 0.46561453f, 0.47139674f, 0.47715878f, 0.48290035f, 0.48862126f, 0.49432120f, 0.50000000f, 0.50565743f, 0.51129311f, 0.51690692f, 0.52249855f, 0.52806789f, 0.53361452f, 0.53913832f, 0.54463905f, 0.55011642f, 0.55557024f, 0.56100029f, 0.56640625f, 0.57178795f, 0.57714522f, 0.58247769f, 0.58778524f, 0.59306765f, 0.59832460f, 0.60355598f, 0.60876143f, 0.61394083f, 0.61909395f, 0.62422055f, 0.62932038f, 0.63439333f, 0.63943899f, 0.64445734f, 0.64944810f, 0.65441096f, 0.65934587f, 0.66425246f, 0.66913062f, 0.67398012f, 0.67880076f, 0.68359232f, 0.68835455f, 0.69308740f, 0.69779050f, 0.70246369f, 0.70710677f, 0.71171963f, 0.71630198f, 0.72085363f, 0.72537440f, 0.72986406f, 0.73432255f, 0.73874950f, 0.74314487f, 0.74750835f, 0.75183982f, 0.75613910f, 0.76040596f, 0.76464027f, 0.76884186f, 0.77301043f, 0.77714598f, 0.78124821f, 0.78531694f, 0.78935206f, 0.79335338f, 0.79732066f, 0.80125386f, 0.80515265f, 0.80901700f, 0.81284672f, 0.81664157f, 0.82040149f, 0.82412618f, 0.82781565f, 0.83146966f, 0.83508795f, 0.83867061f, 0.84221727f, 0.84572780f, 0.84920216f, 0.85264021f, 0.85604161f, 0.85940641f, 0.86273444f, 0.86602545f, 0.86927933f, 0.87249607f, 0.87567532f, 0.87881714f, 0.88192129f, 0.88498765f, 0.88801610f, 0.89100653f, 0.89395881f, 0.89687276f, 0.89974827f, 0.90258533f, 0.90538365f, 0.90814316f, 0.91086388f, 0.91354549f, 0.91618794f, 0.91879123f, 0.92135513f, 0.92387950f, 0.92636442f, 0.92880958f, 0.93121493f, 0.93358046f, 0.93590593f, 0.93819135f, 0.94043654f, 0.94264150f, 0.94480604f, 0.94693011f, 0.94901365f, 0.95105654f, 0.95305866f, 0.95501995f, 0.95694035f, 0.95881975f, 0.96065807f, 0.96245527f, 0.96421117f, 0.96592581f, 0.96759909f, 0.96923089f, 0.97082120f, 0.97236991f, 0.97387701f, 0.97534233f, 0.97676587f, 0.97814763f, 0.97948742f, 0.98078531f, 0.98204112f, 0.98325491f, 0.98442656f, 0.98555607f, 0.98664331f, 0.98768836f, 0.98869103f, 0.98965138f, 0.99056935f, 0.99144489f, 0.99227792f, 0.99306846f, 0.99381649f, 0.99452192f, 0.99518472f, 0.99580491f, 0.99638247f, 0.99691731f, 0.99740952f, 0.99785894f, 0.99826562f, 0.99862951f, 0.99895066f, 0.99922901f, 0.99946457f, 0.99965733f, 0.99980724f, 0.99991435f, 0.99997860f, 1.00000000f, 0.99997860f, 0.99991435f, 0.99980724f, 0.99965733f, 0.99946457f, 0.99922901f, 0.99895066f, 0.99862951f, 0.99826562f, 0.99785894f, 0.99740946f, 0.99691731f, 0.99638247f, 0.99580491f, 0.99518472f, 0.99452192f, 0.99381644f, 0.99306846f, 0.99227792f, 0.99144489f, 0.99056935f, 0.98965138f, 0.98869103f, 0.98768836f, 0.98664331f, 0.98555607f, 0.98442656f, 0.98325491f, 0.98204112f, 0.98078525f, 0.97948742f, 0.97814757f, 0.97676587f, 0.97534227f, 0.97387695f, 0.97236991f, 0.97082120f, 0.96923089f, 0.96759909f, 0.96592581f, 0.96421117f, 0.96245521f, 0.96065807f, 0.95881969f, 0.95694029f, 0.95501995f, 0.95305860f, 0.95105648f, 0.94901365f, 0.94693011f, 0.94480604f, 0.94264150f, 0.94043654f, 0.93819129f, 0.93590593f, 0.93358046f, 0.93121493f, 0.92880952f, 0.92636436f, 0.92387950f, 0.92135507f, 0.91879123f, 0.91618794f, 0.91354543f, 0.91086382f, 0.90814310f, 0.90538365f, 0.90258527f, 0.89974827f, 0.89687276f, 0.89395875f, 0.89100647f, 0.88801610f, 0.88498759f, 0.88192123f, 0.87881714f, 0.87567532f, 0.87249595f, 0.86927933f, 0.86602539f, 0.86273432f, 0.85940641f, 0.85604161f, 0.85264009f, 0.84920216f, 0.84572780f, 0.84221715f, 0.83867055f, 0.83508795f, 0.83146954f, 0.82781565f, 0.82412612f, 0.82040137f, 0.81664157f, 0.81284660f, 0.80901700f, 0.80515265f, 0.80125374f, 0.79732066f, 0.79335332f, 0.78935200f, 0.78531694f, 0.78124815f, 0.77714586f, 0.77301049f, 0.76884180f, 0.76464021f, 0.76040596f, 0.75613904f, 0.75183970f, 0.74750835f, 0.74314481f, 0.73874938f, 0.73432249f, 0.72986400f, 0.72537428f, 0.72085363f, 0.71630186f, 0.71171951f, 0.70710677f, 0.70246363f, 0.69779032f, 0.69308734f, 0.68835449f, 0.68359220f, 0.67880070f, 0.67398006f, 0.66913044f, 0.66425240f, 0.65934575f, 0.65441096f, 0.64944804f, 0.64445722f, 0.63943905f, 0.63439327f, 0.62932026f, 0.62422055f, 0.61909389f, 0.61394072f, 0.60876143f, 0.60355592f, 0.59832448f, 0.59306765f, 0.58778518f, 0.58247757f, 0.57714522f, 0.57178789f, 0.56640613f, 0.56100023f, 0.55557019f, 0.55011630f, 0.54463905f, 0.53913826f, 0.53361434f, 0.52806783f, 0.52249849f, 0.51690674f, 0.51129305f, 0.50565726f, 0.50000006f, 0.49432117f, 0.48862115f, 0.48290038f, 0.47715873f, 0.47139663f, 0.46561456f, 0.45981231f, 0.45399037f, 0.44814920f, 0.44228864f, 0.43640912f, 0.43051112f, 0.42459446f, 0.41865960f, 0.41270703f, 0.40673658f, 0.40074870f, 0.39474386f, 0.38872188f, 0.38268328f, 0.37662849f, 0.37055734f, 0.36447033f, 0.35836792f, 0.35224995f, 0.34611690f, 0.33996922f, 0.33380675f, 0.32763001f, 0.32143945f, 0.31523487f, 0.30901679f, 0.30278572f, 0.29654145f, 0.29028472f, 0.28401530f, 0.27773371f, 0.27144048f, 0.26513538f, 0.25881892f, 0.25249159f, 0.24615324f, 0.23980433f, 0.23344538f, 0.22707619f, 0.22069728f, 0.21430916f, 0.20791161f, 0.20150517f, 0.19509031f, 0.18866688f, 0.18223536f, 0.17579627f, 0.16934940f, 0.16289529f, 0.15643445f, 0.14996666f, 0.14349243f, 0.13701232f, 0.13052608f, 0.12403426f, 0.11753736f, 0.11103519f, 0.10452849f, 0.09801710f, 0.09150149f, 0.08498220f, 0.07845904f, 0.07193252f, 0.06540315f, 0.05887074f, 0.05233581f, 0.04579888f, 0.03925974f, 0.03271893f, 0.02617695f, 0.01963361f, 0.01308943f, 0.00654493f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f}; // Hanning window: for 30ms with 1024 fft with symmetric zeros at 16kHz static const float kBlocks480w1024[1024] = { 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00327249f, 0.00654494f, 0.00981732f, 0.01308960f, 0.01636173f, 0.01963369f, 0.02290544f, 0.02617695f, 0.02944817f, 0.03271908f, 0.03598964f, 0.03925982f, 0.04252957f, 0.04579887f, 0.04906768f, 0.05233596f, 0.05560368f, 0.05887080f, 0.06213730f, 0.06540313f, 0.06866825f, 0.07193266f, 0.07519628f, 0.07845910f, 0.08172107f, 0.08498218f, 0.08824237f, 0.09150162f, 0.09475989f, 0.09801714f, 0.10127335f, 0.10452846f, 0.10778246f, 0.11103531f, 0.11428697f, 0.11753740f, 0.12078657f, 0.12403446f, 0.12728101f, 0.13052620f, 0.13376999f, 0.13701233f, 0.14025325f, 0.14349262f, 0.14673047f, 0.14996676f, 0.15320145f, 0.15643448f, 0.15966582f, 0.16289547f, 0.16612339f, 0.16934951f, 0.17257382f, 0.17579629f, 0.17901687f, 0.18223552f, 0.18545224f, 0.18866697f, 0.19187967f, 0.19509032f, 0.19829889f, 0.20150533f, 0.20470962f, 0.20791170f, 0.21111156f, 0.21430916f, 0.21750447f, 0.22069745f, 0.22388805f, 0.22707628f, 0.23026206f, 0.23344538f, 0.23662618f, 0.23980446f, 0.24298020f, 0.24615330f, 0.24932377f, 0.25249159f, 0.25565669f, 0.25881904f, 0.26197866f, 0.26513544f, 0.26828939f, 0.27144045f, 0.27458861f, 0.27773386f, 0.28087610f, 0.28401536f, 0.28715158f, 0.29028466f, 0.29341471f, 0.29654160f, 0.29966527f, 0.30278578f, 0.30590302f, 0.30901700f, 0.31212768f, 0.31523499f, 0.31833893f, 0.32143945f, 0.32453656f, 0.32763019f, 0.33072028f, 0.33380687f, 0.33688986f, 0.33996925f, 0.34304500f, 0.34611708f, 0.34918544f, 0.35225007f, 0.35531089f, 0.35836795f, 0.36142117f, 0.36447051f, 0.36751595f, 0.37055743f, 0.37359497f, 0.37662852f, 0.37965801f, 0.38268346f, 0.38570479f, 0.38872197f, 0.39173502f, 0.39474389f, 0.39774847f, 0.40074885f, 0.40374491f, 0.40673664f, 0.40972406f, 0.41270703f, 0.41568562f, 0.41865975f, 0.42162940f, 0.42459452f, 0.42755508f, 0.43051112f, 0.43346250f, 0.43640924f, 0.43935132f, 0.44228873f, 0.44522133f, 0.44814920f, 0.45107228f, 0.45399052f, 0.45690390f, 0.45981237f, 0.46271592f, 0.46561453f, 0.46850815f, 0.47139674f, 0.47428030f, 0.47715878f, 0.48003215f, 0.48290035f, 0.48576337f, 0.48862126f, 0.49147385f, 0.49432120f, 0.49716330f, 0.50000000f, 0.50283140f, 0.50565743f, 0.50847799f, 0.51129311f, 0.51410276f, 0.51690692f, 0.51970553f, 0.52249855f, 0.52528602f, 0.52806789f, 0.53084403f, 0.53361452f, 0.53637928f, 0.53913832f, 0.54189163f, 0.54463905f, 0.54738063f, 0.55011642f, 0.55284631f, 0.55557024f, 0.55828828f, 0.56100029f, 0.56370628f, 0.56640625f, 0.56910014f, 0.57178795f, 0.57446963f, 0.57714522f, 0.57981455f, 0.58247769f, 0.58513463f, 0.58778524f, 0.59042960f, 0.59306765f, 0.59569931f, 0.59832460f, 0.60094351f, 0.60355598f, 0.60616195f, 0.60876143f, 0.61135441f, 0.61394083f, 0.61652070f, 0.61909395f, 0.62166059f, 0.62422055f, 0.62677383f, 0.62932038f, 0.63186020f, 0.63439333f, 0.63691956f, 0.63943899f, 0.64195162f, 0.64445734f, 0.64695615f, 0.64944810f, 0.65193301f, 0.65441096f, 0.65688187f, 0.65934587f, 0.66180271f, 0.66425246f, 0.66669512f, 0.66913062f, 0.67155898f, 0.67398012f, 0.67639405f, 0.67880076f, 0.68120021f, 0.68359232f, 0.68597710f, 0.68835455f, 0.69072467f, 0.69308740f, 0.69544262f, 0.69779050f, 0.70013082f, 0.70246369f, 0.70478904f, 0.70710677f, 0.70941699f, 0.71171963f, 0.71401459f, 0.71630198f, 0.71858168f, 0.72085363f, 0.72311789f, 0.72537440f, 0.72762316f, 0.72986406f, 0.73209721f, 0.73432255f, 0.73653996f, 0.73874950f, 0.74095118f, 0.74314487f, 0.74533057f, 0.74750835f, 0.74967808f, 0.75183982f, 0.75399351f, 0.75613910f, 0.75827658f, 0.76040596f, 0.76252723f, 0.76464027f, 0.76674515f, 0.76884186f, 0.77093029f, 0.77301043f, 0.77508241f, 0.77714598f, 0.77920127f, 0.78124821f, 0.78328675f, 0.78531694f, 0.78733873f, 0.78935206f, 0.79135692f, 0.79335338f, 0.79534125f, 0.79732066f, 0.79929149f, 0.80125386f, 0.80320752f, 0.80515265f, 0.80708915f, 0.80901700f, 0.81093621f, 0.81284672f, 0.81474853f, 0.81664157f, 0.81852591f, 0.82040149f, 0.82226825f, 0.82412618f, 0.82597536f, 0.82781565f, 0.82964706f, 0.83146966f, 0.83328325f, 0.83508795f, 0.83688378f, 0.83867061f, 0.84044838f, 0.84221727f, 0.84397703f, 0.84572780f, 0.84746957f, 0.84920216f, 0.85092574f, 0.85264021f, 0.85434544f, 0.85604161f, 0.85772866f, 0.85940641f, 0.86107504f, 0.86273444f, 0.86438453f, 0.86602545f, 0.86765707f, 0.86927933f, 0.87089235f, 0.87249607f, 0.87409031f, 0.87567532f, 0.87725097f, 0.87881714f, 0.88037390f, 0.88192129f, 0.88345921f, 0.88498765f, 0.88650668f, 0.88801610f, 0.88951612f, 0.89100653f, 0.89248741f, 0.89395881f, 0.89542055f, 0.89687276f, 0.89831537f, 0.89974827f, 0.90117162f, 0.90258533f, 0.90398932f, 0.90538365f, 0.90676826f, 0.90814316f, 0.90950841f, 0.91086388f, 0.91220951f, 0.91354549f, 0.91487163f, 0.91618794f, 0.91749454f, 0.91879123f, 0.92007810f, 0.92135513f, 0.92262226f, 0.92387950f, 0.92512691f, 0.92636442f, 0.92759192f, 0.92880958f, 0.93001723f, 0.93121493f, 0.93240267f, 0.93358046f, 0.93474817f, 0.93590593f, 0.93705362f, 0.93819135f, 0.93931901f, 0.94043654f, 0.94154406f, 0.94264150f, 0.94372880f, 0.94480604f, 0.94587320f, 0.94693011f, 0.94797695f, 0.94901365f, 0.95004016f, 0.95105654f, 0.95206273f, 0.95305866f, 0.95404440f, 0.95501995f, 0.95598525f, 0.95694035f, 0.95788521f, 0.95881975f, 0.95974404f, 0.96065807f, 0.96156180f, 0.96245527f, 0.96333838f, 0.96421117f, 0.96507370f, 0.96592581f, 0.96676767f, 0.96759909f, 0.96842021f, 0.96923089f, 0.97003126f, 0.97082120f, 0.97160077f, 0.97236991f, 0.97312868f, 0.97387701f, 0.97461486f, 0.97534233f, 0.97605932f, 0.97676587f, 0.97746199f, 0.97814763f, 0.97882277f, 0.97948742f, 0.98014158f, 0.98078531f, 0.98141843f, 0.98204112f, 0.98265332f, 0.98325491f, 0.98384601f, 0.98442656f, 0.98499662f, 0.98555607f, 0.98610497f, 0.98664331f, 0.98717111f, 0.98768836f, 0.98819500f, 0.98869103f, 0.98917651f, 0.98965138f, 0.99011570f, 0.99056935f, 0.99101239f, 0.99144489f, 0.99186671f, 0.99227792f, 0.99267852f, 0.99306846f, 0.99344778f, 0.99381649f, 0.99417448f, 0.99452192f, 0.99485862f, 0.99518472f, 0.99550015f, 0.99580491f, 0.99609905f, 0.99638247f, 0.99665523f, 0.99691731f, 0.99716878f, 0.99740952f, 0.99763954f, 0.99785894f, 0.99806762f, 0.99826562f, 0.99845290f, 0.99862951f, 0.99879545f, 0.99895066f, 0.99909520f, 0.99922901f, 0.99935216f, 0.99946457f, 0.99956632f, 0.99965733f, 0.99973762f, 0.99980724f, 0.99986613f, 0.99991435f, 0.99995178f, 0.99997860f, 0.99999464f, 1.00000000f, 0.99999464f, 0.99997860f, 0.99995178f, 0.99991435f, 0.99986613f, 0.99980724f, 0.99973762f, 0.99965733f, 0.99956632f, 0.99946457f, 0.99935216f, 0.99922901f, 0.99909520f, 0.99895066f, 0.99879545f, 0.99862951f, 0.99845290f, 0.99826562f, 0.99806762f, 0.99785894f, 0.99763954f, 0.99740946f, 0.99716872f, 0.99691731f, 0.99665523f, 0.99638247f, 0.99609905f, 0.99580491f, 0.99550015f, 0.99518472f, 0.99485862f, 0.99452192f, 0.99417448f, 0.99381644f, 0.99344778f, 0.99306846f, 0.99267852f, 0.99227792f, 0.99186671f, 0.99144489f, 0.99101239f, 0.99056935f, 0.99011564f, 0.98965138f, 0.98917651f, 0.98869103f, 0.98819494f, 0.98768836f, 0.98717111f, 0.98664331f, 0.98610497f, 0.98555607f, 0.98499656f, 0.98442656f, 0.98384601f, 0.98325491f, 0.98265326f, 0.98204112f, 0.98141843f, 0.98078525f, 0.98014158f, 0.97948742f, 0.97882277f, 0.97814757f, 0.97746193f, 0.97676587f, 0.97605932f, 0.97534227f, 0.97461486f, 0.97387695f, 0.97312862f, 0.97236991f, 0.97160077f, 0.97082120f, 0.97003126f, 0.96923089f, 0.96842015f, 0.96759909f, 0.96676761f, 0.96592581f, 0.96507365f, 0.96421117f, 0.96333838f, 0.96245521f, 0.96156180f, 0.96065807f, 0.95974404f, 0.95881969f, 0.95788515f, 0.95694029f, 0.95598525f, 0.95501995f, 0.95404440f, 0.95305860f, 0.95206267f, 0.95105648f, 0.95004016f, 0.94901365f, 0.94797695f, 0.94693011f, 0.94587314f, 0.94480604f, 0.94372880f, 0.94264150f, 0.94154406f, 0.94043654f, 0.93931895f, 0.93819129f, 0.93705362f, 0.93590593f, 0.93474817f, 0.93358046f, 0.93240267f, 0.93121493f, 0.93001723f, 0.92880952f, 0.92759192f, 0.92636436f, 0.92512691f, 0.92387950f, 0.92262226f, 0.92135507f, 0.92007804f, 0.91879123f, 0.91749448f, 0.91618794f, 0.91487157f, 0.91354543f, 0.91220951f, 0.91086382f, 0.90950835f, 0.90814310f, 0.90676820f, 0.90538365f, 0.90398932f, 0.90258527f, 0.90117157f, 0.89974827f, 0.89831525f, 0.89687276f, 0.89542055f, 0.89395875f, 0.89248741f, 0.89100647f, 0.88951600f, 0.88801610f, 0.88650662f, 0.88498759f, 0.88345915f, 0.88192123f, 0.88037384f, 0.87881714f, 0.87725091f, 0.87567532f, 0.87409031f, 0.87249595f, 0.87089223f, 0.86927933f, 0.86765701f, 0.86602539f, 0.86438447f, 0.86273432f, 0.86107504f, 0.85940641f, 0.85772860f, 0.85604161f, 0.85434544f, 0.85264009f, 0.85092574f, 0.84920216f, 0.84746951f, 0.84572780f, 0.84397697f, 0.84221715f, 0.84044844f, 0.83867055f, 0.83688372f, 0.83508795f, 0.83328319f, 0.83146954f, 0.82964706f, 0.82781565f, 0.82597530f, 0.82412612f, 0.82226813f, 0.82040137f, 0.81852591f, 0.81664157f, 0.81474847f, 0.81284660f, 0.81093609f, 0.80901700f, 0.80708915f, 0.80515265f, 0.80320752f, 0.80125374f, 0.79929143f, 0.79732066f, 0.79534125f, 0.79335332f, 0.79135686f, 0.78935200f, 0.78733861f, 0.78531694f, 0.78328675f, 0.78124815f, 0.77920121f, 0.77714586f, 0.77508223f, 0.77301049f, 0.77093029f, 0.76884180f, 0.76674509f, 0.76464021f, 0.76252711f, 0.76040596f, 0.75827658f, 0.75613904f, 0.75399339f, 0.75183970f, 0.74967796f, 0.74750835f, 0.74533057f, 0.74314481f, 0.74095106f, 0.73874938f, 0.73653996f, 0.73432249f, 0.73209721f, 0.72986400f, 0.72762305f, 0.72537428f, 0.72311789f, 0.72085363f, 0.71858162f, 0.71630186f, 0.71401453f, 0.71171951f, 0.70941705f, 0.70710677f, 0.70478898f, 0.70246363f, 0.70013070f, 0.69779032f, 0.69544268f, 0.69308734f, 0.69072461f, 0.68835449f, 0.68597704f, 0.68359220f, 0.68120021f, 0.67880070f, 0.67639399f, 0.67398006f, 0.67155886f, 0.66913044f, 0.66669512f, 0.66425240f, 0.66180259f, 0.65934575f, 0.65688181f, 0.65441096f, 0.65193301f, 0.64944804f, 0.64695609f, 0.64445722f, 0.64195150f, 0.63943905f, 0.63691956f, 0.63439327f, 0.63186014f, 0.62932026f, 0.62677372f, 0.62422055f, 0.62166059f, 0.61909389f, 0.61652064f, 0.61394072f, 0.61135429f, 0.60876143f, 0.60616189f, 0.60355592f, 0.60094339f, 0.59832448f, 0.59569913f, 0.59306765f, 0.59042960f, 0.58778518f, 0.58513451f, 0.58247757f, 0.57981461f, 0.57714522f, 0.57446963f, 0.57178789f, 0.56910002f, 0.56640613f, 0.56370628f, 0.56100023f, 0.55828822f, 0.55557019f, 0.55284619f, 0.55011630f, 0.54738069f, 0.54463905f, 0.54189152f, 0.53913826f, 0.53637916f, 0.53361434f, 0.53084403f, 0.52806783f, 0.52528596f, 0.52249849f, 0.51970541f, 0.51690674f, 0.51410276f, 0.51129305f, 0.50847787f, 0.50565726f, 0.50283122f, 0.50000006f, 0.49716327f, 0.49432117f, 0.49147379f, 0.48862115f, 0.48576325f, 0.48290038f, 0.48003212f, 0.47715873f, 0.47428021f, 0.47139663f, 0.46850798f, 0.46561456f, 0.46271589f, 0.45981231f, 0.45690379f, 0.45399037f, 0.45107210f, 0.44814920f, 0.44522130f, 0.44228864f, 0.43935123f, 0.43640912f, 0.43346232f, 0.43051112f, 0.42755505f, 0.42459446f, 0.42162928f, 0.41865960f, 0.41568545f, 0.41270703f, 0.40972400f, 0.40673658f, 0.40374479f, 0.40074870f, 0.39774850f, 0.39474386f, 0.39173496f, 0.38872188f, 0.38570464f, 0.38268328f, 0.37965804f, 0.37662849f, 0.37359491f, 0.37055734f, 0.36751580f, 0.36447033f, 0.36142117f, 0.35836792f, 0.35531086f, 0.35224995f, 0.34918529f, 0.34611690f, 0.34304500f, 0.33996922f, 0.33688980f, 0.33380675f, 0.33072016f, 0.32763001f, 0.32453656f, 0.32143945f, 0.31833887f, 0.31523487f, 0.31212750f, 0.30901679f, 0.30590302f, 0.30278572f, 0.29966521f, 0.29654145f, 0.29341453f, 0.29028472f, 0.28715155f, 0.28401530f, 0.28087601f, 0.27773371f, 0.27458847f, 0.27144048f, 0.26828936f, 0.26513538f, 0.26197854f, 0.25881892f, 0.25565651f, 0.25249159f, 0.24932374f, 0.24615324f, 0.24298008f, 0.23980433f, 0.23662600f, 0.23344538f, 0.23026201f, 0.22707619f, 0.22388794f, 0.22069728f, 0.21750426f, 0.21430916f, 0.21111152f, 0.20791161f, 0.20470949f, 0.20150517f, 0.19829892f, 0.19509031f, 0.19187963f, 0.18866688f, 0.18545210f, 0.18223536f, 0.17901689f, 0.17579627f, 0.17257376f, 0.16934940f, 0.16612324f, 0.16289529f, 0.15966584f, 0.15643445f, 0.15320137f, 0.14996666f, 0.14673033f, 0.14349243f, 0.14025325f, 0.13701232f, 0.13376991f, 0.13052608f, 0.12728085f, 0.12403426f, 0.12078657f, 0.11753736f, 0.11428688f, 0.11103519f, 0.10778230f, 0.10452849f, 0.10127334f, 0.09801710f, 0.09475980f, 0.09150149f, 0.08824220f, 0.08498220f, 0.08172106f, 0.07845904f, 0.07519618f, 0.07193252f, 0.06866808f, 0.06540315f, 0.06213728f, 0.05887074f, 0.05560357f, 0.05233581f, 0.04906749f, 0.04579888f, 0.04252954f, 0.03925974f, 0.03598953f, 0.03271893f, 0.02944798f, 0.02617695f, 0.02290541f, 0.01963361f, 0.01636161f, 0.01308943f, 0.00981712f, 0.00654493f, 0.00327244f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f}; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_TRANSIENT_WINDOWS_PRIVATE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/wpd_node.cc0000664000175000017500000000410014475643423027271 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/transient/wpd_node.h" #include #include #include "common_audio/fir_filter.h" #include "common_audio/fir_filter_factory.h" #include "modules/audio_processing/transient/dyadic_decimator.h" #include "rtc_base/checks.h" namespace webrtc { WPDNode::WPDNode(size_t length, const float* coefficients, size_t coefficients_length) : // The data buffer has parent data length to be able to contain and // filter it. data_(new float[2 * length + 1]), length_(length), filter_( CreateFirFilter(coefficients, coefficients_length, 2 * length + 1)) { RTC_DCHECK_GT(length, 0); RTC_DCHECK(coefficients); RTC_DCHECK_GT(coefficients_length, 0); memset(data_.get(), 0.f, (2 * length + 1) * sizeof(data_[0])); } WPDNode::~WPDNode() {} int WPDNode::Update(const float* parent_data, size_t parent_data_length) { if (!parent_data || (parent_data_length / 2) != length_) { return -1; } // Filter data. filter_->Filter(parent_data, parent_data_length, data_.get()); // Decimate data. const bool kOddSequence = true; size_t output_samples = DyadicDecimate(data_.get(), parent_data_length, kOddSequence, data_.get(), length_); if (output_samples != length_) { return -1; } // Get abs to all values. for (size_t i = 0; i < length_; ++i) { data_[i] = fabs(data_[i]); } return 0; } int WPDNode::set_data(const float* new_data, size_t length) { if (!new_data || length != length_) { return -1; } memcpy(data_.get(), new_data, length * sizeof(data_[0])); return 0; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/wpd_node.h0000664000175000017500000000265114475643423027144 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_NODE_H_ #define MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_NODE_H_ #include namespace webrtc { class FIRFilter; // A single node of a Wavelet Packet Decomposition (WPD) tree. class WPDNode { public: // Creates a WPDNode. The data vector will contain zeros. The filter will have // the coefficients provided. WPDNode(size_t length, const float* coefficients, size_t coefficients_length); ~WPDNode(); // Updates the node data. |parent_data| / 2 must be equals to |length_|. // Returns 0 if correct, and -1 otherwise. int Update(const float* parent_data, size_t parent_data_length); const float* data() const { return data_.get(); } // Returns 0 if correct, and -1 otherwise. int set_data(const float* new_data, size_t length); size_t length() const { return length_; } private: std::unique_ptr data_; size_t length_; std::unique_ptr filter_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_NODE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/wpd_tree.cc0000664000175000017500000000763014475643423027316 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/transient/wpd_tree.h" #include #include "modules/audio_processing/transient/wpd_node.h" #include "rtc_base/checks.h" namespace webrtc { WPDTree::WPDTree(size_t data_length, const float* high_pass_coefficients, const float* low_pass_coefficients, size_t coefficients_length, int levels) : data_length_(data_length), levels_(levels), num_nodes_((1 << (levels + 1)) - 1) { RTC_DCHECK_GT(data_length, (static_cast(1) << levels)); RTC_DCHECK(high_pass_coefficients); RTC_DCHECK(low_pass_coefficients); RTC_DCHECK_GT(levels, 0); // Size is 1 more, so we can use the array as 1-based. nodes_[0] is never // allocated. nodes_.reset(new std::unique_ptr[num_nodes_ + 1]); // Create the first node const float kRootCoefficient = 1.f; // Identity Coefficient. nodes_[1].reset(new WPDNode(data_length, &kRootCoefficient, 1)); // Variables used to create the rest of the nodes. size_t index = 1; size_t index_left_child = 0; size_t index_right_child = 0; int num_nodes_at_curr_level = 0; // Branching each node in each level to create its children. The last level is // not branched (all the nodes of that level are leaves). for (int current_level = 0; current_level < levels; ++current_level) { num_nodes_at_curr_level = 1 << current_level; for (int i = 0; i < num_nodes_at_curr_level; ++i) { index = (1 << current_level) + i; // Obtain the index of the current node children. index_left_child = index * 2; index_right_child = index_left_child + 1; nodes_[index_left_child].reset(new WPDNode(nodes_[index]->length() / 2, low_pass_coefficients, coefficients_length)); nodes_[index_right_child].reset(new WPDNode(nodes_[index]->length() / 2, high_pass_coefficients, coefficients_length)); } } } WPDTree::~WPDTree() {} WPDNode* WPDTree::NodeAt(int level, int index) { if (level < 0 || level > levels_ || index < 0 || index >= 1 << level) { return NULL; } return nodes_[(1 << level) + index].get(); } int WPDTree::Update(const float* data, size_t data_length) { if (!data || data_length != data_length_) { return -1; } // Update the root node. int update_result = nodes_[1]->set_data(data, data_length); if (update_result != 0) { return -1; } // Variables used to update the rest of the nodes. size_t index = 1; size_t index_left_child = 0; size_t index_right_child = 0; int num_nodes_at_curr_level = 0; for (int current_level = 0; current_level < levels_; ++current_level) { num_nodes_at_curr_level = 1 << current_level; for (int i = 0; i < num_nodes_at_curr_level; ++i) { index = (1 << current_level) + i; // Obtain the index of the current node children. index_left_child = index * 2; index_right_child = index_left_child + 1; update_result = nodes_[index_left_child]->Update(nodes_[index]->data(), nodes_[index]->length()); if (update_result != 0) { return -1; } update_result = nodes_[index_right_child]->Update( nodes_[index]->data(), nodes_[index]->length()); if (update_result != 0) { return -1; } } } return 0; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/transient/wpd_tree.h0000664000175000017500000000655614475643423027166 0ustar00arunarun/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_TREE_H_ #define MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_TREE_H_ #include #include #include "modules/audio_processing/transient/wpd_node.h" namespace webrtc { // Tree of a Wavelet Packet Decomposition (WPD). // // The root node contains all the data provided; for each node in the tree, the // left child contains the approximation coefficients extracted from the node, // and the right child contains the detail coefficients. // It preserves its state, so it can be multiple-called. // // The number of nodes in the tree will be 2 ^ levels - 1. // // Implementation details: Since the tree always will be a complete binary tree, // it is implemented using a single linear array instead of managing the // relationships in each node. For convience is better to use a array that // starts in 1 (instead of 0). Taking that into account, the following formulas // apply: // Root node index: 1. // Node(Level, Index in that level): 2 ^ Level + (Index in that level). // Left Child: Current node index * 2. // Right Child: Current node index * 2 + 1. // Parent: Current Node Index / 2 (Integer division). class WPDTree { public: // Creates a WPD tree using the data length and coefficients provided. WPDTree(size_t data_length, const float* high_pass_coefficients, const float* low_pass_coefficients, size_t coefficients_length, int levels); ~WPDTree(); // Returns the number of nodes at any given level. static int NumberOfNodesAtLevel(int level) { return 1 << level; } // Returns a pointer to the node at the given level and index(of that level). // Level goes from 0 to levels(). // Index goes from 0 to the number of NumberOfNodesAtLevel(level) - 1. // // You can use the following formulas to get any node within the tree: // Notation: (Level, Index of node in that level). // Root node: (0/0). // Left Child: (Current node level + 1, Current node index * 2). // Right Child: (Current node level + 1, Current node index * 2 + 1). // Parent: (Current node level - 1, Current node index / 2) (Integer division) // // If level or index are out of bounds the function will return NULL. WPDNode* NodeAt(int level, int index); // Updates all the nodes of the tree with the new data. |data_length| must be // teh same that was used for the creation of the tree. // Returns 0 if correct, and -1 otherwise. int Update(const float* data, size_t data_length); // Returns the total number of levels below the root. Root is cosidered level // 0. int levels() const { return levels_; } // Returns the total number of nodes. int num_nodes() const { return num_nodes_; } // Returns the total number of leaves. int num_leaves() const { return 1 << levels_; } private: size_t data_length_; int levels_; int num_nodes_; std::unique_ptr[]> nodes_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_TREE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/typing_detection.cc0000664000175000017500000000530014475643423027036 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/typing_detection.h" namespace webrtc { TypingDetection::TypingDetection() : time_active_(0), time_since_last_typing_(0), penalty_counter_(0), counter_since_last_detection_update_(0), detection_to_report_(false), new_detection_to_report_(false), time_window_(10), cost_per_typing_(100), reporting_threshold_(300), penalty_decay_(1), type_event_delay_(2), report_detection_update_period_(1) {} TypingDetection::~TypingDetection() {} bool TypingDetection::Process(bool key_pressed, bool vad_activity) { if (vad_activity) time_active_++; else time_active_ = 0; // Keep track if time since last typing event if (key_pressed) time_since_last_typing_ = 0; else ++time_since_last_typing_; if (time_since_last_typing_ < type_event_delay_ && vad_activity && time_active_ < time_window_) { penalty_counter_ += cost_per_typing_; if (penalty_counter_ > reporting_threshold_) new_detection_to_report_ = true; } if (penalty_counter_ > 0) penalty_counter_ -= penalty_decay_; if (++counter_since_last_detection_update_ == report_detection_update_period_) { detection_to_report_ = new_detection_to_report_; new_detection_to_report_ = false; counter_since_last_detection_update_ = 0; } return detection_to_report_; } int TypingDetection::TimeSinceLastDetectionInSeconds() { // Round to whole seconds. return (time_since_last_typing_ + 50) / 100; } void TypingDetection::SetParameters(int time_window, int cost_per_typing, int reporting_threshold, int penalty_decay, int type_event_delay, int report_detection_update_period) { if (time_window) time_window_ = time_window; if (cost_per_typing) cost_per_typing_ = cost_per_typing; if (reporting_threshold) reporting_threshold_ = reporting_threshold; if (penalty_decay) penalty_decay_ = penalty_decay; if (type_event_delay) type_event_delay_ = type_event_delay; if (report_detection_update_period) report_detection_update_period_ = report_detection_update_period; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/typing_detection.h0000664000175000017500000000650214475643423026705 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_TYPING_DETECTION_H_ #define MODULES_AUDIO_PROCESSING_TYPING_DETECTION_H_ #include "rtc_base/system/rtc_export.h" namespace webrtc { class RTC_EXPORT TypingDetection { public: TypingDetection(); virtual ~TypingDetection(); // Run the detection algortihm. Shall be called every 10 ms. Returns true if // typing is detected, or false if not, based on the update period as set with // SetParameters(). See |report_detection_update_period_| description below. bool Process(bool key_pressed, bool vad_activity); // Gets the time in seconds since the last detection. int TimeSinceLastDetectionInSeconds(); // Sets the algorithm parameters. A parameter value of 0 leaves it unchanged. // See the correspondning member variables below for descriptions. void SetParameters(int time_window, int cost_per_typing, int reporting_threshold, int penalty_decay, int type_event_delay, int report_detection_update_period); private: int time_active_; int time_since_last_typing_; int penalty_counter_; // Counter since last time the detection status reported by Process() was // updated. See also |report_detection_update_period_|. int counter_since_last_detection_update_; // The detection status to report. Updated every // |report_detection_update_period_| call to Process(). bool detection_to_report_; // What |detection_to_report_| should be set to next time it is updated. bool new_detection_to_report_; // Settable threshold values. // Number of 10 ms slots accepted to count as a hit. int time_window_; // Penalty added for a typing + activity coincide. int cost_per_typing_; // Threshold for |penalty_counter_|. int reporting_threshold_; // How much we reduce |penalty_counter_| every 10 ms. int penalty_decay_; // How old typing events we allow. int type_event_delay_; // Settable update period. // Number of 10 ms slots between each update of the detection status returned // by Process(). This inertia added to the algorithm is usually desirable and // provided so that consumers of the class don't have to implement that // themselves if they don't wish. // If set to 1, each call to Process() will return the detection status for // that 10 ms slot. // If set to N (where N > 1), the detection status returned from Process() // will remain the same until Process() has been called N times. Then, if none // of the last N calls to Process() has detected typing for each respective // 10 ms slot, Process() will return false. If at least one of the last N // calls has detected typing, Process() will return true. And that returned // status will then remain the same until the next N calls have been done. int report_detection_update_period_; }; } // namespace webrtc #endif // #ifndef MODULES_AUDIO_PROCESSING_TYPING_DETECTION_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/utility/0000775000175000017500000000000014475643423024664 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/utility/BUILD.gn0000664000175000017500000000364514475643423026061 0ustar00arunarun# Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../../../webrtc.gni") rtc_library("cascaded_biquad_filter") { sources = [ "cascaded_biquad_filter.cc", "cascaded_biquad_filter.h", ] deps = [ "../../../api:array_view", "../../../rtc_base:checks", ] } rtc_library("legacy_delay_estimator") { sources = [ "delay_estimator.cc", "delay_estimator.h", "delay_estimator_internal.h", "delay_estimator_wrapper.cc", "delay_estimator_wrapper.h", ] deps = [ "../../../rtc_base:checks" ] } rtc_library("pffft_wrapper") { visibility = [ "../*" ] sources = [ "pffft_wrapper.cc", "pffft_wrapper.h", ] deps = [ "../../../api:array_view", "../../../rtc_base:checks", "//third_party/pffft", ] } if (rtc_include_tests) { rtc_library("cascaded_biquad_filter_unittest") { testonly = true sources = [ "cascaded_biquad_filter_unittest.cc" ] deps = [ ":cascaded_biquad_filter", "../../../rtc_base:rtc_base_approved", "../../../test:test_support", "//testing/gtest", ] } rtc_library("legacy_delay_estimator_unittest") { testonly = true sources = [ "delay_estimator_unittest.cc" ] deps = [ ":legacy_delay_estimator", "../../../rtc_base:rtc_base_approved", "../../../test:test_support", "//testing/gtest", ] } rtc_library("pffft_wrapper_unittest") { testonly = true sources = [ "pffft_wrapper_unittest.cc" ] deps = [ ":pffft_wrapper", "../../../test:test_support", "//testing/gtest", "//third_party/pffft", ] } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/utility/cascaded_biquad_filter.cc0000664000175000017500000000715014475643423031617 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/utility/cascaded_biquad_filter.h" #include #include "rtc_base/checks.h" namespace webrtc { CascadedBiQuadFilter::BiQuadParam::BiQuadParam(std::complex zero, std::complex pole, float gain, bool mirror_zero_along_i_axis) : zero(zero), pole(pole), gain(gain), mirror_zero_along_i_axis(mirror_zero_along_i_axis) {} CascadedBiQuadFilter::BiQuadParam::BiQuadParam(const BiQuadParam&) = default; CascadedBiQuadFilter::BiQuad::BiQuad( const CascadedBiQuadFilter::BiQuadParam& param) : x(), y() { float z_r = std::real(param.zero); float z_i = std::imag(param.zero); float p_r = std::real(param.pole); float p_i = std::imag(param.pole); float gain = param.gain; if (param.mirror_zero_along_i_axis) { // Assuming zeroes at z_r and -z_r. RTC_DCHECK(z_i == 0.f); coefficients.b[0] = gain * 1.f; coefficients.b[1] = 0.f; coefficients.b[2] = gain * -(z_r * z_r); } else { // Assuming zeros at (z_r + z_i*i) and (z_r - z_i*i). coefficients.b[0] = gain * 1.f; coefficients.b[1] = gain * -2.f * z_r; coefficients.b[2] = gain * (z_r * z_r + z_i * z_i); } // Assuming poles at (p_r + p_i*i) and (p_r - p_i*i). coefficients.a[0] = -2.f * p_r; coefficients.a[1] = p_r * p_r + p_i * p_i; } void CascadedBiQuadFilter::BiQuad::BiQuad::Reset() { x[0] = x[1] = y[0] = y[1] = 0.f; } CascadedBiQuadFilter::CascadedBiQuadFilter( const CascadedBiQuadFilter::BiQuadCoefficients& coefficients, size_t num_biquads) : biquads_(num_biquads, BiQuad(coefficients)) {} CascadedBiQuadFilter::CascadedBiQuadFilter( const std::vector& biquad_params) { for (const auto& param : biquad_params) { biquads_.push_back(BiQuad(param)); } } CascadedBiQuadFilter::~CascadedBiQuadFilter() = default; void CascadedBiQuadFilter::Process(rtc::ArrayView x, rtc::ArrayView y) { if (biquads_.size() > 0) { ApplyBiQuad(x, y, &biquads_[0]); for (size_t k = 1; k < biquads_.size(); ++k) { ApplyBiQuad(y, y, &biquads_[k]); } } else { std::copy(x.begin(), x.end(), y.begin()); } } void CascadedBiQuadFilter::Process(rtc::ArrayView y) { for (auto& biquad : biquads_) { ApplyBiQuad(y, y, &biquad); } } void CascadedBiQuadFilter::Reset() { for (auto& biquad : biquads_) { biquad.Reset(); } } void CascadedBiQuadFilter::ApplyBiQuad(rtc::ArrayView x, rtc::ArrayView y, CascadedBiQuadFilter::BiQuad* biquad) { RTC_DCHECK_EQ(x.size(), y.size()); const auto* c_b = biquad->coefficients.b; const auto* c_a = biquad->coefficients.a; auto* m_x = biquad->x; auto* m_y = biquad->y; for (size_t k = 0; k < x.size(); ++k) { const float tmp = x[k]; y[k] = c_b[0] * tmp + c_b[1] * m_x[0] + c_b[2] * m_x[1] - c_a[0] * m_y[0] - c_a[1] * m_y[1]; m_x[1] = m_x[0]; m_x[0] = tmp; m_y[1] = m_y[0]; m_y[0] = y[k]; } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/utility/cascaded_biquad_filter.h0000664000175000017500000000471714475643423031467 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_UTILITY_CASCADED_BIQUAD_FILTER_H_ #define MODULES_AUDIO_PROCESSING_UTILITY_CASCADED_BIQUAD_FILTER_H_ #include #include #include #include "api/array_view.h" namespace webrtc { // Applies a number of biquads in a cascaded manner. The filter implementation // is direct form 1. class CascadedBiQuadFilter { public: struct BiQuadParam { BiQuadParam(std::complex zero, std::complex pole, float gain, bool mirror_zero_along_i_axis = false); explicit BiQuadParam(const BiQuadParam&); std::complex zero; std::complex pole; float gain; bool mirror_zero_along_i_axis; }; struct BiQuadCoefficients { float b[3]; float a[2]; }; struct BiQuad { explicit BiQuad(const BiQuadCoefficients& coefficients) : coefficients(coefficients), x(), y() {} explicit BiQuad(const CascadedBiQuadFilter::BiQuadParam& param); void Reset(); BiQuadCoefficients coefficients; float x[2]; float y[2]; }; CascadedBiQuadFilter( const CascadedBiQuadFilter::BiQuadCoefficients& coefficients, size_t num_biquads); explicit CascadedBiQuadFilter( const std::vector& biquad_params); ~CascadedBiQuadFilter(); CascadedBiQuadFilter(const CascadedBiQuadFilter&) = delete; CascadedBiQuadFilter& operator=(const CascadedBiQuadFilter&) = delete; // Applies the biquads on the values in x in order to form the output in y. void Process(rtc::ArrayView x, rtc::ArrayView y); // Applies the biquads on the values in y in an in-place manner. void Process(rtc::ArrayView y); // Resets the filter to its initial state. void Reset(); private: void ApplyBiQuad(rtc::ArrayView x, rtc::ArrayView y, CascadedBiQuadFilter::BiQuad* biquad); std::vector biquads_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_UTILITY_CASCADED_BIQUAD_FILTER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/utility/delay_estimator.cc0000664000175000017500000006755214475643423030377 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/utility/delay_estimator.h" #include #include #include #include "rtc_base/checks.h" namespace webrtc { namespace { // Number of right shifts for scaling is linearly depending on number of bits in // the far-end binary spectrum. static const int kShiftsAtZero = 13; // Right shifts at zero binary spectrum. static const int kShiftsLinearSlope = 3; static const int32_t kProbabilityOffset = 1024; // 2 in Q9. static const int32_t kProbabilityLowerLimit = 8704; // 17 in Q9. static const int32_t kProbabilityMinSpread = 2816; // 5.5 in Q9. // Robust validation settings static const float kHistogramMax = 3000.f; static const float kLastHistogramMax = 250.f; static const float kMinHistogramThreshold = 1.5f; static const int kMinRequiredHits = 10; static const int kMaxHitsWhenPossiblyNonCausal = 10; static const int kMaxHitsWhenPossiblyCausal = 1000; static const float kQ14Scaling = 1.f / (1 << 14); // Scaling by 2^14 to get Q0. static const float kFractionSlope = 0.05f; static const float kMinFractionWhenPossiblyCausal = 0.5f; static const float kMinFractionWhenPossiblyNonCausal = 0.25f; } // namespace // Counts and returns number of bits of a 32-bit word. static int BitCount(uint32_t u32) { uint32_t tmp = u32 - ((u32 >> 1) & 033333333333) - ((u32 >> 2) & 011111111111); tmp = ((tmp + (tmp >> 3)) & 030707070707); tmp = (tmp + (tmp >> 6)); tmp = (tmp + (tmp >> 12) + (tmp >> 24)) & 077; return ((int)tmp); } // Compares the |binary_vector| with all rows of the |binary_matrix| and counts // per row the number of times they have the same value. // // Inputs: // - binary_vector : binary "vector" stored in a long // - binary_matrix : binary "matrix" stored as a vector of long // - matrix_size : size of binary "matrix" // // Output: // - bit_counts : "Vector" stored as a long, containing for each // row the number of times the matrix row and the // input vector have the same value // static void BitCountComparison(uint32_t binary_vector, const uint32_t* binary_matrix, int matrix_size, int32_t* bit_counts) { int n = 0; // Compare |binary_vector| with all rows of the |binary_matrix| for (; n < matrix_size; n++) { bit_counts[n] = (int32_t)BitCount(binary_vector ^ binary_matrix[n]); } } // Collects necessary statistics for the HistogramBasedValidation(). This // function has to be called prior to calling HistogramBasedValidation(). The // statistics updated and used by the HistogramBasedValidation() are: // 1. the number of |candidate_hits|, which states for how long we have had the // same |candidate_delay| // 2. the |histogram| of candidate delays over time. This histogram is // weighted with respect to a reliability measure and time-varying to cope // with possible delay shifts. // For further description see commented code. // // Inputs: // - candidate_delay : The delay to validate. // - valley_depth_q14 : The cost function has a valley/minimum at the // |candidate_delay| location. |valley_depth_q14| is the // cost function difference between the minimum and // maximum locations. The value is in the Q14 domain. // - valley_level_q14 : Is the cost function value at the minimum, in Q14. static void UpdateRobustValidationStatistics(BinaryDelayEstimator* self, int candidate_delay, int32_t valley_depth_q14, int32_t valley_level_q14) { const float valley_depth = valley_depth_q14 * kQ14Scaling; float decrease_in_last_set = valley_depth; const int max_hits_for_slow_change = (candidate_delay < self->last_delay) ? kMaxHitsWhenPossiblyNonCausal : kMaxHitsWhenPossiblyCausal; int i = 0; RTC_DCHECK_EQ(self->history_size, self->farend->history_size); // Reset |candidate_hits| if we have a new candidate. if (candidate_delay != self->last_candidate_delay) { self->candidate_hits = 0; self->last_candidate_delay = candidate_delay; } self->candidate_hits++; // The |histogram| is updated differently across the bins. // 1. The |candidate_delay| histogram bin is increased with the // |valley_depth|, which is a simple measure of how reliable the // |candidate_delay| is. The histogram is not increased above // |kHistogramMax|. self->histogram[candidate_delay] += valley_depth; if (self->histogram[candidate_delay] > kHistogramMax) { self->histogram[candidate_delay] = kHistogramMax; } // 2. The histogram bins in the neighborhood of |candidate_delay| are // unaffected. The neighborhood is defined as x + {-2, -1, 0, 1}. // 3. The histogram bins in the neighborhood of |last_delay| are decreased // with |decrease_in_last_set|. This value equals the difference between // the cost function values at the locations |candidate_delay| and // |last_delay| until we reach |max_hits_for_slow_change| consecutive hits // at the |candidate_delay|. If we exceed this amount of hits the // |candidate_delay| is a "potential" candidate and we start decreasing // these histogram bins more rapidly with |valley_depth|. if (self->candidate_hits < max_hits_for_slow_change) { decrease_in_last_set = (self->mean_bit_counts[self->compare_delay] - valley_level_q14) * kQ14Scaling; } // 4. All other bins are decreased with |valley_depth|. // TODO(bjornv): Investigate how to make this loop more efficient. Split up // the loop? Remove parts that doesn't add too much. for (i = 0; i < self->history_size; ++i) { int is_in_last_set = (i >= self->last_delay - 2) && (i <= self->last_delay + 1) && (i != candidate_delay); int is_in_candidate_set = (i >= candidate_delay - 2) && (i <= candidate_delay + 1); self->histogram[i] -= decrease_in_last_set * is_in_last_set + valley_depth * (!is_in_last_set && !is_in_candidate_set); // 5. No histogram bin can go below 0. if (self->histogram[i] < 0) { self->histogram[i] = 0; } } } // Validates the |candidate_delay|, estimated in WebRtc_ProcessBinarySpectrum(), // based on a mix of counting concurring hits with a modified histogram // of recent delay estimates. In brief a candidate is valid (returns 1) if it // is the most likely according to the histogram. There are a couple of // exceptions that are worth mentioning: // 1. If the |candidate_delay| < |last_delay| it can be that we are in a // non-causal state, breaking a possible echo control algorithm. Hence, we // open up for a quicker change by allowing the change even if the // |candidate_delay| is not the most likely one according to the histogram. // 2. There's a minimum number of hits (kMinRequiredHits) and the histogram // value has to reached a minimum (kMinHistogramThreshold) to be valid. // 3. The action is also depending on the filter length used for echo control. // If the delay difference is larger than what the filter can capture, we // also move quicker towards a change. // For further description see commented code. // // Input: // - candidate_delay : The delay to validate. // // Return value: // - is_histogram_valid : 1 - The |candidate_delay| is valid. // 0 - Otherwise. static int HistogramBasedValidation(const BinaryDelayEstimator* self, int candidate_delay) { float fraction = 1.f; float histogram_threshold = self->histogram[self->compare_delay]; const int delay_difference = candidate_delay - self->last_delay; int is_histogram_valid = 0; // The histogram based validation of |candidate_delay| is done by comparing // the |histogram| at bin |candidate_delay| with a |histogram_threshold|. // This |histogram_threshold| equals a |fraction| of the |histogram| at bin // |last_delay|. The |fraction| is a piecewise linear function of the // |delay_difference| between the |candidate_delay| and the |last_delay| // allowing for a quicker move if // i) a potential echo control filter can not handle these large differences. // ii) keeping |last_delay| instead of updating to |candidate_delay| could // force an echo control into a non-causal state. // We further require the histogram to have reached a minimum value of // |kMinHistogramThreshold|. In addition, we also require the number of // |candidate_hits| to be more than |kMinRequiredHits| to remove spurious // values. // Calculate a comparison histogram value (|histogram_threshold|) that is // depending on the distance between the |candidate_delay| and |last_delay|. // TODO(bjornv): How much can we gain by turning the fraction calculation // into tables? if (delay_difference > self->allowed_offset) { fraction = 1.f - kFractionSlope * (delay_difference - self->allowed_offset); fraction = (fraction > kMinFractionWhenPossiblyCausal ? fraction : kMinFractionWhenPossiblyCausal); } else if (delay_difference < 0) { fraction = kMinFractionWhenPossiblyNonCausal - kFractionSlope * delay_difference; fraction = (fraction > 1.f ? 1.f : fraction); } histogram_threshold *= fraction; histogram_threshold = (histogram_threshold > kMinHistogramThreshold ? histogram_threshold : kMinHistogramThreshold); is_histogram_valid = (self->histogram[candidate_delay] >= histogram_threshold) && (self->candidate_hits > kMinRequiredHits); return is_histogram_valid; } // Performs a robust validation of the |candidate_delay| estimated in // WebRtc_ProcessBinarySpectrum(). The algorithm takes the // |is_instantaneous_valid| and the |is_histogram_valid| and combines them // into a robust validation. The HistogramBasedValidation() has to be called // prior to this call. // For further description on how the combination is done, see commented code. // // Inputs: // - candidate_delay : The delay to validate. // - is_instantaneous_valid : The instantaneous validation performed in // WebRtc_ProcessBinarySpectrum(). // - is_histogram_valid : The histogram based validation. // // Return value: // - is_robust : 1 - The candidate_delay is valid according to a // combination of the two inputs. // : 0 - Otherwise. static int RobustValidation(const BinaryDelayEstimator* self, int candidate_delay, int is_instantaneous_valid, int is_histogram_valid) { int is_robust = 0; // The final robust validation is based on the two algorithms; 1) the // |is_instantaneous_valid| and 2) the histogram based with result stored in // |is_histogram_valid|. // i) Before we actually have a valid estimate (|last_delay| == -2), we say // a candidate is valid if either algorithm states so // (|is_instantaneous_valid| OR |is_histogram_valid|). is_robust = (self->last_delay < 0) && (is_instantaneous_valid || is_histogram_valid); // ii) Otherwise, we need both algorithms to be certain // (|is_instantaneous_valid| AND |is_histogram_valid|) is_robust |= is_instantaneous_valid && is_histogram_valid; // iii) With one exception, i.e., the histogram based algorithm can overrule // the instantaneous one if |is_histogram_valid| = 1 and the histogram // is significantly strong. is_robust |= is_histogram_valid && (self->histogram[candidate_delay] > self->last_delay_histogram); return is_robust; } void WebRtc_FreeBinaryDelayEstimatorFarend(BinaryDelayEstimatorFarend* self) { if (self == NULL) { return; } free(self->binary_far_history); self->binary_far_history = NULL; free(self->far_bit_counts); self->far_bit_counts = NULL; free(self); } BinaryDelayEstimatorFarend* WebRtc_CreateBinaryDelayEstimatorFarend( int history_size) { BinaryDelayEstimatorFarend* self = NULL; if (history_size > 1) { // Sanity conditions fulfilled. self = static_cast( malloc(sizeof(BinaryDelayEstimatorFarend))); } if (self == NULL) { return NULL; } self->history_size = 0; self->binary_far_history = NULL; self->far_bit_counts = NULL; if (WebRtc_AllocateFarendBufferMemory(self, history_size) == 0) { WebRtc_FreeBinaryDelayEstimatorFarend(self); self = NULL; } return self; } int WebRtc_AllocateFarendBufferMemory(BinaryDelayEstimatorFarend* self, int history_size) { RTC_DCHECK(self); // (Re-)Allocate memory for history buffers. self->binary_far_history = static_cast( realloc(self->binary_far_history, history_size * sizeof(*self->binary_far_history))); self->far_bit_counts = static_cast(realloc( self->far_bit_counts, history_size * sizeof(*self->far_bit_counts))); if ((self->binary_far_history == NULL) || (self->far_bit_counts == NULL)) { history_size = 0; } // Fill with zeros if we have expanded the buffers. if (history_size > self->history_size) { int size_diff = history_size - self->history_size; memset(&self->binary_far_history[self->history_size], 0, sizeof(*self->binary_far_history) * size_diff); memset(&self->far_bit_counts[self->history_size], 0, sizeof(*self->far_bit_counts) * size_diff); } self->history_size = history_size; return self->history_size; } void WebRtc_InitBinaryDelayEstimatorFarend(BinaryDelayEstimatorFarend* self) { RTC_DCHECK(self); memset(self->binary_far_history, 0, sizeof(uint32_t) * self->history_size); memset(self->far_bit_counts, 0, sizeof(int) * self->history_size); } void WebRtc_SoftResetBinaryDelayEstimatorFarend( BinaryDelayEstimatorFarend* self, int delay_shift) { int abs_shift = abs(delay_shift); int shift_size = 0; int dest_index = 0; int src_index = 0; int padding_index = 0; RTC_DCHECK(self); shift_size = self->history_size - abs_shift; RTC_DCHECK_GT(shift_size, 0); if (delay_shift == 0) { return; } else if (delay_shift > 0) { dest_index = abs_shift; } else if (delay_shift < 0) { src_index = abs_shift; padding_index = shift_size; } // Shift and zero pad buffers. memmove(&self->binary_far_history[dest_index], &self->binary_far_history[src_index], sizeof(*self->binary_far_history) * shift_size); memset(&self->binary_far_history[padding_index], 0, sizeof(*self->binary_far_history) * abs_shift); memmove(&self->far_bit_counts[dest_index], &self->far_bit_counts[src_index], sizeof(*self->far_bit_counts) * shift_size); memset(&self->far_bit_counts[padding_index], 0, sizeof(*self->far_bit_counts) * abs_shift); } void WebRtc_AddBinaryFarSpectrum(BinaryDelayEstimatorFarend* handle, uint32_t binary_far_spectrum) { RTC_DCHECK(handle); // Shift binary spectrum history and insert current |binary_far_spectrum|. memmove(&(handle->binary_far_history[1]), &(handle->binary_far_history[0]), (handle->history_size - 1) * sizeof(uint32_t)); handle->binary_far_history[0] = binary_far_spectrum; // Shift history of far-end binary spectrum bit counts and insert bit count // of current |binary_far_spectrum|. memmove(&(handle->far_bit_counts[1]), &(handle->far_bit_counts[0]), (handle->history_size - 1) * sizeof(int)); handle->far_bit_counts[0] = BitCount(binary_far_spectrum); } void WebRtc_FreeBinaryDelayEstimator(BinaryDelayEstimator* self) { if (self == NULL) { return; } free(self->mean_bit_counts); self->mean_bit_counts = NULL; free(self->bit_counts); self->bit_counts = NULL; free(self->binary_near_history); self->binary_near_history = NULL; free(self->histogram); self->histogram = NULL; // BinaryDelayEstimator does not have ownership of |farend|, hence we do not // free the memory here. That should be handled separately by the user. self->farend = NULL; free(self); } BinaryDelayEstimator* WebRtc_CreateBinaryDelayEstimator( BinaryDelayEstimatorFarend* farend, int max_lookahead) { BinaryDelayEstimator* self = NULL; if ((farend != NULL) && (max_lookahead >= 0)) { // Sanity conditions fulfilled. self = static_cast( malloc(sizeof(BinaryDelayEstimator))); } if (self == NULL) { return NULL; } self->farend = farend; self->near_history_size = max_lookahead + 1; self->history_size = 0; self->robust_validation_enabled = 0; // Disabled by default. self->allowed_offset = 0; self->lookahead = max_lookahead; // Allocate memory for spectrum and history buffers. self->mean_bit_counts = NULL; self->bit_counts = NULL; self->histogram = NULL; self->binary_near_history = static_cast( malloc((max_lookahead + 1) * sizeof(*self->binary_near_history))); if (self->binary_near_history == NULL || WebRtc_AllocateHistoryBufferMemory(self, farend->history_size) == 0) { WebRtc_FreeBinaryDelayEstimator(self); self = NULL; } return self; } int WebRtc_AllocateHistoryBufferMemory(BinaryDelayEstimator* self, int history_size) { BinaryDelayEstimatorFarend* far = self->farend; // (Re-)Allocate memory for spectrum and history buffers. if (history_size != far->history_size) { // Only update far-end buffers if we need. history_size = WebRtc_AllocateFarendBufferMemory(far, history_size); } // The extra array element in |mean_bit_counts| and |histogram| is a dummy // element only used while |last_delay| == -2, i.e., before we have a valid // estimate. self->mean_bit_counts = static_cast( realloc(self->mean_bit_counts, (history_size + 1) * sizeof(*self->mean_bit_counts))); self->bit_counts = static_cast( realloc(self->bit_counts, history_size * sizeof(*self->bit_counts))); self->histogram = static_cast( realloc(self->histogram, (history_size + 1) * sizeof(*self->histogram))); if ((self->mean_bit_counts == NULL) || (self->bit_counts == NULL) || (self->histogram == NULL)) { history_size = 0; } // Fill with zeros if we have expanded the buffers. if (history_size > self->history_size) { int size_diff = history_size - self->history_size; memset(&self->mean_bit_counts[self->history_size], 0, sizeof(*self->mean_bit_counts) * size_diff); memset(&self->bit_counts[self->history_size], 0, sizeof(*self->bit_counts) * size_diff); memset(&self->histogram[self->history_size], 0, sizeof(*self->histogram) * size_diff); } self->history_size = history_size; return self->history_size; } void WebRtc_InitBinaryDelayEstimator(BinaryDelayEstimator* self) { int i = 0; RTC_DCHECK(self); memset(self->bit_counts, 0, sizeof(int32_t) * self->history_size); memset(self->binary_near_history, 0, sizeof(uint32_t) * self->near_history_size); for (i = 0; i <= self->history_size; ++i) { self->mean_bit_counts[i] = (20 << 9); // 20 in Q9. self->histogram[i] = 0.f; } self->minimum_probability = kMaxBitCountsQ9; // 32 in Q9. self->last_delay_probability = (int)kMaxBitCountsQ9; // 32 in Q9. // Default return value if we're unable to estimate. -1 is used for errors. self->last_delay = -2; self->last_candidate_delay = -2; self->compare_delay = self->history_size; self->candidate_hits = 0; self->last_delay_histogram = 0.f; } int WebRtc_SoftResetBinaryDelayEstimator(BinaryDelayEstimator* self, int delay_shift) { int lookahead = 0; RTC_DCHECK(self); lookahead = self->lookahead; self->lookahead -= delay_shift; if (self->lookahead < 0) { self->lookahead = 0; } if (self->lookahead > self->near_history_size - 1) { self->lookahead = self->near_history_size - 1; } return lookahead - self->lookahead; } int WebRtc_ProcessBinarySpectrum(BinaryDelayEstimator* self, uint32_t binary_near_spectrum) { int i = 0; int candidate_delay = -1; int valid_candidate = 0; int32_t value_best_candidate = kMaxBitCountsQ9; int32_t value_worst_candidate = 0; int32_t valley_depth = 0; RTC_DCHECK(self); if (self->farend->history_size != self->history_size) { // Non matching history sizes. return -1; } if (self->near_history_size > 1) { // If we apply lookahead, shift near-end binary spectrum history. Insert // current |binary_near_spectrum| and pull out the delayed one. memmove(&(self->binary_near_history[1]), &(self->binary_near_history[0]), (self->near_history_size - 1) * sizeof(uint32_t)); self->binary_near_history[0] = binary_near_spectrum; binary_near_spectrum = self->binary_near_history[self->lookahead]; } // Compare with delayed spectra and store the |bit_counts| for each delay. BitCountComparison(binary_near_spectrum, self->farend->binary_far_history, self->history_size, self->bit_counts); // Update |mean_bit_counts|, which is the smoothed version of |bit_counts|. for (i = 0; i < self->history_size; i++) { // |bit_counts| is constrained to [0, 32], meaning we can smooth with a // factor up to 2^26. We use Q9. int32_t bit_count = (self->bit_counts[i] << 9); // Q9. // Update |mean_bit_counts| only when far-end signal has something to // contribute. If |far_bit_counts| is zero the far-end signal is weak and // we likely have a poor echo condition, hence don't update. if (self->farend->far_bit_counts[i] > 0) { // Make number of right shifts piecewise linear w.r.t. |far_bit_counts|. int shifts = kShiftsAtZero; shifts -= (kShiftsLinearSlope * self->farend->far_bit_counts[i]) >> 4; WebRtc_MeanEstimatorFix(bit_count, shifts, &(self->mean_bit_counts[i])); } } // Find |candidate_delay|, |value_best_candidate| and |value_worst_candidate| // of |mean_bit_counts|. for (i = 0; i < self->history_size; i++) { if (self->mean_bit_counts[i] < value_best_candidate) { value_best_candidate = self->mean_bit_counts[i]; candidate_delay = i; } if (self->mean_bit_counts[i] > value_worst_candidate) { value_worst_candidate = self->mean_bit_counts[i]; } } valley_depth = value_worst_candidate - value_best_candidate; // The |value_best_candidate| is a good indicator on the probability of // |candidate_delay| being an accurate delay (a small |value_best_candidate| // means a good binary match). In the following sections we make a decision // whether to update |last_delay| or not. // 1) If the difference bit counts between the best and the worst delay // candidates is too small we consider the situation to be unreliable and // don't update |last_delay|. // 2) If the situation is reliable we update |last_delay| if the value of the // best candidate delay has a value less than // i) an adaptive threshold |minimum_probability|, or // ii) this corresponding value |last_delay_probability|, but updated at // this time instant. // Update |minimum_probability|. if ((self->minimum_probability > kProbabilityLowerLimit) && (valley_depth > kProbabilityMinSpread)) { // The "hard" threshold can't be lower than 17 (in Q9). // The valley in the curve also has to be distinct, i.e., the // difference between |value_worst_candidate| and |value_best_candidate| has // to be large enough. int32_t threshold = value_best_candidate + kProbabilityOffset; if (threshold < kProbabilityLowerLimit) { threshold = kProbabilityLowerLimit; } if (self->minimum_probability > threshold) { self->minimum_probability = threshold; } } // Update |last_delay_probability|. // We use a Markov type model, i.e., a slowly increasing level over time. self->last_delay_probability++; // Validate |candidate_delay|. We have a reliable instantaneous delay // estimate if // 1) The valley is distinct enough (|valley_depth| > |kProbabilityOffset|) // and // 2) The depth of the valley is deep enough // (|value_best_candidate| < |minimum_probability|) // and deeper than the best estimate so far // (|value_best_candidate| < |last_delay_probability|) valid_candidate = ((valley_depth > kProbabilityOffset) && ((value_best_candidate < self->minimum_probability) || (value_best_candidate < self->last_delay_probability))); // Check for nonstationary farend signal. const bool non_stationary_farend = std::any_of(self->farend->far_bit_counts, self->farend->far_bit_counts + self->history_size, [](int a) { return a > 0; }); if (non_stationary_farend) { // Only update the validation statistics when the farend is nonstationary // as the underlying estimates are otherwise frozen. UpdateRobustValidationStatistics(self, candidate_delay, valley_depth, value_best_candidate); } if (self->robust_validation_enabled) { int is_histogram_valid = HistogramBasedValidation(self, candidate_delay); valid_candidate = RobustValidation(self, candidate_delay, valid_candidate, is_histogram_valid); } // Only update the delay estimate when the farend is nonstationary and when // a valid delay candidate is available. if (non_stationary_farend && valid_candidate) { if (candidate_delay != self->last_delay) { self->last_delay_histogram = (self->histogram[candidate_delay] > kLastHistogramMax ? kLastHistogramMax : self->histogram[candidate_delay]); // Adjust the histogram if we made a change to |last_delay|, though it was // not the most likely one according to the histogram. if (self->histogram[candidate_delay] < self->histogram[self->compare_delay]) { self->histogram[self->compare_delay] = self->histogram[candidate_delay]; } } self->last_delay = candidate_delay; if (value_best_candidate < self->last_delay_probability) { self->last_delay_probability = value_best_candidate; } self->compare_delay = self->last_delay; } return self->last_delay; } int WebRtc_binary_last_delay(BinaryDelayEstimator* self) { RTC_DCHECK(self); return self->last_delay; } float WebRtc_binary_last_delay_quality(BinaryDelayEstimator* self) { float quality = 0; RTC_DCHECK(self); if (self->robust_validation_enabled) { // Simply a linear function of the histogram height at delay estimate. quality = self->histogram[self->compare_delay] / kHistogramMax; } else { // Note that |last_delay_probability| states how deep the minimum of the // cost function is, so it is rather an error probability. quality = (float)(kMaxBitCountsQ9 - self->last_delay_probability) / kMaxBitCountsQ9; if (quality < 0) { quality = 0; } } return quality; } void WebRtc_MeanEstimatorFix(int32_t new_value, int factor, int32_t* mean_value) { int32_t diff = new_value - *mean_value; // mean_new = mean_value + ((new_value - mean_value) >> factor); if (diff < 0) { diff = -((-diff) >> factor); } else { diff = (diff >> factor); } *mean_value += diff; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/utility/delay_estimator.h0000664000175000017500000002174314475643423030231 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Performs delay estimation on binary converted spectra. // The return value is 0 - OK and -1 - Error, unless otherwise stated. #ifndef MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_ #define MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_ #include namespace webrtc { static const int32_t kMaxBitCountsQ9 = (32 << 9); // 32 matching bits in Q9. typedef struct { // Pointer to bit counts. int* far_bit_counts; // Binary history variables. uint32_t* binary_far_history; int history_size; } BinaryDelayEstimatorFarend; typedef struct { // Pointer to bit counts. int32_t* mean_bit_counts; // Array only used locally in ProcessBinarySpectrum() but whose size is // determined at run-time. int32_t* bit_counts; // Binary history variables. uint32_t* binary_near_history; int near_history_size; int history_size; // Delay estimation variables. int32_t minimum_probability; int last_delay_probability; // Delay memory. int last_delay; // Robust validation int robust_validation_enabled; int allowed_offset; int last_candidate_delay; int compare_delay; int candidate_hits; float* histogram; float last_delay_histogram; // For dynamically changing the lookahead when using SoftReset...(). int lookahead; // Far-end binary spectrum history buffer etc. BinaryDelayEstimatorFarend* farend; } BinaryDelayEstimator; // Releases the memory allocated by // WebRtc_CreateBinaryDelayEstimatorFarend(...). // Input: // - self : Pointer to the binary delay estimation far-end // instance which is the return value of // WebRtc_CreateBinaryDelayEstimatorFarend(). // void WebRtc_FreeBinaryDelayEstimatorFarend(BinaryDelayEstimatorFarend* self); // Allocates the memory needed by the far-end part of the binary delay // estimation. The memory needs to be initialized separately through // WebRtc_InitBinaryDelayEstimatorFarend(...). // // Inputs: // - history_size : Size of the far-end binary spectrum history. // // Return value: // - BinaryDelayEstimatorFarend* // : Created |handle|. If the memory can't be allocated // or if any of the input parameters are invalid NULL // is returned. // BinaryDelayEstimatorFarend* WebRtc_CreateBinaryDelayEstimatorFarend( int history_size); // Re-allocates the buffers. // // Inputs: // - self : Pointer to the binary estimation far-end instance // which is the return value of // WebRtc_CreateBinaryDelayEstimatorFarend(). // - history_size : Size of the far-end binary spectrum history. // // Return value: // - history_size : The history size allocated. int WebRtc_AllocateFarendBufferMemory(BinaryDelayEstimatorFarend* self, int history_size); // Initializes the delay estimation far-end instance created with // WebRtc_CreateBinaryDelayEstimatorFarend(...). // // Input: // - self : Pointer to the delay estimation far-end instance. // // Output: // - self : Initialized far-end instance. // void WebRtc_InitBinaryDelayEstimatorFarend(BinaryDelayEstimatorFarend* self); // Soft resets the delay estimation far-end instance created with // WebRtc_CreateBinaryDelayEstimatorFarend(...). // // Input: // - delay_shift : The amount of blocks to shift history buffers. // void WebRtc_SoftResetBinaryDelayEstimatorFarend( BinaryDelayEstimatorFarend* self, int delay_shift); // Adds the binary far-end spectrum to the internal far-end history buffer. This // spectrum is used as reference when calculating the delay using // WebRtc_ProcessBinarySpectrum(). // // Inputs: // - self : Pointer to the delay estimation far-end // instance. // - binary_far_spectrum : Far-end binary spectrum. // // Output: // - self : Updated far-end instance. // void WebRtc_AddBinaryFarSpectrum(BinaryDelayEstimatorFarend* self, uint32_t binary_far_spectrum); // Releases the memory allocated by WebRtc_CreateBinaryDelayEstimator(...). // // Note that BinaryDelayEstimator utilizes BinaryDelayEstimatorFarend, but does // not take ownership of it, hence the BinaryDelayEstimator has to be torn down // before the far-end. // // Input: // - self : Pointer to the binary delay estimation instance // which is the return value of // WebRtc_CreateBinaryDelayEstimator(). // void WebRtc_FreeBinaryDelayEstimator(BinaryDelayEstimator* self); // Allocates the memory needed by the binary delay estimation. The memory needs // to be initialized separately through WebRtc_InitBinaryDelayEstimator(...). // // See WebRtc_CreateDelayEstimator(..) in delay_estimator_wrapper.c for detailed // description. BinaryDelayEstimator* WebRtc_CreateBinaryDelayEstimator( BinaryDelayEstimatorFarend* farend, int max_lookahead); // Re-allocates |history_size| dependent buffers. The far-end buffers will be // updated at the same time if needed. // // Input: // - self : Pointer to the binary estimation instance which is // the return value of // WebRtc_CreateBinaryDelayEstimator(). // - history_size : Size of the history buffers. // // Return value: // - history_size : The history size allocated. int WebRtc_AllocateHistoryBufferMemory(BinaryDelayEstimator* self, int history_size); // Initializes the delay estimation instance created with // WebRtc_CreateBinaryDelayEstimator(...). // // Input: // - self : Pointer to the delay estimation instance. // // Output: // - self : Initialized instance. // void WebRtc_InitBinaryDelayEstimator(BinaryDelayEstimator* self); // Soft resets the delay estimation instance created with // WebRtc_CreateBinaryDelayEstimator(...). // // Input: // - delay_shift : The amount of blocks to shift history buffers. // // Return value: // - actual_shifts : The actual number of shifts performed. // int WebRtc_SoftResetBinaryDelayEstimator(BinaryDelayEstimator* self, int delay_shift); // Estimates and returns the delay between the binary far-end and binary near- // end spectra. It is assumed the binary far-end spectrum has been added using // WebRtc_AddBinaryFarSpectrum() prior to this call. The value will be offset by // the lookahead (i.e. the lookahead should be subtracted from the returned // value). // // Inputs: // - self : Pointer to the delay estimation instance. // - binary_near_spectrum : Near-end binary spectrum of the current block. // // Output: // - self : Updated instance. // // Return value: // - delay : >= 0 - Calculated delay value. // -2 - Insufficient data for estimation. // int WebRtc_ProcessBinarySpectrum(BinaryDelayEstimator* self, uint32_t binary_near_spectrum); // Returns the last calculated delay updated by the function // WebRtc_ProcessBinarySpectrum(...). // // Input: // - self : Pointer to the delay estimation instance. // // Return value: // - delay : >= 0 - Last calculated delay value // -2 - Insufficient data for estimation. // int WebRtc_binary_last_delay(BinaryDelayEstimator* self); // Returns the estimation quality of the last calculated delay updated by the // function WebRtc_ProcessBinarySpectrum(...). The estimation quality is a value // in the interval [0, 1]. The higher the value, the better the quality. // // Return value: // - delay_quality : >= 0 - Estimation quality of last calculated // delay value. float WebRtc_binary_last_delay_quality(BinaryDelayEstimator* self); // Updates the |mean_value| recursively with a step size of 2^-|factor|. This // function is used internally in the Binary Delay Estimator as well as the // Fixed point wrapper. // // Inputs: // - new_value : The new value the mean should be updated with. // - factor : The step size, in number of right shifts. // // Input/Output: // - mean_value : Pointer to the mean value. // void WebRtc_MeanEstimatorFix(int32_t new_value, int factor, int32_t* mean_value); } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/utility/delay_estimator_internal.h0000664000175000017500000000274114475643423032122 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Header file including the delay estimator handle used for testing. #ifndef MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_INTERNAL_H_ #define MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_INTERNAL_H_ #include "modules/audio_processing/utility/delay_estimator.h" namespace webrtc { typedef union { float float_; int32_t int32_; } SpectrumType; typedef struct { // Pointers to mean values of spectrum. SpectrumType* mean_far_spectrum; // |mean_far_spectrum| initialization indicator. int far_spectrum_initialized; int spectrum_size; // Far-end part of binary spectrum based delay estimation. BinaryDelayEstimatorFarend* binary_farend; } DelayEstimatorFarend; typedef struct { // Pointers to mean values of spectrum. SpectrumType* mean_near_spectrum; // |mean_near_spectrum| initialization indicator. int near_spectrum_initialized; int spectrum_size; // Binary spectrum based delay estimator BinaryDelayEstimator* binary_handle; } DelayEstimator; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_INTERNAL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.cc0000664000175000017500000003360014475643423032122 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/utility/delay_estimator_wrapper.h" #include #include #include "modules/audio_processing/utility/delay_estimator.h" #include "modules/audio_processing/utility/delay_estimator_internal.h" #include "rtc_base/checks.h" namespace webrtc { // Only bit |kBandFirst| through bit |kBandLast| are processed and // |kBandFirst| - |kBandLast| must be < 32. enum { kBandFirst = 12 }; enum { kBandLast = 43 }; static __inline uint32_t SetBit(uint32_t in, int pos) { uint32_t mask = (1 << pos); uint32_t out = (in | mask); return out; } // Calculates the mean recursively. Same version as WebRtc_MeanEstimatorFix(), // but for float. // // Inputs: // - new_value : New additional value. // - scale : Scale for smoothing (should be less than 1.0). // // Input/Output: // - mean_value : Pointer to the mean value for updating. // static void MeanEstimatorFloat(float new_value, float scale, float* mean_value) { RTC_DCHECK_LT(scale, 1.0f); *mean_value += (new_value - *mean_value) * scale; } // Computes the binary spectrum by comparing the input |spectrum| with a // |threshold_spectrum|. Float and fixed point versions. // // Inputs: // - spectrum : Spectrum of which the binary spectrum should be // calculated. // - threshold_spectrum : Threshold spectrum with which the input // spectrum is compared. // Return: // - out : Binary spectrum. // static uint32_t BinarySpectrumFix(const uint16_t* spectrum, SpectrumType* threshold_spectrum, int q_domain, int* threshold_initialized) { int i = kBandFirst; uint32_t out = 0; RTC_DCHECK_LT(q_domain, 16); if (!(*threshold_initialized)) { // Set the |threshold_spectrum| to half the input |spectrum| as starting // value. This speeds up the convergence. for (i = kBandFirst; i <= kBandLast; i++) { if (spectrum[i] > 0) { // Convert input spectrum from Q(|q_domain|) to Q15. int32_t spectrum_q15 = ((int32_t)spectrum[i]) << (15 - q_domain); threshold_spectrum[i].int32_ = (spectrum_q15 >> 1); *threshold_initialized = 1; } } } for (i = kBandFirst; i <= kBandLast; i++) { // Convert input spectrum from Q(|q_domain|) to Q15. int32_t spectrum_q15 = ((int32_t)spectrum[i]) << (15 - q_domain); // Update the |threshold_spectrum|. WebRtc_MeanEstimatorFix(spectrum_q15, 6, &(threshold_spectrum[i].int32_)); // Convert |spectrum| at current frequency bin to a binary value. if (spectrum_q15 > threshold_spectrum[i].int32_) { out = SetBit(out, i - kBandFirst); } } return out; } static uint32_t BinarySpectrumFloat(const float* spectrum, SpectrumType* threshold_spectrum, int* threshold_initialized) { int i = kBandFirst; uint32_t out = 0; const float kScale = 1 / 64.0; if (!(*threshold_initialized)) { // Set the |threshold_spectrum| to half the input |spectrum| as starting // value. This speeds up the convergence. for (i = kBandFirst; i <= kBandLast; i++) { if (spectrum[i] > 0.0f) { threshold_spectrum[i].float_ = (spectrum[i] / 2); *threshold_initialized = 1; } } } for (i = kBandFirst; i <= kBandLast; i++) { // Update the |threshold_spectrum|. MeanEstimatorFloat(spectrum[i], kScale, &(threshold_spectrum[i].float_)); // Convert |spectrum| at current frequency bin to a binary value. if (spectrum[i] > threshold_spectrum[i].float_) { out = SetBit(out, i - kBandFirst); } } return out; } void WebRtc_FreeDelayEstimatorFarend(void* handle) { DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle; if (handle == NULL) { return; } free(self->mean_far_spectrum); self->mean_far_spectrum = NULL; WebRtc_FreeBinaryDelayEstimatorFarend(self->binary_farend); self->binary_farend = NULL; free(self); } void* WebRtc_CreateDelayEstimatorFarend(int spectrum_size, int history_size) { DelayEstimatorFarend* self = NULL; // Check if the sub band used in the delay estimation is small enough to fit // the binary spectra in a uint32_t. static_assert(kBandLast - kBandFirst < 32, ""); if (spectrum_size >= kBandLast) { self = static_cast( malloc(sizeof(DelayEstimatorFarend))); } if (self != NULL) { int memory_fail = 0; // Allocate memory for the binary far-end spectrum handling. self->binary_farend = WebRtc_CreateBinaryDelayEstimatorFarend(history_size); memory_fail |= (self->binary_farend == NULL); // Allocate memory for spectrum buffers. self->mean_far_spectrum = static_cast( malloc(spectrum_size * sizeof(SpectrumType))); memory_fail |= (self->mean_far_spectrum == NULL); self->spectrum_size = spectrum_size; if (memory_fail) { WebRtc_FreeDelayEstimatorFarend(self); self = NULL; } } return self; } int WebRtc_InitDelayEstimatorFarend(void* handle) { DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle; if (self == NULL) { return -1; } // Initialize far-end part of binary delay estimator. WebRtc_InitBinaryDelayEstimatorFarend(self->binary_farend); // Set averaged far and near end spectra to zero. memset(self->mean_far_spectrum, 0, sizeof(SpectrumType) * self->spectrum_size); // Reset initialization indicators. self->far_spectrum_initialized = 0; return 0; } void WebRtc_SoftResetDelayEstimatorFarend(void* handle, int delay_shift) { DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle; RTC_DCHECK(self); WebRtc_SoftResetBinaryDelayEstimatorFarend(self->binary_farend, delay_shift); } int WebRtc_AddFarSpectrumFix(void* handle, const uint16_t* far_spectrum, int spectrum_size, int far_q) { DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle; uint32_t binary_spectrum = 0; if (self == NULL) { return -1; } if (far_spectrum == NULL) { // Empty far end spectrum. return -1; } if (spectrum_size != self->spectrum_size) { // Data sizes don't match. return -1; } if (far_q > 15) { // If |far_q| is larger than 15 we cannot guarantee no wrap around. return -1; } // Get binary spectrum. binary_spectrum = BinarySpectrumFix(far_spectrum, self->mean_far_spectrum, far_q, &(self->far_spectrum_initialized)); WebRtc_AddBinaryFarSpectrum(self->binary_farend, binary_spectrum); return 0; } int WebRtc_AddFarSpectrumFloat(void* handle, const float* far_spectrum, int spectrum_size) { DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle; uint32_t binary_spectrum = 0; if (self == NULL) { return -1; } if (far_spectrum == NULL) { // Empty far end spectrum. return -1; } if (spectrum_size != self->spectrum_size) { // Data sizes don't match. return -1; } // Get binary spectrum. binary_spectrum = BinarySpectrumFloat(far_spectrum, self->mean_far_spectrum, &(self->far_spectrum_initialized)); WebRtc_AddBinaryFarSpectrum(self->binary_farend, binary_spectrum); return 0; } void WebRtc_FreeDelayEstimator(void* handle) { DelayEstimator* self = (DelayEstimator*)handle; if (handle == NULL) { return; } free(self->mean_near_spectrum); self->mean_near_spectrum = NULL; WebRtc_FreeBinaryDelayEstimator(self->binary_handle); self->binary_handle = NULL; free(self); } void* WebRtc_CreateDelayEstimator(void* farend_handle, int max_lookahead) { DelayEstimator* self = NULL; DelayEstimatorFarend* farend = (DelayEstimatorFarend*)farend_handle; if (farend_handle != NULL) { self = static_cast(malloc(sizeof(DelayEstimator))); } if (self != NULL) { int memory_fail = 0; // Allocate memory for the farend spectrum handling. self->binary_handle = WebRtc_CreateBinaryDelayEstimator(farend->binary_farend, max_lookahead); memory_fail |= (self->binary_handle == NULL); // Allocate memory for spectrum buffers. self->mean_near_spectrum = static_cast( malloc(farend->spectrum_size * sizeof(SpectrumType))); memory_fail |= (self->mean_near_spectrum == NULL); self->spectrum_size = farend->spectrum_size; if (memory_fail) { WebRtc_FreeDelayEstimator(self); self = NULL; } } return self; } int WebRtc_InitDelayEstimator(void* handle) { DelayEstimator* self = (DelayEstimator*)handle; if (self == NULL) { return -1; } // Initialize binary delay estimator. WebRtc_InitBinaryDelayEstimator(self->binary_handle); // Set averaged far and near end spectra to zero. memset(self->mean_near_spectrum, 0, sizeof(SpectrumType) * self->spectrum_size); // Reset initialization indicators. self->near_spectrum_initialized = 0; return 0; } int WebRtc_SoftResetDelayEstimator(void* handle, int delay_shift) { DelayEstimator* self = (DelayEstimator*)handle; RTC_DCHECK(self); return WebRtc_SoftResetBinaryDelayEstimator(self->binary_handle, delay_shift); } int WebRtc_set_history_size(void* handle, int history_size) { DelayEstimator* self = static_cast(handle); if ((self == NULL) || (history_size <= 1)) { return -1; } return WebRtc_AllocateHistoryBufferMemory(self->binary_handle, history_size); } int WebRtc_history_size(const void* handle) { const DelayEstimator* self = static_cast(handle); if (self == NULL) { return -1; } if (self->binary_handle->farend->history_size != self->binary_handle->history_size) { // Non matching history sizes. return -1; } return self->binary_handle->history_size; } int WebRtc_set_lookahead(void* handle, int lookahead) { DelayEstimator* self = (DelayEstimator*)handle; RTC_DCHECK(self); RTC_DCHECK(self->binary_handle); if ((lookahead > self->binary_handle->near_history_size - 1) || (lookahead < 0)) { return -1; } self->binary_handle->lookahead = lookahead; return self->binary_handle->lookahead; } int WebRtc_lookahead(void* handle) { DelayEstimator* self = (DelayEstimator*)handle; RTC_DCHECK(self); RTC_DCHECK(self->binary_handle); return self->binary_handle->lookahead; } int WebRtc_set_allowed_offset(void* handle, int allowed_offset) { DelayEstimator* self = (DelayEstimator*)handle; if ((self == NULL) || (allowed_offset < 0)) { return -1; } self->binary_handle->allowed_offset = allowed_offset; return 0; } int WebRtc_get_allowed_offset(const void* handle) { const DelayEstimator* self = (const DelayEstimator*)handle; if (self == NULL) { return -1; } return self->binary_handle->allowed_offset; } int WebRtc_enable_robust_validation(void* handle, int enable) { DelayEstimator* self = (DelayEstimator*)handle; if (self == NULL) { return -1; } if ((enable < 0) || (enable > 1)) { return -1; } RTC_DCHECK(self->binary_handle); self->binary_handle->robust_validation_enabled = enable; return 0; } int WebRtc_is_robust_validation_enabled(const void* handle) { const DelayEstimator* self = (const DelayEstimator*)handle; if (self == NULL) { return -1; } return self->binary_handle->robust_validation_enabled; } int WebRtc_DelayEstimatorProcessFix(void* handle, const uint16_t* near_spectrum, int spectrum_size, int near_q) { DelayEstimator* self = (DelayEstimator*)handle; uint32_t binary_spectrum = 0; if (self == NULL) { return -1; } if (near_spectrum == NULL) { // Empty near end spectrum. return -1; } if (spectrum_size != self->spectrum_size) { // Data sizes don't match. return -1; } if (near_q > 15) { // If |near_q| is larger than 15 we cannot guarantee no wrap around. return -1; } // Get binary spectra. binary_spectrum = BinarySpectrumFix(near_spectrum, self->mean_near_spectrum, near_q, &(self->near_spectrum_initialized)); return WebRtc_ProcessBinarySpectrum(self->binary_handle, binary_spectrum); } int WebRtc_DelayEstimatorProcessFloat(void* handle, const float* near_spectrum, int spectrum_size) { DelayEstimator* self = (DelayEstimator*)handle; uint32_t binary_spectrum = 0; if (self == NULL) { return -1; } if (near_spectrum == NULL) { // Empty near end spectrum. return -1; } if (spectrum_size != self->spectrum_size) { // Data sizes don't match. return -1; } // Get binary spectrum. binary_spectrum = BinarySpectrumFloat(near_spectrum, self->mean_near_spectrum, &(self->near_spectrum_initialized)); return WebRtc_ProcessBinarySpectrum(self->binary_handle, binary_spectrum); } int WebRtc_last_delay(void* handle) { DelayEstimator* self = (DelayEstimator*)handle; if (self == NULL) { return -1; } return WebRtc_binary_last_delay(self->binary_handle); } float WebRtc_last_delay_quality(void* handle) { DelayEstimator* self = (DelayEstimator*)handle; RTC_DCHECK(self); return WebRtc_binary_last_delay_quality(self->binary_handle); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h0000664000175000017500000002560214475643423031767 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Performs delay estimation on block by block basis. // The return value is 0 - OK and -1 - Error, unless otherwise stated. #ifndef MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_ #define MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_ #include namespace webrtc { // Releases the memory allocated by WebRtc_CreateDelayEstimatorFarend(...) void WebRtc_FreeDelayEstimatorFarend(void* handle); // Allocates the memory needed by the far-end part of the delay estimation. The // memory needs to be initialized separately through // WebRtc_InitDelayEstimatorFarend(...). // // Inputs: // - spectrum_size : Size of the spectrum used both in far-end and // near-end. Used to allocate memory for spectrum // specific buffers. // - history_size : The far-end history buffer size. A change in buffer // size can be forced with WebRtc_set_history_size(). // Note that the maximum delay which can be estimated is // determined together with WebRtc_set_lookahead(). // // Return value: // - void* : Created |handle|. If the memory can't be allocated or // if any of the input parameters are invalid NULL is // returned. void* WebRtc_CreateDelayEstimatorFarend(int spectrum_size, int history_size); // Initializes the far-end part of the delay estimation instance returned by // WebRtc_CreateDelayEstimatorFarend(...) int WebRtc_InitDelayEstimatorFarend(void* handle); // Soft resets the far-end part of the delay estimation instance returned by // WebRtc_CreateDelayEstimatorFarend(...). // Input: // - delay_shift : The amount of blocks to shift history buffers. void WebRtc_SoftResetDelayEstimatorFarend(void* handle, int delay_shift); // Adds the far-end spectrum to the far-end history buffer. This spectrum is // used as reference when calculating the delay using // WebRtc_ProcessSpectrum(). // // Inputs: // - far_spectrum : Far-end spectrum. // - spectrum_size : The size of the data arrays (same for both far- and // near-end). // - far_q : The Q-domain of the far-end data. // // Output: // - handle : Updated far-end instance. // int WebRtc_AddFarSpectrumFix(void* handle, const uint16_t* far_spectrum, int spectrum_size, int far_q); // See WebRtc_AddFarSpectrumFix() for description. int WebRtc_AddFarSpectrumFloat(void* handle, const float* far_spectrum, int spectrum_size); // Releases the memory allocated by WebRtc_CreateDelayEstimator(...) void WebRtc_FreeDelayEstimator(void* handle); // Allocates the memory needed by the delay estimation. The memory needs to be // initialized separately through WebRtc_InitDelayEstimator(...). // // Inputs: // - farend_handle : Pointer to the far-end part of the delay estimation // instance created prior to this call using // WebRtc_CreateDelayEstimatorFarend(). // // Note that WebRtc_CreateDelayEstimator does not take // ownership of |farend_handle|, which has to be torn // down properly after this instance. // // - max_lookahead : Maximum amount of non-causal lookahead allowed. The // actual amount of lookahead used can be controlled by // WebRtc_set_lookahead(...). The default |lookahead| is // set to |max_lookahead| at create time. Use // WebRtc_set_lookahead(...) before start if a different // value is desired. // // Using lookahead can detect cases in which a near-end // signal occurs before the corresponding far-end signal. // It will delay the estimate for the current block by an // equal amount, and the returned values will be offset // by it. // // A value of zero is the typical no-lookahead case. // This also represents the minimum delay which can be // estimated. // // Note that the effective range of delay estimates is // [-|lookahead|,... ,|history_size|-|lookahead|) // where |history_size| is set through // WebRtc_set_history_size(). // // Return value: // - void* : Created |handle|. If the memory can't be allocated or // if any of the input parameters are invalid NULL is // returned. void* WebRtc_CreateDelayEstimator(void* farend_handle, int max_lookahead); // Initializes the delay estimation instance returned by // WebRtc_CreateDelayEstimator(...) int WebRtc_InitDelayEstimator(void* handle); // Soft resets the delay estimation instance returned by // WebRtc_CreateDelayEstimator(...) // Input: // - delay_shift : The amount of blocks to shift history buffers. // // Return value: // - actual_shifts : The actual number of shifts performed. int WebRtc_SoftResetDelayEstimator(void* handle, int delay_shift); // Sets the effective |history_size| used. Valid values from 2. We simply need // at least two delays to compare to perform an estimate. If |history_size| is // changed, buffers are reallocated filling in with zeros if necessary. // Note that changing the |history_size| affects both buffers in far-end and // near-end. Hence it is important to change all DelayEstimators that use the // same reference far-end, to the same |history_size| value. // Inputs: // - handle : Pointer to the delay estimation instance. // - history_size : Effective history size to be used. // Return value: // - new_history_size : The new history size used. If the memory was not able // to be allocated 0 is returned. int WebRtc_set_history_size(void* handle, int history_size); // Returns the history_size currently used. // Input: // - handle : Pointer to the delay estimation instance. int WebRtc_history_size(const void* handle); // Sets the amount of |lookahead| to use. Valid values are [0, max_lookahead] // where |max_lookahead| was set at create time through // WebRtc_CreateDelayEstimator(...). // // Input: // - handle : Pointer to the delay estimation instance. // - lookahead : The amount of lookahead to be used. // // Return value: // - new_lookahead : The actual amount of lookahead set, unless |handle| is // a NULL pointer or |lookahead| is invalid, for which an // error is returned. int WebRtc_set_lookahead(void* handle, int lookahead); // Returns the amount of lookahead we currently use. // Input: // - handle : Pointer to the delay estimation instance. int WebRtc_lookahead(void* handle); // Sets the |allowed_offset| used in the robust validation scheme. If the // delay estimator is used in an echo control component, this parameter is // related to the filter length. In principle |allowed_offset| should be set to // the echo control filter length minus the expected echo duration, i.e., the // delay offset the echo control can handle without quality regression. The // default value, used if not set manually, is zero. Note that |allowed_offset| // has to be non-negative. // Inputs: // - handle : Pointer to the delay estimation instance. // - allowed_offset : The amount of delay offset, measured in partitions, // the echo control filter can handle. int WebRtc_set_allowed_offset(void* handle, int allowed_offset); // Returns the |allowed_offset| in number of partitions. int WebRtc_get_allowed_offset(const void* handle); // Enables/Disables a robust validation functionality in the delay estimation. // This is by default set to disabled at create time. The state is preserved // over a reset. // Inputs: // - handle : Pointer to the delay estimation instance. // - enable : Enable (1) or disable (0) this feature. int WebRtc_enable_robust_validation(void* handle, int enable); // Returns 1 if robust validation is enabled and 0 if disabled. int WebRtc_is_robust_validation_enabled(const void* handle); // Estimates and returns the delay between the far-end and near-end blocks. The // value will be offset by the lookahead (i.e. the lookahead should be // subtracted from the returned value). // Inputs: // - handle : Pointer to the delay estimation instance. // - near_spectrum : Pointer to the near-end spectrum data of the current // block. // - spectrum_size : The size of the data arrays (same for both far- and // near-end). // - near_q : The Q-domain of the near-end data. // // Output: // - handle : Updated instance. // // Return value: // - delay : >= 0 - Calculated delay value. // -1 - Error. // -2 - Insufficient data for estimation. int WebRtc_DelayEstimatorProcessFix(void* handle, const uint16_t* near_spectrum, int spectrum_size, int near_q); // See WebRtc_DelayEstimatorProcessFix() for description. int WebRtc_DelayEstimatorProcessFloat(void* handle, const float* near_spectrum, int spectrum_size); // Returns the last calculated delay updated by the function // WebRtc_DelayEstimatorProcess(...). // // Input: // - handle : Pointer to the delay estimation instance. // // Return value: // - delay : >= 0 - Last calculated delay value. // -1 - Error. // -2 - Insufficient data for estimation. int WebRtc_last_delay(void* handle); // Returns the estimation quality/probability of the last calculated delay // updated by the function WebRtc_DelayEstimatorProcess(...). The estimation // quality is a value in the interval [0, 1]. The higher the value, the better // the quality. // // Return value: // - delay_quality : >= 0 - Estimation quality of last calculated delay. float WebRtc_last_delay_quality(void* handle); } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/utility/pffft_wrapper.cc0000664000175000017500000001052014475643423030036 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/utility/pffft_wrapper.h" #include "rtc_base/checks.h" #include "third_party/pffft/src/pffft.h" namespace webrtc { namespace { size_t GetBufferSize(size_t fft_size, Pffft::FftType fft_type) { return fft_size * (fft_type == Pffft::FftType::kReal ? 1 : 2); } float* AllocatePffftBuffer(size_t size) { return static_cast(pffft_aligned_malloc(size * sizeof(float))); } } // namespace Pffft::FloatBuffer::FloatBuffer(size_t fft_size, FftType fft_type) : size_(GetBufferSize(fft_size, fft_type)), data_(AllocatePffftBuffer(size_)) {} Pffft::FloatBuffer::~FloatBuffer() { pffft_aligned_free(data_); } rtc::ArrayView Pffft::FloatBuffer::GetConstView() const { return {data_, size_}; } rtc::ArrayView Pffft::FloatBuffer::GetView() { return {data_, size_}; } Pffft::Pffft(size_t fft_size, FftType fft_type) : fft_size_(fft_size), fft_type_(fft_type), pffft_status_(pffft_new_setup( fft_size_, fft_type == Pffft::FftType::kReal ? PFFFT_REAL : PFFFT_COMPLEX)), scratch_buffer_( AllocatePffftBuffer(GetBufferSize(fft_size_, fft_type_))) { RTC_DCHECK(pffft_status_); RTC_DCHECK(scratch_buffer_); } Pffft::~Pffft() { pffft_destroy_setup(pffft_status_); pffft_aligned_free(scratch_buffer_); } bool Pffft::IsValidFftSize(size_t fft_size, FftType fft_type) { if (fft_size == 0) { return false; } // PFFFT only supports transforms for inputs of length N of the form // N = (2^a)*(3^b)*(5^c) where b >=0 and c >= 0 and a >= 5 for the real FFT // and a >= 4 for the complex FFT. constexpr int kFactors[] = {2, 3, 5}; int factorization[] = {0, 0, 0}; int n = static_cast(fft_size); for (int i = 0; i < 3; ++i) { while (n % kFactors[i] == 0) { n = n / kFactors[i]; factorization[i]++; } } int a_min = (fft_type == Pffft::FftType::kReal) ? 5 : 4; return factorization[0] >= a_min && n == 1; } bool Pffft::IsSimdEnabled() { return pffft_simd_size() > 1; } std::unique_ptr Pffft::CreateBuffer() const { // Cannot use make_unique from absl because Pffft is the only friend of // Pffft::FloatBuffer. std::unique_ptr buffer( new Pffft::FloatBuffer(fft_size_, fft_type_)); return buffer; } void Pffft::ForwardTransform(const FloatBuffer& in, FloatBuffer* out, bool ordered) { RTC_DCHECK_EQ(in.size(), GetBufferSize(fft_size_, fft_type_)); RTC_DCHECK_EQ(in.size(), out->size()); RTC_DCHECK(scratch_buffer_); if (ordered) { pffft_transform_ordered(pffft_status_, in.const_data(), out->data(), scratch_buffer_, PFFFT_FORWARD); } else { pffft_transform(pffft_status_, in.const_data(), out->data(), scratch_buffer_, PFFFT_FORWARD); } } void Pffft::BackwardTransform(const FloatBuffer& in, FloatBuffer* out, bool ordered) { RTC_DCHECK_EQ(in.size(), GetBufferSize(fft_size_, fft_type_)); RTC_DCHECK_EQ(in.size(), out->size()); RTC_DCHECK(scratch_buffer_); if (ordered) { pffft_transform_ordered(pffft_status_, in.const_data(), out->data(), scratch_buffer_, PFFFT_BACKWARD); } else { pffft_transform(pffft_status_, in.const_data(), out->data(), scratch_buffer_, PFFFT_BACKWARD); } } void Pffft::FrequencyDomainConvolve(const FloatBuffer& fft_x, const FloatBuffer& fft_y, FloatBuffer* out, float scaling) { RTC_DCHECK_EQ(fft_x.size(), GetBufferSize(fft_size_, fft_type_)); RTC_DCHECK_EQ(fft_x.size(), fft_y.size()); RTC_DCHECK_EQ(fft_x.size(), out->size()); pffft_zconvolve_accumulate(pffft_status_, fft_x.const_data(), fft_y.const_data(), out->data(), scaling); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/utility/pffft_wrapper.h0000664000175000017500000000617714475643423027715 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_UTILITY_PFFFT_WRAPPER_H_ #define MODULES_AUDIO_PROCESSING_UTILITY_PFFFT_WRAPPER_H_ #include #include "api/array_view.h" // Forward declaration. struct PFFFT_Setup; namespace webrtc { // Pretty-Fast Fast Fourier Transform (PFFFT) wrapper class. // Not thread safe. class Pffft { public: enum class FftType { kReal, kComplex }; // 1D floating point buffer used as input/output data type for the FFT ops. // It must be constructed using Pffft::CreateBuffer(). class FloatBuffer { public: FloatBuffer(const FloatBuffer&) = delete; FloatBuffer& operator=(const FloatBuffer&) = delete; ~FloatBuffer(); rtc::ArrayView GetConstView() const; rtc::ArrayView GetView(); private: friend class Pffft; FloatBuffer(size_t fft_size, FftType fft_type); const float* const_data() const { return data_; } float* data() { return data_; } size_t size() const { return size_; } const size_t size_; float* const data_; }; // TODO(https://crbug.com/webrtc/9577): Consider adding a factory and making // the ctor private. // static std::unique_ptr Create(size_t fft_size, // FftType fft_type); Ctor. |fft_size| must be a supported size (see // Pffft::IsValidFftSize()). If not supported, the code will crash. Pffft(size_t fft_size, FftType fft_type); Pffft(const Pffft&) = delete; Pffft& operator=(const Pffft&) = delete; ~Pffft(); // Returns true if the FFT size is supported. static bool IsValidFftSize(size_t fft_size, FftType fft_type); // Returns true if SIMD code optimizations are being used. static bool IsSimdEnabled(); // Creates a buffer of the right size. std::unique_ptr CreateBuffer() const; // TODO(https://crbug.com/webrtc/9577): Overload with rtc::ArrayView args. // Computes the forward fast Fourier transform. void ForwardTransform(const FloatBuffer& in, FloatBuffer* out, bool ordered); // Computes the backward fast Fourier transform. void BackwardTransform(const FloatBuffer& in, FloatBuffer* out, bool ordered); // Multiplies the frequency components of |fft_x| and |fft_y| and accumulates // them into |out|. The arrays must have been obtained with // ForwardTransform(..., /*ordered=*/false) - i.e., |fft_x| and |fft_y| must // not be ordered. void FrequencyDomainConvolve(const FloatBuffer& fft_x, const FloatBuffer& fft_y, FloatBuffer* out, float scaling = 1.f); private: const size_t fft_size_; const FftType fft_type_; PFFFT_Setup* pffft_status_; float* const scratch_buffer_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_UTILITY_PFFFT_WRAPPER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/0000775000175000017500000000000014475643423023733 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/BUILD.gn0000664000175000017500000000353314475643423025124 0ustar00arunarun# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../../../webrtc.gni") rtc_library("vad") { visibility = [ "../*", "../../../rtc_tools:*", ] sources = [ "common.h", "gmm.cc", "gmm.h", "noise_gmm_tables.h", "pitch_based_vad.cc", "pitch_based_vad.h", "pitch_internal.cc", "pitch_internal.h", "pole_zero_filter.cc", "pole_zero_filter.h", "standalone_vad.cc", "standalone_vad.h", "vad_audio_proc.cc", "vad_audio_proc.h", "vad_audio_proc_internal.h", "vad_circular_buffer.cc", "vad_circular_buffer.h", "voice_activity_detector.cc", "voice_activity_detector.h", "voice_gmm_tables.h", ] deps = [ "../../../audio/utility:audio_frame_operations", "../../../common_audio", "../../../common_audio:common_audio_c", "../../../common_audio/third_party/ooura:fft_size_256", "../../../rtc_base:checks", "../../audio_coding:isac_vad", ] } if (rtc_include_tests) { rtc_library("vad_unittests") { testonly = true sources = [ "gmm_unittest.cc", "pitch_based_vad_unittest.cc", "pitch_internal_unittest.cc", "pole_zero_filter_unittest.cc", "standalone_vad_unittest.cc", "vad_audio_proc_unittest.cc", "vad_circular_buffer_unittest.cc", "voice_activity_detector_unittest.cc", ] deps = [ ":vad", "../../../common_audio", "../../../test:fileutils", "../../../test:test_support", "//testing/gmock", "//testing/gtest", ] } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/common.h0000664000175000017500000000163514475643423025401 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_VAD_COMMON_H_ #define MODULES_AUDIO_PROCESSING_VAD_COMMON_H_ #include static const int kSampleRateHz = 16000; static const size_t kLength10Ms = kSampleRateHz / 100; static const size_t kMaxNumFrames = 4; struct AudioFeatures { double log_pitch_gain[kMaxNumFrames]; double pitch_lag_hz[kMaxNumFrames]; double spectral_peak[kMaxNumFrames]; double rms[kMaxNumFrames]; size_t num_frames; bool silence; }; #endif // MODULES_AUDIO_PROCESSING_VAD_COMMON_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/gmm.cc0000664000175000017500000000352514475643423025027 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/vad/gmm.h" #include namespace webrtc { static const int kMaxDimension = 10; static void RemoveMean(const double* in, const double* mean_vec, int dimension, double* out) { for (int n = 0; n < dimension; ++n) out[n] = in[n] - mean_vec[n]; } static double ComputeExponent(const double* in, const double* covar_inv, int dimension) { double q = 0; for (int i = 0; i < dimension; ++i) { double v = 0; for (int j = 0; j < dimension; j++) v += (*covar_inv++) * in[j]; q += v * in[i]; } q *= -0.5; return q; } double EvaluateGmm(const double* x, const GmmParameters& gmm_parameters) { if (gmm_parameters.dimension > kMaxDimension) { return -1; // This is invalid pdf so the caller can check this. } double f = 0; double v[kMaxDimension]; const double* mean_vec = gmm_parameters.mean; const double* covar_inv = gmm_parameters.covar_inverse; for (int n = 0; n < gmm_parameters.num_mixtures; n++) { RemoveMean(x, mean_vec, gmm_parameters.dimension, v); double q = ComputeExponent(v, covar_inv, gmm_parameters.dimension) + gmm_parameters.weight[n]; f += exp(q); mean_vec += gmm_parameters.dimension; covar_inv += gmm_parameters.dimension * gmm_parameters.dimension; } return f; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/gmm.h0000664000175000017500000000334214475643423024666 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_VAD_GMM_H_ #define MODULES_AUDIO_PROCESSING_VAD_GMM_H_ namespace webrtc { // A structure that specifies a GMM. // A GMM is formulated as // f(x) = w[0] * mixture[0] + w[1] * mixture[1] + ... + // w[num_mixtures - 1] * mixture[num_mixtures - 1]; // Where a 'mixture' is a Gaussian density. struct GmmParameters { // weight[n] = log(w[n]) - |dimension|/2 * log(2*pi) - 1/2 * log(det(cov[n])); // where cov[n] is the covariance matrix of mixture n; const double* weight; // pointer to the first element of a |num_mixtures|x|dimension| matrix // where kth row is the mean of the kth mixture. const double* mean; // pointer to the first element of a |num_mixtures|x|dimension|x|dimension| // 3D-matrix, where the kth 2D-matrix is the inverse of the covariance // matrix of the kth mixture. const double* covar_inverse; // Dimensionality of the mixtures. int dimension; // number of the mixtures. int num_mixtures; }; // Evaluate the given GMM, according to |gmm_parameters|, at the given point // |x|. If the dimensionality of the given GMM is larger that the maximum // acceptable dimension by the following function -1 is returned. double EvaluateGmm(const double* x, const GmmParameters& gmm_parameters); } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_VAD_GMM_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/noise_gmm_tables.h0000664000175000017500000001163414475643423027420 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // GMM tables for inactive segments. Generated by MakeGmmTables.m. #ifndef MODULES_AUDIO_PROCESSING_VAD_NOISE_GMM_TABLES_H_ #define MODULES_AUDIO_PROCESSING_VAD_NOISE_GMM_TABLES_H_ namespace webrtc { static const int kNoiseGmmNumMixtures = 12; static const int kNoiseGmmDim = 3; static const double kNoiseGmmCovarInverse[kNoiseGmmNumMixtures][kNoiseGmmDim][kNoiseGmmDim] = { {{7.36219567592941e+00, 4.83060785179861e-03, 1.23335151497610e-02}, {4.83060785179861e-03, 1.65289507047817e-04, -2.41490588169997e-04}, {1.23335151497610e-02, -2.41490588169997e-04, 6.59472060689382e-03}}, {{8.70265239309140e+00, -5.30636201431086e-04, 5.44014966585347e-03}, {-5.30636201431086e-04, 3.11095453521008e-04, -1.86287206836035e-04}, {5.44014966585347e-03, -1.86287206836035e-04, 6.29493388790744e-04}}, {{4.53467851955055e+00, -3.92977536695197e-03, -2.46521420693317e-03}, {-3.92977536695197e-03, 4.94650752632750e-05, -1.08587438501826e-05}, {-2.46521420693317e-03, -1.08587438501826e-05, 9.28793975422261e-05}}, {{9.26817997114275e-01, -4.03976069276753e-04, -3.56441427392165e-03}, {-4.03976069276753e-04, 2.51976251631430e-06, 1.46914206734572e-07}, {-3.56441427392165e-03, 1.46914206734572e-07, 8.19914567685373e-05}}, {{7.61715986787441e+00, -1.54889041216888e-04, 2.41756280071656e-02}, {-1.54889041216888e-04, 3.50282550461672e-07, -6.27251196972490e-06}, {2.41756280071656e-02, -6.27251196972490e-06, 1.45061847649872e-02}}, {{8.31193642663158e+00, -3.84070508164323e-04, -3.09750630821876e-02}, {-3.84070508164323e-04, 3.80433432277336e-07, -1.14321142836636e-06}, {-3.09750630821876e-02, -1.14321142836636e-06, 8.35091486289997e-04}}, {{9.67283151270894e-01, 5.82465812445039e-05, -3.18350798617053e-03}, {5.82465812445039e-05, 2.23762672000318e-07, -7.74196587408623e-07}, {-3.18350798617053e-03, -7.74196587408623e-07, 3.85120938338325e-04}}, {{8.28066236985388e+00, 5.87634508319763e-05, 6.99303090891743e-03}, {5.87634508319763e-05, 2.93746018618058e-07, 3.40843332882272e-07}, {6.99303090891743e-03, 3.40843332882272e-07, 1.99379171190344e-04}}, {{6.07488998675646e+00, -1.11494526618473e-02, 5.10013111123381e-03}, {-1.11494526618473e-02, 6.99238879921751e-04, 5.36718550370870e-05}, {5.10013111123381e-03, 5.36718550370870e-05, 5.26909853276753e-04}}, {{6.90492021419175e+00, 4.20639355257863e-04, -2.38612752336481e-03}, {4.20639355257863e-04, 3.31246767338153e-06, -2.42052288150859e-08}, {-2.38612752336481e-03, -2.42052288150859e-08, 4.46608368363412e-04}}, {{1.31069150869715e+01, -1.73718583865670e-04, -1.97591814508578e-02}, {-1.73718583865670e-04, 2.80451716300124e-07, 9.96570755379865e-07}, {-1.97591814508578e-02, 9.96570755379865e-07, 2.41361900868847e-03}}, {{4.69566344239814e+00, -2.61077567563690e-04, 5.26359000761433e-03}, {-2.61077567563690e-04, 1.82420859823767e-06, -7.83645887541601e-07}, {5.26359000761433e-03, -7.83645887541601e-07, 1.33586288288802e-02}}}; static const double kNoiseGmmMean[kNoiseGmmNumMixtures][kNoiseGmmDim] = { {-2.01386094766163e+00, 1.69702162045397e+02, 7.41715804872181e+01}, {-1.94684591777290e+00, 1.42398396732668e+02, 1.64186321157831e+02}, {-2.29319297562437e+00, 3.86415425589868e+02, 2.13452215267125e+02}, {-3.25487177070268e+00, 1.08668712553616e+03, 2.33119949467419e+02}, {-2.13159632447467e+00, 4.83821702557717e+03, 6.86786166673740e+01}, {-2.26171410780526e+00, 4.79420193982422e+03, 1.53222513286450e+02}, {-3.32166740703185e+00, 4.35161135834358e+03, 1.33206448431316e+02}, {-2.19290322814343e+00, 3.98325506609408e+03, 2.13249167359934e+02}, {-2.02898459255404e+00, 7.37039893155007e+03, 1.12518527491926e+02}, {-2.26150236399500e+00, 1.54896745196145e+03, 1.49717357868579e+02}, {-2.00417668301790e+00, 3.82434760310304e+03, 1.07438913004312e+02}, {-2.30193040814533e+00, 1.43953696546439e+03, 7.04085275122649e+01}}; static const double kNoiseGmmWeights[kNoiseGmmNumMixtures] = { -1.09422832086193e+01, -1.10847897513425e+01, -1.36767587732187e+01, -1.79789356118641e+01, -1.42830169160894e+01, -1.56500228061379e+01, -1.83124990950113e+01, -1.69979436177477e+01, -1.12329424387828e+01, -1.41311785780639e+01, -1.47171861448585e+01, -1.35963362781839e+01}; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_VAD_NOISE_GMM_TABLES_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/pitch_based_vad.cc0000664000175000017500000001026514475643423027345 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/vad/pitch_based_vad.h" #include #include "modules/audio_processing/vad/common.h" #include "modules/audio_processing/vad/noise_gmm_tables.h" #include "modules/audio_processing/vad/vad_circular_buffer.h" #include "modules/audio_processing/vad/voice_gmm_tables.h" namespace webrtc { static_assert(kNoiseGmmDim == kVoiceGmmDim, "noise and voice gmm dimension not equal"); // These values should match MATLAB counterparts for unit-tests to pass. static const int kPosteriorHistorySize = 500; // 5 sec of 10 ms frames. static const double kInitialPriorProbability = 0.3; static const int kTransientWidthThreshold = 7; static const double kLowProbabilityThreshold = 0.2; static double LimitProbability(double p) { const double kLimHigh = 0.99; const double kLimLow = 0.01; if (p > kLimHigh) p = kLimHigh; else if (p < kLimLow) p = kLimLow; return p; } PitchBasedVad::PitchBasedVad() : p_prior_(kInitialPriorProbability), circular_buffer_(VadCircularBuffer::Create(kPosteriorHistorySize)) { // Setup noise GMM. noise_gmm_.dimension = kNoiseGmmDim; noise_gmm_.num_mixtures = kNoiseGmmNumMixtures; noise_gmm_.weight = kNoiseGmmWeights; noise_gmm_.mean = &kNoiseGmmMean[0][0]; noise_gmm_.covar_inverse = &kNoiseGmmCovarInverse[0][0][0]; // Setup voice GMM. voice_gmm_.dimension = kVoiceGmmDim; voice_gmm_.num_mixtures = kVoiceGmmNumMixtures; voice_gmm_.weight = kVoiceGmmWeights; voice_gmm_.mean = &kVoiceGmmMean[0][0]; voice_gmm_.covar_inverse = &kVoiceGmmCovarInverse[0][0][0]; } PitchBasedVad::~PitchBasedVad() {} int PitchBasedVad::VoicingProbability(const AudioFeatures& features, double* p_combined) { double p; double gmm_features[3]; double pdf_features_given_voice; double pdf_features_given_noise; // These limits are the same in matlab implementation 'VoicingProbGMM().' const double kLimLowLogPitchGain = -2.0; const double kLimHighLogPitchGain = -0.9; const double kLimLowSpectralPeak = 200; const double kLimHighSpectralPeak = 2000; const double kEps = 1e-12; for (size_t n = 0; n < features.num_frames; n++) { gmm_features[0] = features.log_pitch_gain[n]; gmm_features[1] = features.spectral_peak[n]; gmm_features[2] = features.pitch_lag_hz[n]; pdf_features_given_voice = EvaluateGmm(gmm_features, voice_gmm_); pdf_features_given_noise = EvaluateGmm(gmm_features, noise_gmm_); if (features.spectral_peak[n] < kLimLowSpectralPeak || features.spectral_peak[n] > kLimHighSpectralPeak || features.log_pitch_gain[n] < kLimLowLogPitchGain) { pdf_features_given_voice = kEps * pdf_features_given_noise; } else if (features.log_pitch_gain[n] > kLimHighLogPitchGain) { pdf_features_given_noise = kEps * pdf_features_given_voice; } p = p_prior_ * pdf_features_given_voice / (pdf_features_given_voice * p_prior_ + pdf_features_given_noise * (1 - p_prior_)); p = LimitProbability(p); // Combine pitch-based probability with standalone probability, before // updating prior probabilities. double prod_active = p * p_combined[n]; double prod_inactive = (1 - p) * (1 - p_combined[n]); p_combined[n] = prod_active / (prod_active + prod_inactive); if (UpdatePrior(p_combined[n]) < 0) return -1; // Limit prior probability. With a zero prior probability the posterior // probability is always zero. p_prior_ = LimitProbability(p_prior_); } return 0; } int PitchBasedVad::UpdatePrior(double p) { circular_buffer_->Insert(p); if (circular_buffer_->RemoveTransient(kTransientWidthThreshold, kLowProbabilityThreshold) < 0) return -1; p_prior_ = circular_buffer_->Mean(); return 0; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/pitch_based_vad.h0000664000175000017500000000351514475643423027207 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_VAD_PITCH_BASED_VAD_H_ #define MODULES_AUDIO_PROCESSING_VAD_PITCH_BASED_VAD_H_ #include #include "modules/audio_processing/vad/common.h" #include "modules/audio_processing/vad/gmm.h" namespace webrtc { class VadCircularBuffer; // Computes the probability of the input audio frame to be active given // the corresponding pitch-gain and lag of the frame. class PitchBasedVad { public: PitchBasedVad(); ~PitchBasedVad(); // Compute pitch-based voicing probability, given the features. // features: a structure containing features required for computing voicing // probabilities. // // p_combined: an array which contains the combined activity probabilities // computed prior to the call of this function. The method, // then, computes the voicing probabilities and combine them // with the given values. The result are returned in |p|. int VoicingProbability(const AudioFeatures& features, double* p_combined); private: int UpdatePrior(double p); // TODO(turajs): maybe defining this at a higher level (maybe enum) so that // all the code recognize it as "no-error." static const int kNoError = 0; GmmParameters noise_gmm_; GmmParameters voice_gmm_; double p_prior_; std::unique_ptr circular_buffer_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_VAD_PITCH_BASED_VAD_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/pitch_internal.cc0000664000175000017500000000416214475643423027250 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/vad/pitch_internal.h" #include namespace webrtc { // A 4-to-3 linear interpolation. // The interpolation constants are derived as following: // Input pitch parameters are updated every 7.5 ms. Within a 30-ms interval // we are interested in pitch parameters of 0-5 ms, 10-15ms and 20-25ms. This is // like interpolating 4-to-6 and keep the odd samples. // The reason behind this is that LPC coefficients are computed for the first // half of each 10ms interval. static void PitchInterpolation(double old_val, const double* in, double* out) { out[0] = 1. / 6. * old_val + 5. / 6. * in[0]; out[1] = 5. / 6. * in[1] + 1. / 6. * in[2]; out[2] = 0.5 * in[2] + 0.5 * in[3]; } void GetSubframesPitchParameters(int sampling_rate_hz, double* gains, double* lags, int num_in_frames, int num_out_frames, double* log_old_gain, double* old_lag, double* log_pitch_gain, double* pitch_lag_hz) { // Gain interpolation is in log-domain, also returned in log-domain. for (int n = 0; n < num_in_frames; n++) gains[n] = log(gains[n] + 1e-12); // Interpolate lags and gains. PitchInterpolation(*log_old_gain, gains, log_pitch_gain); *log_old_gain = gains[num_in_frames - 1]; PitchInterpolation(*old_lag, lags, pitch_lag_hz); *old_lag = lags[num_in_frames - 1]; // Convert pitch-lags to Hertz. for (int n = 0; n < num_out_frames; n++) { pitch_lag_hz[n] = (sampling_rate_hz) / (pitch_lag_hz[n]); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/pitch_internal.h0000664000175000017500000000232114475643423027105 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_VAD_PITCH_INTERNAL_H_ #define MODULES_AUDIO_PROCESSING_VAD_PITCH_INTERNAL_H_ namespace webrtc { // TODO(turajs): Write a description of this function. Also be consistent with // usage of |sampling_rate_hz| vs |kSamplingFreqHz|. void GetSubframesPitchParameters(int sampling_rate_hz, double* gains, double* lags, int num_in_frames, int num_out_frames, double* log_old_gain, double* old_lag, double* log_pitch_gain, double* pitch_lag_hz); } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_VAD_PITCH_INTERNAL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/pole_zero_filter.cc0000664000175000017500000001037114475643423027607 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/vad/pole_zero_filter.h" #include #include namespace webrtc { PoleZeroFilter* PoleZeroFilter::Create(const float* numerator_coefficients, size_t order_numerator, const float* denominator_coefficients, size_t order_denominator) { if (order_numerator > kMaxFilterOrder || order_denominator > kMaxFilterOrder || denominator_coefficients[0] == 0 || numerator_coefficients == NULL || denominator_coefficients == NULL) return NULL; return new PoleZeroFilter(numerator_coefficients, order_numerator, denominator_coefficients, order_denominator); } PoleZeroFilter::PoleZeroFilter(const float* numerator_coefficients, size_t order_numerator, const float* denominator_coefficients, size_t order_denominator) : past_input_(), past_output_(), numerator_coefficients_(), denominator_coefficients_(), order_numerator_(order_numerator), order_denominator_(order_denominator), highest_order_(std::max(order_denominator, order_numerator)) { memcpy(numerator_coefficients_, numerator_coefficients, sizeof(numerator_coefficients_[0]) * (order_numerator_ + 1)); memcpy(denominator_coefficients_, denominator_coefficients, sizeof(denominator_coefficients_[0]) * (order_denominator_ + 1)); if (denominator_coefficients_[0] != 1) { for (size_t n = 0; n <= order_numerator_; n++) numerator_coefficients_[n] /= denominator_coefficients_[0]; for (size_t n = 0; n <= order_denominator_; n++) denominator_coefficients_[n] /= denominator_coefficients_[0]; } } template static float FilterArPast(const T* past, size_t order, const float* coefficients) { float sum = 0.0f; size_t past_index = order - 1; for (size_t k = 1; k <= order; k++, past_index--) sum += coefficients[k] * past[past_index]; return sum; } int PoleZeroFilter::Filter(const int16_t* in, size_t num_input_samples, float* output) { if (in == NULL || output == NULL) return -1; // This is the typical case, just a memcpy. const size_t k = std::min(num_input_samples, highest_order_); size_t n; for (n = 0; n < k; n++) { output[n] = in[n] * numerator_coefficients_[0]; output[n] += FilterArPast(&past_input_[n], order_numerator_, numerator_coefficients_); output[n] -= FilterArPast(&past_output_[n], order_denominator_, denominator_coefficients_); past_input_[n + order_numerator_] = in[n]; past_output_[n + order_denominator_] = output[n]; } if (highest_order_ < num_input_samples) { for (size_t m = 0; n < num_input_samples; n++, m++) { output[n] = in[n] * numerator_coefficients_[0]; output[n] += FilterArPast(&in[m], order_numerator_, numerator_coefficients_); output[n] -= FilterArPast(&output[m], order_denominator_, denominator_coefficients_); } // Record into the past signal. memcpy(past_input_, &in[num_input_samples - order_numerator_], sizeof(in[0]) * order_numerator_); memcpy(past_output_, &output[num_input_samples - order_denominator_], sizeof(output[0]) * order_denominator_); } else { // Odd case that the length of the input is shorter that filter order. memmove(past_input_, &past_input_[num_input_samples], order_numerator_ * sizeof(past_input_[0])); memmove(past_output_, &past_output_[num_input_samples], order_denominator_ * sizeof(past_output_[0])); } return 0; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/pole_zero_filter.h0000664000175000017500000000307114475643423027450 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_VAD_POLE_ZERO_FILTER_H_ #define MODULES_AUDIO_PROCESSING_VAD_POLE_ZERO_FILTER_H_ #include #include namespace webrtc { class PoleZeroFilter { public: ~PoleZeroFilter() {} static PoleZeroFilter* Create(const float* numerator_coefficients, size_t order_numerator, const float* denominator_coefficients, size_t order_denominator); int Filter(const int16_t* in, size_t num_input_samples, float* output); private: PoleZeroFilter(const float* numerator_coefficients, size_t order_numerator, const float* denominator_coefficients, size_t order_denominator); static const int kMaxFilterOrder = 24; int16_t past_input_[kMaxFilterOrder * 2]; float past_output_[kMaxFilterOrder * 2]; float numerator_coefficients_[kMaxFilterOrder + 1]; float denominator_coefficients_[kMaxFilterOrder + 1]; size_t order_numerator_; size_t order_denominator_; size_t highest_order_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_VAD_POLE_ZERO_FILTER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/standalone_vad.cc0000664000175000017500000000461714475643423027234 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/vad/standalone_vad.h" #include #include "common_audio/vad/include/webrtc_vad.h" #include "rtc_base/checks.h" namespace webrtc { static const int kDefaultStandaloneVadMode = 3; StandaloneVad::StandaloneVad(VadInst* vad) : vad_(vad), buffer_(), index_(0), mode_(kDefaultStandaloneVadMode) {} StandaloneVad::~StandaloneVad() { WebRtcVad_Free(vad_); } StandaloneVad* StandaloneVad::Create() { VadInst* vad = WebRtcVad_Create(); if (!vad) return nullptr; int err = WebRtcVad_Init(vad); err |= WebRtcVad_set_mode(vad, kDefaultStandaloneVadMode); if (err != 0) { WebRtcVad_Free(vad); return nullptr; } return new StandaloneVad(vad); } int StandaloneVad::AddAudio(const int16_t* data, size_t length) { if (length != kLength10Ms) return -1; if (index_ + length > kLength10Ms * kMaxNum10msFrames) // Reset the buffer if it's full. // TODO(ajm): Instead, consider just processing every 10 ms frame. Then we // can forgo the buffering. index_ = 0; memcpy(&buffer_[index_], data, sizeof(int16_t) * length); index_ += length; return 0; } int StandaloneVad::GetActivity(double* p, size_t length_p) { if (index_ == 0) return -1; const size_t num_frames = index_ / kLength10Ms; if (num_frames > length_p) return -1; RTC_DCHECK_EQ(0, WebRtcVad_ValidRateAndFrameLength(kSampleRateHz, index_)); int activity = WebRtcVad_Process(vad_, kSampleRateHz, buffer_, index_); if (activity < 0) return -1; else if (activity == 0) p[0] = 0.01; // Arbitrary but small and non-zero. else p[0] = 0.5; // 0.5 is neutral values when combinned by other probabilities. for (size_t n = 1; n < num_frames; n++) p[n] = p[0]; // Reset the buffer to start from the beginning. index_ = 0; return activity; } int StandaloneVad::set_mode(int mode) { if (mode < 0 || mode > 3) return -1; if (WebRtcVad_set_mode(vad_, mode) != 0) return -1; mode_ = mode; return 0; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/standalone_vad.h0000664000175000017500000000442114475643423027067 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_AGC_STANDALONE_VAD_H_ #define MODULES_AUDIO_PROCESSING_AGC_STANDALONE_VAD_H_ #include #include #include "common_audio/vad/include/webrtc_vad.h" #include "modules/audio_processing/vad/common.h" namespace webrtc { class StandaloneVad { public: static StandaloneVad* Create(); ~StandaloneVad(); // Outputs // p: a buffer where probabilities are written to. // length_p: number of elements of |p|. // // return value: // -1: if no audio is stored or VAD returns error. // 0: in success. // In case of error the content of |activity| is unchanged. // // Note that due to a high false-positive (VAD decision is active while the // processed audio is just background noise) rate, stand-alone VAD is used as // a one-sided indicator. The activity probability is 0.5 if the frame is // classified as active, and the probability is 0.01 if the audio is // classified as passive. In this way, when probabilities are combined, the // effect of the stand-alone VAD is neutral if the input is classified as // active. int GetActivity(double* p, size_t length_p); // Expecting 10 ms of 16 kHz audio to be pushed in. int AddAudio(const int16_t* data, size_t length); // Set aggressiveness of VAD, 0 is the least aggressive and 3 is the most // aggressive mode. Returns -1 if the input is less than 0 or larger than 3, // otherwise 0 is returned. int set_mode(int mode); // Get the agressiveness of the current VAD. int mode() const { return mode_; } private: explicit StandaloneVad(VadInst* vad); static const size_t kMaxNum10msFrames = 3; // TODO(turajs): Is there a way to use scoped-pointer here? VadInst* vad_; int16_t buffer_[kMaxNum10msFrames * kLength10Ms]; size_t index_; int mode_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_AGC_STANDALONE_VAD_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/vad_audio_proc.cc0000664000175000017500000002512214475643423027222 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/vad/vad_audio_proc.h" #include #include #include #include "common_audio/third_party/ooura/fft_size_256/fft4g.h" #include "modules/audio_processing/vad/pitch_internal.h" #include "modules/audio_processing/vad/pole_zero_filter.h" #include "modules/audio_processing/vad/vad_audio_proc_internal.h" #include "rtc_base/checks.h" extern "C" { #include "modules/audio_coding/codecs/isac/main/source/filter_functions.h" #include "modules/audio_coding/codecs/isac/main/source/isac_vad.h" #include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h" #include "modules/audio_coding/codecs/isac/main/source/structs.h" } namespace webrtc { // The following structures are declared anonymous in iSAC's structs.h. To // forward declare them, we use this derived class trick. struct VadAudioProc::PitchAnalysisStruct : public ::PitchAnalysisStruct {}; struct VadAudioProc::PreFiltBankstr : public ::PreFiltBankstr {}; static constexpr float kFrequencyResolution = kSampleRateHz / static_cast(VadAudioProc::kDftSize); static constexpr int kSilenceRms = 5; // TODO(turajs): Make a Create or Init for VadAudioProc. VadAudioProc::VadAudioProc() : audio_buffer_(), num_buffer_samples_(kNumPastSignalSamples), log_old_gain_(-2), old_lag_(50), // Arbitrary but valid as pitch-lag (in samples). pitch_analysis_handle_(new PitchAnalysisStruct), pre_filter_handle_(new PreFiltBankstr), high_pass_filter_(PoleZeroFilter::Create(kCoeffNumerator, kFilterOrder, kCoeffDenominator, kFilterOrder)) { static_assert(kNumPastSignalSamples + kNumSubframeSamples == sizeof(kLpcAnalWin) / sizeof(kLpcAnalWin[0]), "lpc analysis window incorrect size"); static_assert(kLpcOrder + 1 == sizeof(kCorrWeight) / sizeof(kCorrWeight[0]), "correlation weight incorrect size"); // TODO(turajs): Are we doing too much in the constructor? float data[kDftSize]; // Make FFT to initialize. ip_[0] = 0; WebRtc_rdft(kDftSize, 1, data, ip_, w_fft_); // TODO(turajs): Need to initialize high-pass filter. // Initialize iSAC components. WebRtcIsac_InitPreFilterbank(pre_filter_handle_.get()); WebRtcIsac_InitPitchAnalysis(pitch_analysis_handle_.get()); } VadAudioProc::~VadAudioProc() {} void VadAudioProc::ResetBuffer() { memcpy(audio_buffer_, &audio_buffer_[kNumSamplesToProcess], sizeof(audio_buffer_[0]) * kNumPastSignalSamples); num_buffer_samples_ = kNumPastSignalSamples; } int VadAudioProc::ExtractFeatures(const int16_t* frame, size_t length, AudioFeatures* features) { features->num_frames = 0; if (length != kNumSubframeSamples) { return -1; } // High-pass filter to remove the DC component and very low frequency content. // We have experienced that this high-pass filtering improves voice/non-voiced // classification. if (high_pass_filter_->Filter(frame, kNumSubframeSamples, &audio_buffer_[num_buffer_samples_]) != 0) { return -1; } num_buffer_samples_ += kNumSubframeSamples; if (num_buffer_samples_ < kBufferLength) { return 0; } RTC_DCHECK_EQ(num_buffer_samples_, kBufferLength); features->num_frames = kNum10msSubframes; features->silence = false; Rms(features->rms, kMaxNumFrames); for (size_t i = 0; i < kNum10msSubframes; ++i) { if (features->rms[i] < kSilenceRms) { // PitchAnalysis can cause NaNs in the pitch gain if it's fed silence. // Bail out here instead. features->silence = true; ResetBuffer(); return 0; } } PitchAnalysis(features->log_pitch_gain, features->pitch_lag_hz, kMaxNumFrames); FindFirstSpectralPeaks(features->spectral_peak, kMaxNumFrames); ResetBuffer(); return 0; } // Computes |kLpcOrder + 1| correlation coefficients. void VadAudioProc::SubframeCorrelation(double* corr, size_t length_corr, size_t subframe_index) { RTC_DCHECK_GE(length_corr, kLpcOrder + 1); double windowed_audio[kNumSubframeSamples + kNumPastSignalSamples]; size_t buffer_index = subframe_index * kNumSubframeSamples; for (size_t n = 0; n < kNumSubframeSamples + kNumPastSignalSamples; n++) windowed_audio[n] = audio_buffer_[buffer_index++] * kLpcAnalWin[n]; WebRtcIsac_AutoCorr(corr, windowed_audio, kNumSubframeSamples + kNumPastSignalSamples, kLpcOrder); } // Compute |kNum10msSubframes| sets of LPC coefficients, one per 10 ms input. // The analysis window is 15 ms long and it is centered on the first half of // each 10ms sub-frame. This is equivalent to computing LPC coefficients for the // first half of each 10 ms subframe. void VadAudioProc::GetLpcPolynomials(double* lpc, size_t length_lpc) { RTC_DCHECK_GE(length_lpc, kNum10msSubframes * (kLpcOrder + 1)); double corr[kLpcOrder + 1]; double reflec_coeff[kLpcOrder]; for (size_t i = 0, offset_lpc = 0; i < kNum10msSubframes; i++, offset_lpc += kLpcOrder + 1) { SubframeCorrelation(corr, kLpcOrder + 1, i); corr[0] *= 1.0001; // This makes Lev-Durb a bit more stable. for (size_t k = 0; k < kLpcOrder + 1; k++) { corr[k] *= kCorrWeight[k]; } WebRtcIsac_LevDurb(&lpc[offset_lpc], reflec_coeff, corr, kLpcOrder); } } // Fit a second order curve to these 3 points and find the location of the // extremum. The points are inverted before curve fitting. static float QuadraticInterpolation(float prev_val, float curr_val, float next_val) { // Doing the interpolation in |1 / A(z)|^2. float fractional_index = 0; next_val = 1.0f / next_val; prev_val = 1.0f / prev_val; curr_val = 1.0f / curr_val; fractional_index = -(next_val - prev_val) * 0.5f / (next_val + prev_val - 2.f * curr_val); RTC_DCHECK_LT(fabs(fractional_index), 1); return fractional_index; } // 1 / A(z), where A(z) is defined by |lpc| is a model of the spectral envelope // of the input signal. The local maximum of the spectral envelope corresponds // with the local minimum of A(z). It saves complexity, as we save one // inversion. Furthermore, we find the first local maximum of magnitude squared, // to save on one square root. void VadAudioProc::FindFirstSpectralPeaks(double* f_peak, size_t length_f_peak) { RTC_DCHECK_GE(length_f_peak, kNum10msSubframes); double lpc[kNum10msSubframes * (kLpcOrder + 1)]; // For all sub-frames. GetLpcPolynomials(lpc, kNum10msSubframes * (kLpcOrder + 1)); const size_t kNumDftCoefficients = kDftSize / 2 + 1; float data[kDftSize]; for (size_t i = 0; i < kNum10msSubframes; i++) { // Convert to float with zero pad. memset(data, 0, sizeof(data)); for (size_t n = 0; n < kLpcOrder + 1; n++) { data[n] = static_cast(lpc[i * (kLpcOrder + 1) + n]); } // Transform to frequency domain. WebRtc_rdft(kDftSize, 1, data, ip_, w_fft_); size_t index_peak = 0; float prev_magn_sqr = data[0] * data[0]; float curr_magn_sqr = data[2] * data[2] + data[3] * data[3]; float next_magn_sqr; bool found_peak = false; for (size_t n = 2; n < kNumDftCoefficients - 1; n++) { next_magn_sqr = data[2 * n] * data[2 * n] + data[2 * n + 1] * data[2 * n + 1]; if (curr_magn_sqr < prev_magn_sqr && curr_magn_sqr < next_magn_sqr) { found_peak = true; index_peak = n - 1; break; } prev_magn_sqr = curr_magn_sqr; curr_magn_sqr = next_magn_sqr; } float fractional_index = 0; if (!found_peak) { // Checking if |kNumDftCoefficients - 1| is the local minimum. next_magn_sqr = data[1] * data[1]; if (curr_magn_sqr < prev_magn_sqr && curr_magn_sqr < next_magn_sqr) { index_peak = kNumDftCoefficients - 1; } } else { // A peak is found, do a simple quadratic interpolation to get a more // accurate estimate of the peak location. fractional_index = QuadraticInterpolation(prev_magn_sqr, curr_magn_sqr, next_magn_sqr); } f_peak[i] = (index_peak + fractional_index) * kFrequencyResolution; } } // Using iSAC functions to estimate pitch gains & lags. void VadAudioProc::PitchAnalysis(double* log_pitch_gains, double* pitch_lags_hz, size_t length) { // TODO(turajs): This can be "imported" from iSAC & and the next two // constants. RTC_DCHECK_GE(length, kNum10msSubframes); const int kNumPitchSubframes = 4; double gains[kNumPitchSubframes]; double lags[kNumPitchSubframes]; const int kNumSubbandFrameSamples = 240; const int kNumLookaheadSamples = 24; float lower[kNumSubbandFrameSamples]; float upper[kNumSubbandFrameSamples]; double lower_lookahead[kNumSubbandFrameSamples]; double upper_lookahead[kNumSubbandFrameSamples]; double lower_lookahead_pre_filter[kNumSubbandFrameSamples + kNumLookaheadSamples]; // Split signal to lower and upper bands WebRtcIsac_SplitAndFilterFloat(&audio_buffer_[kNumPastSignalSamples], lower, upper, lower_lookahead, upper_lookahead, pre_filter_handle_.get()); WebRtcIsac_PitchAnalysis(lower_lookahead, lower_lookahead_pre_filter, pitch_analysis_handle_.get(), lags, gains); // Lags are computed on lower-band signal with sampling rate half of the // input signal. GetSubframesPitchParameters( kSampleRateHz / 2, gains, lags, kNumPitchSubframes, kNum10msSubframes, &log_old_gain_, &old_lag_, log_pitch_gains, pitch_lags_hz); } void VadAudioProc::Rms(double* rms, size_t length_rms) { RTC_DCHECK_GE(length_rms, kNum10msSubframes); size_t offset = kNumPastSignalSamples; for (size_t i = 0; i < kNum10msSubframes; i++) { rms[i] = 0; for (size_t n = 0; n < kNumSubframeSamples; n++, offset++) rms[i] += audio_buffer_[offset] * audio_buffer_[offset]; rms[i] = sqrt(rms[i] / kNumSubframeSamples); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/vad_audio_proc.h0000664000175000017500000000566214475643423027073 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_VAD_VAD_AUDIO_PROC_H_ #define MODULES_AUDIO_PROCESSING_VAD_VAD_AUDIO_PROC_H_ #include #include #include #include "modules/audio_processing/vad/common.h" // AudioFeatures, kSampleR... namespace webrtc { class PoleZeroFilter; class VadAudioProc { public: // Forward declare iSAC structs. struct PitchAnalysisStruct; struct PreFiltBankstr; VadAudioProc(); ~VadAudioProc(); int ExtractFeatures(const int16_t* audio_frame, size_t length, AudioFeatures* audio_features); static const size_t kDftSize = 512; private: void PitchAnalysis(double* pitch_gains, double* pitch_lags_hz, size_t length); void SubframeCorrelation(double* corr, size_t length_corr, size_t subframe_index); void GetLpcPolynomials(double* lpc, size_t length_lpc); void FindFirstSpectralPeaks(double* f_peak, size_t length_f_peak); void Rms(double* rms, size_t length_rms); void ResetBuffer(); // To compute spectral peak we perform LPC analysis to get spectral envelope. // For every 30 ms we compute 3 spectral peak there for 3 LPC analysis. // LPC is computed over 15 ms of windowed audio. For every 10 ms sub-frame // we need 5 ms of past signal to create the input of LPC analysis. enum : size_t { kNumPastSignalSamples = static_cast(kSampleRateHz / 200) }; // TODO(turajs): maybe defining this at a higher level (maybe enum) so that // all the code recognize it as "no-error." enum : int { kNoError = 0 }; enum : size_t { kNum10msSubframes = 3 }; enum : size_t { kNumSubframeSamples = static_cast(kSampleRateHz / 100) }; enum : size_t { // Samples in 30 ms @ given sampling rate. kNumSamplesToProcess = kNum10msSubframes * kNumSubframeSamples }; enum : size_t { kBufferLength = kNumPastSignalSamples + kNumSamplesToProcess }; enum : size_t { kIpLength = kDftSize >> 1 }; enum : size_t { kWLength = kDftSize >> 1 }; enum : size_t { kLpcOrder = 16 }; size_t ip_[kIpLength]; float w_fft_[kWLength]; // A buffer of 5 ms (past audio) + 30 ms (one iSAC frame ). float audio_buffer_[kBufferLength]; size_t num_buffer_samples_; double log_old_gain_; double old_lag_; std::unique_ptr pitch_analysis_handle_; std::unique_ptr pre_filter_handle_; std::unique_ptr high_pass_filter_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_VAD_VAD_AUDIO_PROC_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/vad_audio_proc_internal.h0000664000175000017500000001112114475643423030752 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_VAD_VAD_AUDIO_PROC_INTERNAL_H_ #define MODULES_AUDIO_PROCESSING_VAD_VAD_AUDIO_PROC_INTERNAL_H_ namespace webrtc { // These values should match MATLAB counterparts for unit-tests to pass. static const double kCorrWeight[] = { 1.000000, 0.985000, 0.970225, 0.955672, 0.941337, 0.927217, 0.913308, 0.899609, 0.886115, 0.872823, 0.859730, 0.846834, 0.834132, 0.821620, 0.809296, 0.797156, 0.785199}; static const double kLpcAnalWin[] = { 0.00000000, 0.01314436, 0.02628645, 0.03942400, 0.05255473, 0.06567639, 0.07878670, 0.09188339, 0.10496421, 0.11802689, 0.13106918, 0.14408883, 0.15708358, 0.17005118, 0.18298941, 0.19589602, 0.20876878, 0.22160547, 0.23440387, 0.24716177, 0.25987696, 0.27254725, 0.28517045, 0.29774438, 0.31026687, 0.32273574, 0.33514885, 0.34750406, 0.35979922, 0.37203222, 0.38420093, 0.39630327, 0.40833713, 0.42030043, 0.43219112, 0.44400713, 0.45574642, 0.46740697, 0.47898676, 0.49048379, 0.50189608, 0.51322164, 0.52445853, 0.53560481, 0.54665854, 0.55761782, 0.56848075, 0.57924546, 0.58991008, 0.60047278, 0.61093173, 0.62128512, 0.63153117, 0.64166810, 0.65169416, 0.66160761, 0.67140676, 0.68108990, 0.69065536, 0.70010148, 0.70942664, 0.71862923, 0.72770765, 0.73666033, 0.74548573, 0.75418233, 0.76274862, 0.77118312, 0.77948437, 0.78765094, 0.79568142, 0.80357442, 0.81132858, 0.81894256, 0.82641504, 0.83374472, 0.84093036, 0.84797069, 0.85486451, 0.86161063, 0.86820787, 0.87465511, 0.88095122, 0.88709512, 0.89308574, 0.89892206, 0.90460306, 0.91012776, 0.91549520, 0.92070447, 0.92575465, 0.93064488, 0.93537432, 0.93994213, 0.94434755, 0.94858979, 0.95266814, 0.95658189, 0.96033035, 0.96391289, 0.96732888, 0.97057773, 0.97365889, 0.97657181, 0.97931600, 0.98189099, 0.98429632, 0.98653158, 0.98859639, 0.99049038, 0.99221324, 0.99376466, 0.99514438, 0.99635215, 0.99738778, 0.99825107, 0.99894188, 0.99946010, 0.99980562, 0.99997840, 0.99997840, 0.99980562, 0.99946010, 0.99894188, 0.99825107, 0.99738778, 0.99635215, 0.99514438, 0.99376466, 0.99221324, 0.99049038, 0.98859639, 0.98653158, 0.98429632, 0.98189099, 0.97931600, 0.97657181, 0.97365889, 0.97057773, 0.96732888, 0.96391289, 0.96033035, 0.95658189, 0.95266814, 0.94858979, 0.94434755, 0.93994213, 0.93537432, 0.93064488, 0.92575465, 0.92070447, 0.91549520, 0.91012776, 0.90460306, 0.89892206, 0.89308574, 0.88709512, 0.88095122, 0.87465511, 0.86820787, 0.86161063, 0.85486451, 0.84797069, 0.84093036, 0.83374472, 0.82641504, 0.81894256, 0.81132858, 0.80357442, 0.79568142, 0.78765094, 0.77948437, 0.77118312, 0.76274862, 0.75418233, 0.74548573, 0.73666033, 0.72770765, 0.71862923, 0.70942664, 0.70010148, 0.69065536, 0.68108990, 0.67140676, 0.66160761, 0.65169416, 0.64166810, 0.63153117, 0.62128512, 0.61093173, 0.60047278, 0.58991008, 0.57924546, 0.56848075, 0.55761782, 0.54665854, 0.53560481, 0.52445853, 0.51322164, 0.50189608, 0.49048379, 0.47898676, 0.46740697, 0.45574642, 0.44400713, 0.43219112, 0.42030043, 0.40833713, 0.39630327, 0.38420093, 0.37203222, 0.35979922, 0.34750406, 0.33514885, 0.32273574, 0.31026687, 0.29774438, 0.28517045, 0.27254725, 0.25987696, 0.24716177, 0.23440387, 0.22160547, 0.20876878, 0.19589602, 0.18298941, 0.17005118, 0.15708358, 0.14408883, 0.13106918, 0.11802689, 0.10496421, 0.09188339, 0.07878670, 0.06567639, 0.05255473, 0.03942400, 0.02628645, 0.01314436, 0.00000000}; static const size_t kFilterOrder = 2; static const float kCoeffNumerator[kFilterOrder + 1] = {0.974827f, -1.949650f, 0.974827f}; static const float kCoeffDenominator[kFilterOrder + 1] = {1.0f, -1.971999f, 0.972457f}; static_assert(kFilterOrder + 1 == sizeof(kCoeffNumerator) / sizeof(kCoeffNumerator[0]), "numerator coefficients incorrect size"); static_assert(kFilterOrder + 1 == sizeof(kCoeffDenominator) / sizeof(kCoeffDenominator[0]), "denominator coefficients incorrect size"); } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_VAD_VAD_AUDIO_PROCESSING_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/vad_circular_buffer.cc0000664000175000017500000000556714475643423030246 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/vad/vad_circular_buffer.h" #include namespace webrtc { VadCircularBuffer::VadCircularBuffer(int buffer_size) : buffer_(new double[buffer_size]), is_full_(false), index_(0), buffer_size_(buffer_size), sum_(0) {} VadCircularBuffer::~VadCircularBuffer() {} void VadCircularBuffer::Reset() { is_full_ = false; index_ = 0; sum_ = 0; } VadCircularBuffer* VadCircularBuffer::Create(int buffer_size) { if (buffer_size <= 0) return NULL; return new VadCircularBuffer(buffer_size); } double VadCircularBuffer::Oldest() const { if (!is_full_) return buffer_[0]; else return buffer_[index_]; } double VadCircularBuffer::Mean() { double m; if (is_full_) { m = sum_ / buffer_size_; } else { if (index_ > 0) m = sum_ / index_; else m = 0; } return m; } void VadCircularBuffer::Insert(double value) { if (is_full_) { sum_ -= buffer_[index_]; } sum_ += value; buffer_[index_] = value; index_++; if (index_ >= buffer_size_) { is_full_ = true; index_ = 0; } } int VadCircularBuffer::BufferLevel() { if (is_full_) return buffer_size_; return index_; } int VadCircularBuffer::Get(int index, double* value) const { int err = ConvertToLinearIndex(&index); if (err < 0) return -1; *value = buffer_[index]; return 0; } int VadCircularBuffer::Set(int index, double value) { int err = ConvertToLinearIndex(&index); if (err < 0) return -1; sum_ -= buffer_[index]; buffer_[index] = value; sum_ += value; return 0; } int VadCircularBuffer::ConvertToLinearIndex(int* index) const { if (*index < 0 || *index >= buffer_size_) return -1; if (!is_full_ && *index >= index_) return -1; *index = index_ - 1 - *index; if (*index < 0) *index += buffer_size_; return 0; } int VadCircularBuffer::RemoveTransient(int width_threshold, double val_threshold) { if (!is_full_ && index_ < width_threshold + 2) return 0; int index_1 = 0; int index_2 = width_threshold + 1; double v = 0; if (Get(index_1, &v) < 0) return -1; if (v < val_threshold) { Set(index_1, 0); int index; for (index = index_2; index > index_1; index--) { if (Get(index, &v) < 0) return -1; if (v < val_threshold) break; } for (; index > index_1; index--) { if (Set(index, 0.0) < 0) return -1; } } return 0; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/vad_circular_buffer.h0000664000175000017500000000470114475643423030075 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_VAD_VAD_CIRCULAR_BUFFER_H_ #define MODULES_AUDIO_PROCESSING_VAD_VAD_CIRCULAR_BUFFER_H_ #include namespace webrtc { // A circular buffer tailored to the need of this project. It stores last // K samples of the input, and keeps track of the mean of the last samples. // // It is used in class "PitchBasedActivity" to keep track of posterior // probabilities in the past few seconds. The posterior probabilities are used // to recursively update prior probabilities. class VadCircularBuffer { public: static VadCircularBuffer* Create(int buffer_size); ~VadCircularBuffer(); // If buffer is wrapped around. bool is_full() const { return is_full_; } // Get the oldest entry in the buffer. double Oldest() const; // Insert new value into the buffer. void Insert(double value); // Reset buffer, forget the past, start fresh. void Reset(); // The mean value of the elements in the buffer. The return value is zero if // buffer is empty, i.e. no value is inserted. double Mean(); // Remove transients. If the values exceed |val_threshold| for a period // shorter then or equal to |width_threshold|, then that period is considered // transient and set to zero. int RemoveTransient(int width_threshold, double val_threshold); private: explicit VadCircularBuffer(int buffer_size); // Get previous values. |index = 0| corresponds to the most recent // insertion. |index = 1| is the one before the most recent insertion, and // so on. int Get(int index, double* value) const; // Set a given position to |value|. |index| is interpreted as above. int Set(int index, double value); // Return the number of valid elements in the buffer. int BufferLevel(); // Convert an index with the interpretation as get() method to the // corresponding linear index. int ConvertToLinearIndex(int* index) const; std::unique_ptr buffer_; bool is_full_; int index_; int buffer_size_; double sum_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_VAD_VAD_CIRCULAR_BUFFER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/voice_activity_detector.cc0000664000175000017500000000605514475643423031162 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/vad/voice_activity_detector.h" #include #include "rtc_base/checks.h" namespace webrtc { namespace { const size_t kNumChannels = 1; const double kDefaultVoiceValue = 1.0; const double kNeutralProbability = 0.5; const double kLowProbability = 0.01; } // namespace VoiceActivityDetector::VoiceActivityDetector() : last_voice_probability_(kDefaultVoiceValue), standalone_vad_(StandaloneVad::Create()) {} VoiceActivityDetector::~VoiceActivityDetector() = default; // Because ISAC has a different chunk length, it updates // |chunkwise_voice_probabilities_| and |chunkwise_rms_| when there is new data. // Otherwise it clears them. void VoiceActivityDetector::ProcessChunk(const int16_t* audio, size_t length, int sample_rate_hz) { RTC_DCHECK_EQ(length, sample_rate_hz / 100); // Resample to the required rate. const int16_t* resampled_ptr = audio; if (sample_rate_hz != kSampleRateHz) { RTC_CHECK_EQ( resampler_.ResetIfNeeded(sample_rate_hz, kSampleRateHz, kNumChannels), 0); resampler_.Push(audio, length, resampled_, kLength10Ms, length); resampled_ptr = resampled_; } RTC_DCHECK_EQ(length, kLength10Ms); // Each chunk needs to be passed into |standalone_vad_|, because internally it // buffers the audio and processes it all at once when GetActivity() is // called. RTC_CHECK_EQ(standalone_vad_->AddAudio(resampled_ptr, length), 0); audio_processing_.ExtractFeatures(resampled_ptr, length, &features_); chunkwise_voice_probabilities_.resize(features_.num_frames); chunkwise_rms_.resize(features_.num_frames); std::copy(features_.rms, features_.rms + chunkwise_rms_.size(), chunkwise_rms_.begin()); if (features_.num_frames > 0) { if (features_.silence) { // The other features are invalid, so set the voice probabilities to an // arbitrary low value. std::fill(chunkwise_voice_probabilities_.begin(), chunkwise_voice_probabilities_.end(), kLowProbability); } else { std::fill(chunkwise_voice_probabilities_.begin(), chunkwise_voice_probabilities_.end(), kNeutralProbability); RTC_CHECK_GE( standalone_vad_->GetActivity(&chunkwise_voice_probabilities_[0], chunkwise_voice_probabilities_.size()), 0); RTC_CHECK_GE(pitch_based_vad_.VoicingProbability( features_, &chunkwise_voice_probabilities_[0]), 0); } last_voice_probability_ = chunkwise_voice_probabilities_.back(); } } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/voice_activity_detector.h0000664000175000017500000000465014475643423031023 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_VAD_VOICE_ACTIVITY_DETECTOR_H_ #define MODULES_AUDIO_PROCESSING_VAD_VOICE_ACTIVITY_DETECTOR_H_ #include #include #include #include #include "common_audio/resampler/include/resampler.h" #include "modules/audio_processing/vad/common.h" #include "modules/audio_processing/vad/pitch_based_vad.h" #include "modules/audio_processing/vad/standalone_vad.h" #include "modules/audio_processing/vad/vad_audio_proc.h" namespace webrtc { // A Voice Activity Detector (VAD) that combines the voice probability from the // StandaloneVad and PitchBasedVad to get a more robust estimation. class VoiceActivityDetector { public: VoiceActivityDetector(); ~VoiceActivityDetector(); // Processes each audio chunk and estimates the voice probability. void ProcessChunk(const int16_t* audio, size_t length, int sample_rate_hz); // Returns a vector of voice probabilities for each chunk. It can be empty for // some chunks, but it catches up afterwards returning multiple values at // once. const std::vector& chunkwise_voice_probabilities() const { return chunkwise_voice_probabilities_; } // Returns a vector of RMS values for each chunk. It has the same length as // chunkwise_voice_probabilities(). const std::vector& chunkwise_rms() const { return chunkwise_rms_; } // Returns the last voice probability, regardless of the internal // implementation, although it has a few chunks of delay. float last_voice_probability() const { return last_voice_probability_; } private: // TODO(aluebs): Change these to float. std::vector chunkwise_voice_probabilities_; std::vector chunkwise_rms_; float last_voice_probability_; Resampler resampler_; VadAudioProc audio_processing_; std::unique_ptr standalone_vad_; PitchBasedVad pitch_based_vad_; int16_t resampled_[kLength10Ms]; AudioFeatures features_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_VAD_VOICE_ACTIVITY_DETECTOR_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/vad/voice_gmm_tables.h0000664000175000017500000001156514475643423027413 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // GMM tables for active segments. Generated by MakeGmmTables.m. #ifndef MODULES_AUDIO_PROCESSING_VAD_VOICE_GMM_TABLES_H_ #define MODULES_AUDIO_PROCESSING_VAD_VOICE_GMM_TABLES_H_ static const int kVoiceGmmNumMixtures = 12; static const int kVoiceGmmDim = 3; static const double kVoiceGmmCovarInverse[kVoiceGmmNumMixtures][kVoiceGmmDim][kVoiceGmmDim] = { {{1.83673825579513e+00, -8.09791637570095e-04, 4.60106414365986e-03}, {-8.09791637570095e-04, 8.89351738394608e-04, -9.80188953277734e-04}, {4.60106414365986e-03, -9.80188953277734e-04, 1.38706060206582e-03}}, {{6.76228912850703e+01, -1.98893120119660e-02, -3.53548357253551e-03}, {-1.98893120119660e-02, 3.96216858500530e-05, -4.08492938394097e-05}, {-3.53548357253551e-03, -4.08492938394097e-05, 9.31864352856416e-04}}, {{9.98612435944558e+00, -5.27880954316893e-03, -6.30342541619017e-03}, {-5.27880954316893e-03, 4.54359480225226e-05, 6.30804591626044e-05}, {-6.30342541619017e-03, 6.30804591626044e-05, 5.36466441382942e-04}}, {{3.39917474216349e+01, -1.56213579433191e-03, -4.01459014990225e-02}, {-1.56213579433191e-03, 6.40415424897724e-05, 6.20076342427833e-05}, {-4.01459014990225e-02, 6.20076342427833e-05, 3.51199070103063e-03}}, {{1.34545062271428e+01, -7.94513610147144e-03, -5.34401019341728e-02}, {-7.94513610147144e-03, 1.16511820098649e-04, 4.66063702069293e-05}, {-5.34401019341728e-02, 4.66063702069293e-05, 2.72354323774163e-03}}, {{1.08557844314806e+02, -1.54885805673668e-02, -1.88029692674851e-02}, {-1.54885805673668e-02, 1.16404042786406e-04, 6.45579292702802e-06}, {-1.88029692674851e-02, 6.45579292702802e-06, 4.32330478391416e-04}}, {{8.22940066541450e+01, -1.15903110231303e-02, -4.92166764865343e-02}, {-1.15903110231303e-02, 7.42510742165261e-05, 3.73007314191290e-06}, {-4.92166764865343e-02, 3.73007314191290e-06, 3.64005221593244e-03}}, {{2.31133605685660e+00, -7.83261568950254e-04, 7.45744012346313e-04}, {-7.83261568950254e-04, 1.29460648214142e-05, -2.22774455093730e-06}, {7.45744012346313e-04, -2.22774455093730e-06, 1.05117294093010e-04}}, {{3.78767849189611e+02, 1.57759761011568e-03, -2.08551217988774e-02}, {1.57759761011568e-03, 4.76066236886865e-05, -2.33977412299324e-05}, {-2.08551217988774e-02, -2.33977412299324e-05, 5.24261005371196e-04}}, {{6.98580096506135e-01, -5.13850255217378e-04, -4.01124551717056e-04}, {-5.13850255217378e-04, 1.40501021984840e-06, -2.09496928716569e-06}, {-4.01124551717056e-04, -2.09496928716569e-06, 2.82879357740037e-04}}, {{2.62770945162399e+00, -2.31825753241430e-03, -5.30447217466318e-03}, {-2.31825753241430e-03, 4.59108572227649e-05, 7.67631886355405e-05}, {-5.30447217466318e-03, 7.67631886355405e-05, 2.28521601674098e-03}}, {{1.89940391362152e+02, -4.23280856852379e-03, -2.70608873541399e-02}, {-4.23280856852379e-03, 6.77547582742563e-05, 2.69154203800467e-05}, {-2.70608873541399e-02, 2.69154203800467e-05, 3.88574543373470e-03}}}; static const double kVoiceGmmMean[kVoiceGmmNumMixtures][kVoiceGmmDim] = { {-2.15020241646536e+00, 4.97079062999877e+02, 4.77078119504505e+02}, {-8.92097680029190e-01, 5.92064964199921e+02, 1.81045145941059e+02}, {-1.29435784144398e+00, 4.98450293410611e+02, 1.71991263804064e+02}, {-1.03925228397884e+00, 4.99511274321571e+02, 1.05838336539105e+02}, {-1.29229047206129e+00, 4.15026762566707e+02, 1.12861119017125e+02}, {-7.88748114599810e-01, 4.48739336688113e+02, 1.89784216956337e+02}, {-8.77777402332642e-01, 4.86620285054533e+02, 1.13477708016491e+02}, {-2.06465957063057e+00, 6.33385049870607e+02, 2.32758546796149e+02}, {-6.98893789231685e-01, 5.93622051503385e+02, 1.92536982473203e+02}, {-2.55901217508894e+00, 1.55914919756205e+03, 1.39769980835570e+02}, {-1.92070024165837e+00, 4.87983940444185e+02, 1.02745468128289e+02}, {-7.29187507662854e-01, 5.22717685022855e+02, 1.16377942283991e+02}}; static const double kVoiceGmmWeights[kVoiceGmmNumMixtures] = { -1.39789694361035e+01, -1.19527720202104e+01, -1.32396317929055e+01, -1.09436815209238e+01, -1.13440027478149e+01, -1.12200721834504e+01, -1.02537324043693e+01, -1.60789861938302e+01, -1.03394494048344e+01, -1.83207938586818e+01, -1.31186044948288e+01, -9.52479998673554e+00}; #endif // MODULES_AUDIO_PROCESSING_VAD_VOICE_GMM_TABLES_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/voice_detection.cc0000664000175000017500000000563714475643423026646 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/voice_detection.h" #include "common_audio/vad/include/webrtc_vad.h" #include "modules/audio_processing/audio_buffer.h" #include "rtc_base/checks.h" namespace webrtc { class VoiceDetection::Vad { public: Vad() { state_ = WebRtcVad_Create(); RTC_CHECK(state_); int error = WebRtcVad_Init(state_); RTC_DCHECK_EQ(0, error); } ~Vad() { WebRtcVad_Free(state_); } Vad(Vad&) = delete; Vad& operator=(Vad&) = delete; VadInst* state() { return state_; } private: VadInst* state_ = nullptr; }; VoiceDetection::VoiceDetection(int sample_rate_hz, Likelihood likelihood) : sample_rate_hz_(sample_rate_hz), frame_size_samples_(static_cast(sample_rate_hz_ / 100)), likelihood_(likelihood), vad_(new Vad()) { int mode = 2; switch (likelihood) { case VoiceDetection::kVeryLowLikelihood: mode = 3; break; case VoiceDetection::kLowLikelihood: mode = 2; break; case VoiceDetection::kModerateLikelihood: mode = 1; break; case VoiceDetection::kHighLikelihood: mode = 0; break; default: RTC_NOTREACHED(); break; } int error = WebRtcVad_set_mode(vad_->state(), mode); RTC_DCHECK_EQ(0, error); } VoiceDetection::~VoiceDetection() {} bool VoiceDetection::ProcessCaptureAudio(AudioBuffer* audio) { RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio->num_frames_per_band()); std::array mixed_low_pass_data; rtc::ArrayView mixed_low_pass(mixed_low_pass_data.data(), audio->num_frames_per_band()); if (audio->num_channels() == 1) { FloatS16ToS16(audio->split_bands_const(0)[kBand0To8kHz], audio->num_frames_per_band(), mixed_low_pass_data.data()); } else { const int num_channels = static_cast(audio->num_channels()); for (size_t i = 0; i < audio->num_frames_per_band(); ++i) { int32_t value = FloatS16ToS16(audio->split_channels_const(kBand0To8kHz)[0][i]); for (int j = 1; j < num_channels; ++j) { value += FloatS16ToS16(audio->split_channels_const(kBand0To8kHz)[j][i]); } mixed_low_pass_data[i] = value / num_channels; } } int vad_ret = WebRtcVad_Process(vad_->state(), sample_rate_hz_, mixed_low_pass.data(), frame_size_samples_); RTC_DCHECK(vad_ret == 0 || vad_ret == 1); return vad_ret == 0 ? false : true; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/audio_processing/voice_detection.h0000664000175000017500000000323214475643423026475 0ustar00arunarun/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_AUDIO_PROCESSING_VOICE_DETECTION_H_ #define MODULES_AUDIO_PROCESSING_VOICE_DETECTION_H_ #include #include #include "modules/audio_processing/include/audio_processing.h" namespace webrtc { class AudioBuffer; // The voice activity detection (VAD) component analyzes the stream to // determine if voice is present. class VoiceDetection { public: // Specifies the likelihood that a frame will be declared to contain voice. // A higher value makes it more likely that speech will not be clipped, at // the expense of more noise being detected as voice. enum Likelihood { kVeryLowLikelihood, kLowLikelihood, kModerateLikelihood, kHighLikelihood }; VoiceDetection(int sample_rate_hz, Likelihood likelihood); ~VoiceDetection(); VoiceDetection(VoiceDetection&) = delete; VoiceDetection& operator=(VoiceDetection&) = delete; // Returns true if voice is detected in the current frame. bool ProcessCaptureAudio(AudioBuffer* audio); Likelihood likelihood() const { return likelihood_; } private: class Vad; int sample_rate_hz_; size_t frame_size_samples_; Likelihood likelihood_; std::unique_ptr vad_; }; } // namespace webrtc #endif // MODULES_AUDIO_PROCESSING_VOICE_DETECTION_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/meson.build0000664000175000017500000000011414475643423021762 0ustar00arunarunsubdir('third_party/fft') subdir('audio_coding') subdir('audio_processing') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/third_party/0000775000175000017500000000000014475643423022155 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/third_party/fft/0000775000175000017500000000000014475643423022734 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/third_party/fft/BUILD.gn0000664000175000017500000000076514475643423024131 0ustar00arunarun# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the ../../../LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../../../webrtc.gni") rtc_library("fft") { sources = [ "fft.c", "fft.h", ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/third_party/fft/LICENSE0000664000175000017500000000214514475643423023743 0ustar00arunarun/* * Copyright(c)1995,97 Mark Olesen * Queen's Univ at Kingston (Canada) * * Permission to use, copy, modify, and distribute this software for * any purpose without fee is hereby granted, provided that this * entire notice is included in all copies of any software which is * or includes a copy or modification of this software and in all * copies of the supporting documentation for such software. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR * IMPLIED WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR QUEEN'S * UNIVERSITY AT KINGSTON MAKES ANY REPRESENTATION OR WARRANTY OF ANY * KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS * FITNESS FOR ANY PARTICULAR PURPOSE. * * All of which is to say that you can do what you like with this * source code provided you don't try to sell it as your own and you * include an unaltered copy of this message (including the * copyright). * * It is also implicitly understood that bug fixes and improvements * should make their way back to the general Internet community so * that everyone benefits. */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/third_party/fft/fft.c0000664000175000017500000006317314475643423023671 0ustar00arunarun/* * Copyright(c)1995,97 Mark Olesen * Queen's Univ at Kingston (Canada) * * Permission to use, copy, modify, and distribute this software for * any purpose without fee is hereby granted, provided that this * entire notice is included in all copies of any software which is * or includes a copy or modification of this software and in all * copies of the supporting documentation for such software. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR * IMPLIED WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR QUEEN'S * UNIVERSITY AT KINGSTON MAKES ANY REPRESENTATION OR WARRANTY OF ANY * KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS * FITNESS FOR ANY PARTICULAR PURPOSE. * * All of which is to say that you can do what you like with this * source code provided you don't try to sell it as your own and you * include an unaltered copy of this message (including the * copyright). * * It is also implicitly understood that bug fixes and improvements * should make their way back to the general Internet community so * that everyone benefits. * * Changes: * Trivial type modifications by the WebRTC authors. */ /* * File: * WebRtcIsac_Fftn.c * * Public: * WebRtcIsac_Fftn / fftnf (); * * Private: * WebRtcIsac_Fftradix / fftradixf (); * * Descript: * multivariate complex Fourier transform, computed in place * using mixed-radix Fast Fourier Transform algorithm. * * Fortran code by: * RC Singleton, Stanford Research Institute, Sept. 1968 * * translated by f2c (version 19950721). * * int WebRtcIsac_Fftn (int ndim, const int dims[], REAL Re[], REAL Im[], * int iSign, double scaling); * * NDIM = the total number dimensions * DIMS = a vector of array sizes * if NDIM is zero then DIMS must be zero-terminated * * RE and IM hold the real and imaginary components of the data, and return * the resulting real and imaginary Fourier coefficients. Multidimensional * data *must* be allocated contiguously. There is no limit on the number * of dimensions. * * ISIGN = the sign of the complex exponential (ie, forward or inverse FFT) * the magnitude of ISIGN (normally 1) is used to determine the * correct indexing increment (see below). * * SCALING = normalizing constant by which the final result is *divided* * if SCALING == -1, normalize by total dimension of the transform * if SCALING < -1, normalize by the square-root of the total dimension * * example: * tri-variate transform with Re[n1][n2][n3], Im[n1][n2][n3] * * int dims[3] = {n1,n2,n3} * WebRtcIsac_Fftn (3, dims, Re, Im, 1, scaling); * *-----------------------------------------------------------------------* * int WebRtcIsac_Fftradix (REAL Re[], REAL Im[], size_t nTotal, size_t nPass, * size_t nSpan, int iSign, size_t max_factors, * size_t max_perm); * * RE, IM - see above documentation * * Although there is no limit on the number of dimensions, WebRtcIsac_Fftradix() must * be called once for each dimension, but the calls may be in any order. * * NTOTAL = the total number of complex data values * NPASS = the dimension of the current variable * NSPAN/NPASS = the spacing of consecutive data values while indexing the * current variable * ISIGN - see above documentation * * example: * tri-variate transform with Re[n1][n2][n3], Im[n1][n2][n3] * * WebRtcIsac_Fftradix (Re, Im, n1*n2*n3, n1, n1, 1, maxf, maxp); * WebRtcIsac_Fftradix (Re, Im, n1*n2*n3, n2, n1*n2, 1, maxf, maxp); * WebRtcIsac_Fftradix (Re, Im, n1*n2*n3, n3, n1*n2*n3, 1, maxf, maxp); * * single-variate transform, * NTOTAL = N = NSPAN = (number of complex data values), * * WebRtcIsac_Fftradix (Re, Im, n, n, n, 1, maxf, maxp); * * The data can also be stored in a single array with alternating real and * imaginary parts, the magnitude of ISIGN is changed to 2 to give correct * indexing increment, and data [0] and data [1] used to pass the initial * addresses for the sequences of real and imaginary values, * * example: * REAL data [2*NTOTAL]; * WebRtcIsac_Fftradix ( &data[0], &data[1], NTOTAL, nPass, nSpan, 2, maxf, maxp); * * for temporary allocation: * * MAX_FACTORS >= the maximum prime factor of NPASS * MAX_PERM >= the number of prime factors of NPASS. In addition, * if the square-free portion K of NPASS has two or more prime * factors, then MAX_PERM >= (K-1) * * storage in FACTOR for a maximum of 15 prime factors of NPASS. if NPASS * has more than one square-free factor, the product of the square-free * factors must be <= 210 array storage for maximum prime factor of 23 the * following two constants should agree with the array dimensions. * *----------------------------------------------------------------------*/ #include #include #include "modules/third_party/fft/fft.h" /* double precision routine */ static int WebRtcIsac_Fftradix (double Re[], double Im[], size_t nTotal, size_t nPass, size_t nSpan, int isign, int max_factors, unsigned int max_perm, FFTstr *fftstate); #ifndef M_PI # define M_PI 3.14159265358979323846264338327950288 #endif #ifndef SIN60 # define SIN60 0.86602540378443865 /* sin(60 deg) */ # define COS72 0.30901699437494742 /* cos(72 deg) */ # define SIN72 0.95105651629515357 /* sin(72 deg) */ #endif # define REAL double # define FFTN WebRtcIsac_Fftn # define FFTNS "fftn" # define FFTRADIX WebRtcIsac_Fftradix # define FFTRADIXS "fftradix" int WebRtcIsac_Fftns(unsigned int ndim, const int dims[], double Re[], double Im[], int iSign, double scaling, FFTstr *fftstate) { size_t nSpan, nPass, nTotal; unsigned int i; int ret, max_factors, max_perm; /* * tally the number of elements in the data array * and determine the number of dimensions */ nTotal = 1; if (ndim && dims [0]) { for (i = 0; i < ndim; i++) { if (dims [i] <= 0) { return -1; } nTotal *= dims [i]; } } else { ndim = 0; for (i = 0; dims [i]; i++) { if (dims [i] <= 0) { return -1; } nTotal *= dims [i]; ndim++; } } /* determine maximum number of factors and permuations */ #if 1 /* * follow John Beale's example, just use the largest dimension and don't * worry about excess allocation. May be someone else will do it? */ max_factors = max_perm = 1; for (i = 0; i < ndim; i++) { nSpan = dims [i]; if ((int)nSpan > max_factors) { max_factors = (int)nSpan; } if ((int)nSpan > max_perm) { max_perm = (int)nSpan; } } #else /* use the constants used in the original Fortran code */ max_factors = 23; max_perm = 209; #endif /* loop over the dimensions: */ nPass = 1; for (i = 0; i < ndim; i++) { nSpan = dims [i]; nPass *= nSpan; ret = FFTRADIX (Re, Im, nTotal, nSpan, nPass, iSign, max_factors, max_perm, fftstate); /* exit, clean-up already done */ if (ret) return ret; } /* Divide through by the normalizing constant: */ if (scaling && scaling != 1.0) { if (iSign < 0) iSign = -iSign; if (scaling < 0.0) { scaling = (double)nTotal; if (scaling < -1.0) scaling = sqrt (scaling); } scaling = 1.0 / scaling; /* multiply is often faster */ for (i = 0; i < nTotal; i += iSign) { Re [i] *= scaling; Im [i] *= scaling; } } return 0; } /* * singleton's mixed radix routine * * could move allocation out to WebRtcIsac_Fftn(), but leave it here so that it's * possible to make this a standalone function */ static int FFTRADIX (REAL Re[], REAL Im[], size_t nTotal, size_t nPass, size_t nSpan, int iSign, int max_factors, unsigned int max_perm, FFTstr *fftstate) { int ii, mfactor, kspan, ispan, inc; int j, jc, jf, jj, k, k1, k2, k3, k4, kk, kt, nn, ns, nt; REAL radf; REAL c1, c2, c3, cd, aa, aj, ak, ajm, ajp, akm, akp; REAL s1, s2, s3, sd, bb, bj, bk, bjm, bjp, bkm, bkp; REAL *Rtmp = NULL; /* temp space for real part*/ REAL *Itmp = NULL; /* temp space for imaginary part */ REAL *Cos = NULL; /* Cosine values */ REAL *Sin = NULL; /* Sine values */ REAL s60 = SIN60; /* sin(60 deg) */ REAL c72 = COS72; /* cos(72 deg) */ REAL s72 = SIN72; /* sin(72 deg) */ REAL pi2 = M_PI; /* use PI first, 2 PI later */ fftstate->SpaceAlloced = 0; fftstate->MaxPermAlloced = 0; // initialize to avoid warnings k3 = c2 = c3 = s2 = s3 = 0.0; if (nPass < 2) return 0; /* allocate storage */ if (fftstate->SpaceAlloced < max_factors * sizeof (REAL)) { #ifdef SUN_BROKEN_REALLOC if (!fftstate->SpaceAlloced) /* first time */ { fftstate->SpaceAlloced = max_factors * sizeof (REAL); } else { #endif fftstate->SpaceAlloced = max_factors * sizeof (REAL); #ifdef SUN_BROKEN_REALLOC } #endif } else { /* allow full use of alloc'd space */ max_factors = fftstate->SpaceAlloced / sizeof (REAL); } if (fftstate->MaxPermAlloced < max_perm) { #ifdef SUN_BROKEN_REALLOC if (!fftstate->MaxPermAlloced) /* first time */ else #endif fftstate->MaxPermAlloced = max_perm; } else { /* allow full use of alloc'd space */ max_perm = fftstate->MaxPermAlloced; } /* assign pointers */ Rtmp = (REAL *) fftstate->Tmp0; Itmp = (REAL *) fftstate->Tmp1; Cos = (REAL *) fftstate->Tmp2; Sin = (REAL *) fftstate->Tmp3; /* * Function Body */ inc = iSign; if (iSign < 0) { s72 = -s72; s60 = -s60; pi2 = -pi2; inc = -inc; /* absolute value */ } /* adjust for strange increments */ nt = inc * (int)nTotal; ns = inc * (int)nSpan; kspan = ns; nn = nt - inc; jc = ns / (int)nPass; radf = pi2 * (double) jc; pi2 *= 2.0; /* use 2 PI from here on */ ii = 0; jf = 0; /* determine the factors of n */ mfactor = 0; k = (int)nPass; while (k % 16 == 0) { mfactor++; fftstate->factor [mfactor - 1] = 4; k /= 16; } j = 3; jj = 9; do { while (k % jj == 0) { mfactor++; fftstate->factor [mfactor - 1] = j; k /= jj; } j += 2; jj = j * j; } while (jj <= k); if (k <= 4) { kt = mfactor; fftstate->factor [mfactor] = k; if (k != 1) mfactor++; } else { if (k - (k / 4 << 2) == 0) { mfactor++; fftstate->factor [mfactor - 1] = 2; k /= 4; } kt = mfactor; j = 2; do { if (k % j == 0) { mfactor++; fftstate->factor [mfactor - 1] = j; k /= j; } j = ((j + 1) / 2 << 1) + 1; } while (j <= k); } if (kt) { j = kt; do { mfactor++; fftstate->factor [mfactor - 1] = fftstate->factor [j - 1]; j--; } while (j); } /* test that mfactors is in range */ if (mfactor > FFT_NFACTOR) { return -1; } /* compute fourier transform */ for (;;) { sd = radf / (double) kspan; cd = sin(sd); cd = 2.0 * cd * cd; sd = sin(sd + sd); kk = 0; ii++; switch (fftstate->factor [ii - 1]) { case 2: /* transform for factor of 2 (including rotation factor) */ kspan /= 2; k1 = kspan + 2; do { do { k2 = kk + kspan; ak = Re [k2]; bk = Im [k2]; Re [k2] = Re [kk] - ak; Im [k2] = Im [kk] - bk; Re [kk] += ak; Im [kk] += bk; kk = k2 + kspan; } while (kk < nn); kk -= nn; } while (kk < jc); if (kk >= kspan) goto Permute_Results_Label; /* exit infinite loop */ do { c1 = 1.0 - cd; s1 = sd; do { do { do { k2 = kk + kspan; ak = Re [kk] - Re [k2]; bk = Im [kk] - Im [k2]; Re [kk] += Re [k2]; Im [kk] += Im [k2]; Re [k2] = c1 * ak - s1 * bk; Im [k2] = s1 * ak + c1 * bk; kk = k2 + kspan; } while (kk < (nt-1)); k2 = kk - nt; c1 = -c1; kk = k1 - k2; } while (kk > k2); ak = c1 - (cd * c1 + sd * s1); s1 = sd * c1 - cd * s1 + s1; c1 = 2.0 - (ak * ak + s1 * s1); s1 *= c1; c1 *= ak; kk += jc; } while (kk < k2); k1 += inc + inc; kk = (k1 - kspan + 1) / 2 + jc - 1; } while (kk < (jc + jc)); break; case 4: /* transform for factor of 4 */ ispan = kspan; kspan /= 4; do { c1 = 1.0; s1 = 0.0; do { do { k1 = kk + kspan; k2 = k1 + kspan; k3 = k2 + kspan; akp = Re [kk] + Re [k2]; akm = Re [kk] - Re [k2]; ajp = Re [k1] + Re [k3]; ajm = Re [k1] - Re [k3]; bkp = Im [kk] + Im [k2]; bkm = Im [kk] - Im [k2]; bjp = Im [k1] + Im [k3]; bjm = Im [k1] - Im [k3]; Re [kk] = akp + ajp; Im [kk] = bkp + bjp; ajp = akp - ajp; bjp = bkp - bjp; if (iSign < 0) { akp = akm + bjm; bkp = bkm - ajm; akm -= bjm; bkm += ajm; } else { akp = akm - bjm; bkp = bkm + ajm; akm += bjm; bkm -= ajm; } /* avoid useless multiplies */ if (s1 == 0.0) { Re [k1] = akp; Re [k2] = ajp; Re [k3] = akm; Im [k1] = bkp; Im [k2] = bjp; Im [k3] = bkm; } else { Re [k1] = akp * c1 - bkp * s1; Re [k2] = ajp * c2 - bjp * s2; Re [k3] = akm * c3 - bkm * s3; Im [k1] = akp * s1 + bkp * c1; Im [k2] = ajp * s2 + bjp * c2; Im [k3] = akm * s3 + bkm * c3; } kk = k3 + kspan; } while (kk < nt); c2 = c1 - (cd * c1 + sd * s1); s1 = sd * c1 - cd * s1 + s1; c1 = 2.0 - (c2 * c2 + s1 * s1); s1 *= c1; c1 *= c2; /* values of c2, c3, s2, s3 that will get used next time */ c2 = c1 * c1 - s1 * s1; s2 = 2.0 * c1 * s1; c3 = c2 * c1 - s2 * s1; s3 = c2 * s1 + s2 * c1; kk = kk - nt + jc; } while (kk < kspan); kk = kk - kspan + inc; } while (kk < jc); if (kspan == jc) goto Permute_Results_Label; /* exit infinite loop */ break; default: /* transform for odd factors */ #ifdef FFT_RADIX4 return -1; break; #else /* FFT_RADIX4 */ k = fftstate->factor [ii - 1]; ispan = kspan; kspan /= k; switch (k) { case 3: /* transform for factor of 3 (optional code) */ do { do { k1 = kk + kspan; k2 = k1 + kspan; ak = Re [kk]; bk = Im [kk]; aj = Re [k1] + Re [k2]; bj = Im [k1] + Im [k2]; Re [kk] = ak + aj; Im [kk] = bk + bj; ak -= 0.5 * aj; bk -= 0.5 * bj; aj = (Re [k1] - Re [k2]) * s60; bj = (Im [k1] - Im [k2]) * s60; Re [k1] = ak - bj; Re [k2] = ak + bj; Im [k1] = bk + aj; Im [k2] = bk - aj; kk = k2 + kspan; } while (kk < (nn - 1)); kk -= nn; } while (kk < kspan); break; case 5: /* transform for factor of 5 (optional code) */ c2 = c72 * c72 - s72 * s72; s2 = 2.0 * c72 * s72; do { do { k1 = kk + kspan; k2 = k1 + kspan; k3 = k2 + kspan; k4 = k3 + kspan; akp = Re [k1] + Re [k4]; akm = Re [k1] - Re [k4]; bkp = Im [k1] + Im [k4]; bkm = Im [k1] - Im [k4]; ajp = Re [k2] + Re [k3]; ajm = Re [k2] - Re [k3]; bjp = Im [k2] + Im [k3]; bjm = Im [k2] - Im [k3]; aa = Re [kk]; bb = Im [kk]; Re [kk] = aa + akp + ajp; Im [kk] = bb + bkp + bjp; ak = akp * c72 + ajp * c2 + aa; bk = bkp * c72 + bjp * c2 + bb; aj = akm * s72 + ajm * s2; bj = bkm * s72 + bjm * s2; Re [k1] = ak - bj; Re [k4] = ak + bj; Im [k1] = bk + aj; Im [k4] = bk - aj; ak = akp * c2 + ajp * c72 + aa; bk = bkp * c2 + bjp * c72 + bb; aj = akm * s2 - ajm * s72; bj = bkm * s2 - bjm * s72; Re [k2] = ak - bj; Re [k3] = ak + bj; Im [k2] = bk + aj; Im [k3] = bk - aj; kk = k4 + kspan; } while (kk < (nn-1)); kk -= nn; } while (kk < kspan); break; default: if (k != jf) { jf = k; s1 = pi2 / (double) k; c1 = cos(s1); s1 = sin(s1); if (jf > max_factors){ return -1; } Cos [jf - 1] = 1.0; Sin [jf - 1] = 0.0; j = 1; do { Cos [j - 1] = Cos [k - 1] * c1 + Sin [k - 1] * s1; Sin [j - 1] = Cos [k - 1] * s1 - Sin [k - 1] * c1; k--; Cos [k - 1] = Cos [j - 1]; Sin [k - 1] = -Sin [j - 1]; j++; } while (j < k); } do { do { k1 = kk; k2 = kk + ispan; ak = aa = Re [kk]; bk = bb = Im [kk]; j = 1; k1 += kspan; do { k2 -= kspan; j++; Rtmp [j - 1] = Re [k1] + Re [k2]; ak += Rtmp [j - 1]; Itmp [j - 1] = Im [k1] + Im [k2]; bk += Itmp [j - 1]; j++; Rtmp [j - 1] = Re [k1] - Re [k2]; Itmp [j - 1] = Im [k1] - Im [k2]; k1 += kspan; } while (k1 < k2); Re [kk] = ak; Im [kk] = bk; k1 = kk; k2 = kk + ispan; j = 1; do { k1 += kspan; k2 -= kspan; jj = j; ak = aa; bk = bb; aj = 0.0; bj = 0.0; k = 1; do { k++; ak += Rtmp [k - 1] * Cos [jj - 1]; bk += Itmp [k - 1] * Cos [jj - 1]; k++; aj += Rtmp [k - 1] * Sin [jj - 1]; bj += Itmp [k - 1] * Sin [jj - 1]; jj += j; if (jj > jf) { jj -= jf; } } while (k < jf); k = jf - j; Re [k1] = ak - bj; Im [k1] = bk + aj; Re [k2] = ak + bj; Im [k2] = bk - aj; j++; } while (j < k); kk += ispan; } while (kk < nn); kk -= nn; } while (kk < kspan); break; } /* multiply by rotation factor (except for factors of 2 and 4) */ if (ii == mfactor) goto Permute_Results_Label; /* exit infinite loop */ kk = jc; do { c2 = 1.0 - cd; s1 = sd; do { c1 = c2; s2 = s1; kk += kspan; do { do { ak = Re [kk]; Re [kk] = c2 * ak - s2 * Im [kk]; Im [kk] = s2 * ak + c2 * Im [kk]; kk += ispan; } while (kk < nt); ak = s1 * s2; s2 = s1 * c2 + c1 * s2; c2 = c1 * c2 - ak; kk = kk - nt + kspan; } while (kk < ispan); c2 = c1 - (cd * c1 + sd * s1); s1 += sd * c1 - cd * s1; c1 = 2.0 - (c2 * c2 + s1 * s1); s1 *= c1; c2 *= c1; kk = kk - ispan + jc; } while (kk < kspan); kk = kk - kspan + jc + inc; } while (kk < (jc + jc)); break; #endif /* FFT_RADIX4 */ } } /* permute the results to normal order---done in two stages */ /* permutation for square factors of n */ Permute_Results_Label: fftstate->Perm [0] = ns; if (kt) { k = kt + kt + 1; if (mfactor < k) k--; j = 1; fftstate->Perm [k] = jc; do { fftstate->Perm [j] = fftstate->Perm [j - 1] / fftstate->factor [j - 1]; fftstate->Perm [k - 1] = fftstate->Perm [k] * fftstate->factor [j - 1]; j++; k--; } while (j < k); k3 = fftstate->Perm [k]; kspan = fftstate->Perm [1]; kk = jc; k2 = kspan; j = 1; if (nPass != nTotal) { /* permutation for multivariate transform */ Permute_Multi_Label: do { do { k = kk + jc; do { /* swap Re [kk] <> Re [k2], Im [kk] <> Im [k2] */ ak = Re [kk]; Re [kk] = Re [k2]; Re [k2] = ak; bk = Im [kk]; Im [kk] = Im [k2]; Im [k2] = bk; kk += inc; k2 += inc; } while (kk < (k-1)); kk += ns - jc; k2 += ns - jc; } while (kk < (nt-1)); k2 = k2 - nt + kspan; kk = kk - nt + jc; } while (k2 < (ns-1)); do { do { k2 -= fftstate->Perm [j - 1]; j++; k2 = fftstate->Perm [j] + k2; } while (k2 > fftstate->Perm [j - 1]); j = 1; do { if (kk < (k2-1)) goto Permute_Multi_Label; kk += jc; k2 += kspan; } while (k2 < (ns-1)); } while (kk < (ns-1)); } else { /* permutation for single-variate transform (optional code) */ Permute_Single_Label: do { /* swap Re [kk] <> Re [k2], Im [kk] <> Im [k2] */ ak = Re [kk]; Re [kk] = Re [k2]; Re [k2] = ak; bk = Im [kk]; Im [kk] = Im [k2]; Im [k2] = bk; kk += inc; k2 += kspan; } while (k2 < (ns-1)); do { do { k2 -= fftstate->Perm [j - 1]; j++; k2 = fftstate->Perm [j] + k2; } while (k2 >= fftstate->Perm [j - 1]); j = 1; do { if (kk < k2) goto Permute_Single_Label; kk += inc; k2 += kspan; } while (k2 < (ns-1)); } while (kk < (ns-1)); } jc = k3; } if ((kt << 1) + 1 >= mfactor) return 0; ispan = fftstate->Perm [kt]; /* permutation for square-free factors of n */ j = mfactor - kt; fftstate->factor [j] = 1; do { fftstate->factor [j - 1] *= fftstate->factor [j]; j--; } while (j != kt); kt++; nn = fftstate->factor [kt - 1] - 1; if (nn > (int) max_perm) { return -1; } j = jj = 0; for (;;) { k = kt + 1; k2 = fftstate->factor [kt - 1]; kk = fftstate->factor [k - 1]; j++; if (j > nn) break; /* exit infinite loop */ jj += kk; while (jj >= k2) { jj -= k2; k2 = kk; k++; kk = fftstate->factor [k - 1]; jj += kk; } fftstate->Perm [j - 1] = jj; } /* determine the permutation cycles of length greater than 1 */ j = 0; for (;;) { do { j++; kk = fftstate->Perm [j - 1]; } while (kk < 0); if (kk != j) { do { k = kk; kk = fftstate->Perm [k - 1]; fftstate->Perm [k - 1] = -kk; } while (kk != j); k3 = kk; } else { fftstate->Perm [j - 1] = -j; if (j == nn) break; /* exit infinite loop */ } } max_factors *= inc; /* reorder a and b, following the permutation cycles */ for (;;) { j = k3 + 1; nt -= ispan; ii = nt - inc + 1; if (nt < 0) break; /* exit infinite loop */ do { do { j--; } while (fftstate->Perm [j - 1] < 0); jj = jc; do { kspan = jj; if (jj > max_factors) { kspan = max_factors; } jj -= kspan; k = fftstate->Perm [j - 1]; kk = jc * k + ii + jj; k1 = kk + kspan - 1; k2 = 0; do { k2++; Rtmp [k2 - 1] = Re [k1]; Itmp [k2 - 1] = Im [k1]; k1 -= inc; } while (k1 != (kk-1)); do { k1 = kk + kspan - 1; k2 = k1 - jc * (k + fftstate->Perm [k - 1]); k = -fftstate->Perm [k - 1]; do { Re [k1] = Re [k2]; Im [k1] = Im [k2]; k1 -= inc; k2 -= inc; } while (k1 != (kk-1)); kk = k2 + 1; } while (k != j); k1 = kk + kspan - 1; k2 = 0; do { k2++; Re [k1] = Rtmp [k2 - 1]; Im [k1] = Itmp [k2 - 1]; k1 -= inc; } while (k1 != (kk-1)); } while (jj); } while (j != 1); } return 0; /* exit point here */ } /* ---------------------- end-of-file (c source) ---------------------- */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/third_party/fft/fft.h0000664000175000017500000000372214475643423023670 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the ../../../LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /*--------------------------------*-C-*---------------------------------* * File: * fftn.h * ---------------------------------------------------------------------* * Re[]: real value array * Im[]: imaginary value array * nTotal: total number of complex values * nPass: number of elements involved in this pass of transform * nSpan: nspan/nPass = number of bytes to increment pointer * in Re[] and Im[] * isign: exponent: +1 = forward -1 = reverse * scaling: normalizing constant by which the final result is *divided* * scaling == -1, normalize by total dimension of the transform * scaling < -1, normalize by the square-root of the total dimension * * ---------------------------------------------------------------------- * See the comments in the code for correct usage! */ #ifndef MODULES_THIRD_PARTY_FFT_FFT_H_ #define MODULES_THIRD_PARTY_FFT_FFT_H_ #define FFT_MAXFFTSIZE 2048 #define FFT_NFACTOR 11 typedef struct { unsigned int SpaceAlloced; unsigned int MaxPermAlloced; double Tmp0[FFT_MAXFFTSIZE]; double Tmp1[FFT_MAXFFTSIZE]; double Tmp2[FFT_MAXFFTSIZE]; double Tmp3[FFT_MAXFFTSIZE]; int Perm[FFT_MAXFFTSIZE]; int factor[FFT_NFACTOR]; } FFTstr; /* double precision routine */ int WebRtcIsac_Fftns(unsigned int ndim, const int dims[], double Re[], double Im[], int isign, double scaling, FFTstr* fftstate); #endif /* MODULES_THIRD_PARTY_FFT_FFT_H_ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/modules/third_party/fft/meson.build0000664000175000017500000000035114475643423025075 0ustar00arunarunfft_sources = ['fft.c'] libfft = static_library('libfft', fft_sources, dependencies: common_deps, include_directories: webrtc_inc, cpp_args : common_cxxflags ) fft_dep = declare_dependency( link_with: libfft ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/0000775000175000017500000000000014475643423017736 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/BUILD.gn0000664000175000017500000010400414475643423021122 0ustar00arunarun# Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("//build/config/crypto.gni") import("//build/config/ui.gni") import("../webrtc.gni") if (is_android) { import("//build/config/android/config.gni") import("//build/config/android/rules.gni") } config("rtc_base_chromium_config") { defines = [ "NO_MAIN_THREAD_WRAPPING" ] } if (!rtc_build_ssl) { config("external_ssl_library") { assert(rtc_ssl_root != "", "You must specify rtc_ssl_root when rtc_build_ssl==0.") include_dirs = [ rtc_ssl_root ] } } rtc_source_set("protobuf_utils") { sources = [ "protobuf_utils.h" ] if (rtc_enable_protobuf) { public_configs = [ "//third_party/protobuf:protobuf_config" ] deps = [ "//third_party/protobuf:protobuf_lite" ] } } rtc_source_set("compile_assert_c") { sources = [ "compile_assert_c.h" ] } rtc_source_set("ignore_wundef") { sources = [ "ignore_wundef.h" ] } rtc_source_set("untyped_function") { sources = [ "untyped_function.h" ] deps = [ "system:assume" ] } rtc_source_set("robo_caller") { sources = [ "robo_caller.cc", "robo_caller.h", ] deps = [ ":untyped_function", "../api:function_view", "system:assume", "system:inline", ] } # The subset of rtc_base approved for use outside of libjingle. # TODO(bugs.webrtc.org/9838): Create small and focused build targets and remove # the old concept of rtc_base and rtc_base_approved. rtc_library("rtc_base_approved") { visibility = [ "*" ] deps = [ ":checks", ":rtc_task_queue", ":safe_compare", ":type_traits", "../api:array_view", "../api:scoped_refptr", "synchronization:mutex", "system:arch", "system:rtc_export", "system:unused", "third_party/base64", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] public_deps = [] # no-presubmit-check TODO(webrtc:8603) sources = [ "bind.h", "bit_buffer.cc", "bit_buffer.h", "buffer.h", "buffer_queue.cc", "buffer_queue.h", "byte_buffer.cc", "byte_buffer.h", "byte_order.h", "copy_on_write_buffer.cc", "copy_on_write_buffer.h", "event_tracer.cc", "event_tracer.h", "location.cc", "location.h", "message_buffer_reader.h", "numerics/histogram_percentile_counter.cc", "numerics/histogram_percentile_counter.h", "numerics/mod_ops.h", "numerics/moving_max_counter.h", "numerics/sample_counter.cc", "numerics/sample_counter.h", "one_time_event.h", "race_checker.cc", "race_checker.h", "random.cc", "random.h", "rate_statistics.cc", "rate_statistics.h", "rate_tracker.cc", "rate_tracker.h", "swap_queue.h", "timestamp_aligner.cc", "timestamp_aligner.h", "trace_event.h", "zero_memory.cc", "zero_memory.h", ] if (is_win) { sources += [ "win/windows_version.cc", "win/windows_version.h", ] data_deps = [ "//build/win:runtime_libs" ] } if (is_nacl) { public_deps += # no-presubmit-check TODO(webrtc:8603) [ "//native_client_sdk/src/libraries/nacl_io" ] } if (is_android) { libs = [ "log" ] } public_deps += [ # no-presubmit-check TODO(webrtc:8603) ":atomicops", ":criticalsection", ":logging", ":macromagic", ":platform_thread", ":platform_thread_types", ":refcount", ":rtc_event", ":safe_conversions", ":stringutils", ":thread_checker", ":timeutils", "synchronization:sequence_checker", ] } rtc_source_set("macromagic") { # TODO(bugs.webrtc.org/9606): This should not be public. visibility = [ "*" ] sources = [ "arraysize.h", "constructor_magic.h", "format_macros.h", "thread_annotations.h", ] deps = [ "system:arch" ] } rtc_library("platform_thread_types") { sources = [ "platform_thread_types.cc", "platform_thread_types.h", ] deps = [ ":macromagic" ] } rtc_source_set("refcount") { visibility = [ "*" ] sources = [ "ref_count.h", "ref_counted_object.h", "ref_counter.h", ] deps = [ ":macromagic" ] } rtc_library("criticalsection") { sources = [ "deprecated/recursive_critical_section.cc", "deprecated/recursive_critical_section.h", ] deps = [ ":atomicops", ":checks", ":macromagic", ":platform_thread_types", "synchronization:yield", "system:unused", ] } rtc_library("platform_thread") { visibility = [ ":rtc_base_approved", ":rtc_task_queue_libevent", ":rtc_task_queue_stdlib", ":rtc_task_queue_win", "synchronization:mutex", "synchronization:sequence_checker", ] sources = [ "platform_thread.cc", "platform_thread.h", ] deps = [ ":atomicops", ":checks", ":macromagic", ":platform_thread_types", ":rtc_event", ":thread_checker", ":timeutils", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } rtc_library("rtc_event") { if (build_with_chromium) { sources = [ "../../webrtc_overrides/rtc_base/event.cc", "../../webrtc_overrides/rtc_base/event.h", ] deps = [ ":checks", "system:rtc_export", # Only Chromium's rtc::Event use RTC_EXPORT. "//base", # Dependency on chromium's waitable_event. ] } else { sources = [ "event.cc", "event.h", ] deps = [ ":checks", "synchronization:yield_policy", "system:warn_current_thread_is_deadlocked", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } } rtc_library("logging") { visibility = [ "*" ] libs = [] deps = [ ":checks", ":criticalsection", ":macromagic", ":platform_thread_types", ":stringutils", ":timeutils", "synchronization:mutex", ] absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers", "//third_party/abseil-cpp/absl/meta:type_traits", "//third_party/abseil-cpp/absl/strings", ] if (build_with_chromium) { # Dependency on chromium's logging (in //base). deps += [ "//base" ] sources = [ "../../webrtc_overrides/rtc_base/logging.cc", "../../webrtc_overrides/rtc_base/logging.h", ] } else { configs += [ "..:no_exit_time_destructors", "..:no_global_constructors", ] sources = [ "logging.cc", "logging.h", ] deps += [ "system:inline" ] if (is_mac) { frameworks = [ "Foundation.framework" ] } # logging.h needs the deprecation header while downstream projects are # removing code that depends on logging implementation details. deps += [ ":deprecation" ] if (is_android) { libs += [ "log" ] } } } rtc_source_set("thread_checker") { sources = [ "thread_checker.h" ] deps = [ ":deprecation", "synchronization:sequence_checker", ] } rtc_source_set("atomicops") { sources = [ "atomic_ops.h" ] } rtc_library("checks") { # TODO(bugs.webrtc.org/9607): This should not be public. visibility = [ "*" ] libs = [] sources = [ "checks.cc", "checks.h", ] deps = [ ":safe_compare", "system:inline", "system:rtc_export", ] absl_deps = [ "//third_party/abseil-cpp/absl/meta:type_traits", "//third_party/abseil-cpp/absl/strings", ] if (is_android) { libs += [ "log" ] } } rtc_library("rate_limiter") { sources = [ "rate_limiter.cc", "rate_limiter.h", ] deps = [ ":rtc_base_approved", "../system_wrappers", "synchronization:mutex", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_source_set("sanitizer") { sources = [ "sanitizer.h" ] absl_deps = [ "//third_party/abseil-cpp/absl/meta:type_traits" ] } rtc_source_set("bounded_inline_vector") { public = [ "bounded_inline_vector.h" ] sources = [ "bounded_inline_vector_impl.h" ] deps = [ ":checks" ] } rtc_source_set("divide_round") { sources = [ "numerics/divide_round.h" ] deps = [ ":checks", ":safe_compare", ] } rtc_source_set("safe_compare") { sources = [ "numerics/safe_compare.h" ] deps = [ ":type_traits" ] } rtc_source_set("safe_minmax") { sources = [ "numerics/safe_minmax.h" ] deps = [ ":checks", ":safe_compare", ":type_traits", ] } rtc_source_set("safe_conversions") { sources = [ "numerics/safe_conversions.h", "numerics/safe_conversions_impl.h", ] deps = [ ":checks" ] } rtc_library("timeutils") { visibility = [ "*" ] sources = [ "time_utils.cc", "time_utils.h", ] deps = [ ":checks", ":safe_conversions", ":stringutils", "system:rtc_export", ] libs = [] if (is_win) { libs += [ "winmm.lib" ] } } rtc_library("stringutils") { sources = [ "string_encode.cc", "string_encode.h", "string_to_number.cc", "string_to_number.h", "string_utils.cc", "string_utils.h", "strings/string_builder.cc", "strings/string_builder.h", "strings/string_format.cc", "strings/string_format.h", ] deps = [ ":checks", ":macromagic", ":safe_minmax", "../api:array_view", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] } rtc_library("audio_format_to_string") { sources = [ "strings/audio_format_to_string.cc", "strings/audio_format_to_string.h", ] deps = [ ":stringutils", "../api/audio_codecs:audio_codecs_api", ] } rtc_source_set("type_traits") { sources = [ "type_traits.h" ] } rtc_source_set("deprecation") { sources = [ "deprecation.h" ] } rtc_library("rtc_task_queue") { visibility = [ "*" ] sources = [ "task_queue.cc", "task_queue.h", ] deps = [ ":macromagic", "../api/task_queue", "system:rtc_export", "task_utils:to_queued_task", ] absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] } rtc_source_set("rtc_operations_chain") { visibility = [ "*" ] sources = [ "operations_chain.cc", "operations_chain.h", ] deps = [ ":checks", ":macromagic", ":refcount", "../api:scoped_refptr", "synchronization:sequence_checker", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } if (rtc_enable_libevent) { rtc_library("rtc_task_queue_libevent") { visibility = [ "../api/task_queue:default_task_queue_factory" ] sources = [ "task_queue_libevent.cc", "task_queue_libevent.h", ] deps = [ ":checks", ":criticalsection", ":logging", ":macromagic", ":platform_thread", ":platform_thread_types", ":safe_conversions", ":timeutils", "../api/task_queue", "synchronization:mutex", ] absl_deps = [ "//third_party/abseil-cpp/absl/container:inlined_vector", "//third_party/abseil-cpp/absl/strings", ] if (rtc_build_libevent) { deps += [ "//base/third_party/libevent" ] } } } if (is_mac || is_ios) { rtc_library("rtc_task_queue_gcd") { visibility = [ "../api/task_queue:default_task_queue_factory" ] sources = [ "task_queue_gcd.cc", "task_queue_gcd.h", ] deps = [ ":checks", ":logging", "../api/task_queue", "synchronization:mutex", "system:gcd_helpers", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } } if (is_win) { rtc_library("rtc_task_queue_win") { visibility = [ "../api/task_queue:default_task_queue_factory" ] sources = [ "task_queue_win.cc", "task_queue_win.h", ] deps = [ ":checks", ":criticalsection", ":logging", ":macromagic", ":platform_thread", ":rtc_event", ":safe_conversions", ":timeutils", "../api/task_queue", "synchronization:mutex", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } } rtc_library("rtc_task_queue_stdlib") { sources = [ "task_queue_stdlib.cc", "task_queue_stdlib.h", ] deps = [ ":checks", ":criticalsection", ":logging", ":macromagic", ":platform_thread", ":rtc_event", ":safe_conversions", ":timeutils", "../api/task_queue", "synchronization:mutex", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } rtc_library("weak_ptr") { sources = [ "weak_ptr.cc", "weak_ptr.h", ] deps = [ ":refcount", "../api:scoped_refptr", "synchronization:sequence_checker", ] } rtc_library("rtc_numerics") { sources = [ "numerics/event_based_exponential_moving_average.cc", "numerics/event_based_exponential_moving_average.h", "numerics/exp_filter.cc", "numerics/exp_filter.h", "numerics/math_utils.h", "numerics/moving_average.cc", "numerics/moving_average.h", "numerics/moving_median_filter.h", "numerics/percentile_filter.h", "numerics/running_statistics.h", "numerics/sequence_number_util.h", ] deps = [ ":checks", ":rtc_base_approved", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("rtc_stats_counters") { sources = [ "numerics/event_rate_counter.cc", "numerics/event_rate_counter.h", "numerics/sample_stats.cc", "numerics/sample_stats.h", ] deps = [ "../api/numerics", "../api/units:data_rate", "../api/units:time_delta", "../api/units:timestamp", ] absl_deps = [] } config("rtc_json_suppressions") { if (!is_win || is_clang) { cflags_cc = [ # TODO(bugs.webrtc.org/10770): Update jsoncpp API usage and remove # -Wno-deprecated-declarations. "-Wno-deprecated-declarations", # TODO(bugs.webrtc.org/10814): Remove -Wno-undef as soon as it get # removed upstream. "-Wno-undef", ] } } rtc_library("rtc_json") { public_configs = [ ":rtc_json_suppressions" ] poisonous = [ "rtc_json" ] defines = [] sources = [ "strings/json.cc", "strings/json.h", ] deps = [ ":stringutils" ] all_dependent_configs = [ "//third_party/jsoncpp:jsoncpp_config" ] if (rtc_build_json) { public_deps = # no-presubmit-check TODO(webrtc:8603) [ "//third_party/jsoncpp" ] } else { include_dirs = [ "$rtc_jsoncpp_root" ] # When defined changes the include path for json.h to where it is # expected to be when building json outside of the standalone build. defines += [ "WEBRTC_EXTERNAL_JSON" ] } } rtc_source_set("net_helpers") { # TODO(bugs.webrtc.org/9987): This build target will soon contain # the following files: # sources = [ # "net_helpers.cc", # "net_helpers.h", # ] } rtc_source_set("async_resolver_interface") { visibility = [ "*" ] # TODO(bugs.webrtc.org/9987): This build target will soon contain # the following files: # sources = [ # "async_resolver_interface.cc", # "async_resolver_interface.h", # ] } rtc_source_set("ip_address") { visibility = [ "*" ] # TODO(bugs.webrtc.org/9987): This build target will soon contain # the following files: # sources = [ # "ip_address.cc", # "ip_address.h", # ] } rtc_source_set("socket_address") { visibility = [ "*" ] # TODO(bugs.webrtc.org/9987): This build target will soon contain # the following files: # sources = [ # "socket_address.cc", # "socket_address.h", # ] } rtc_source_set("null_socket_server") { # TODO(bugs.webrtc.org/9987): This build target will soon contain # the following files: # sources = [ # "null_socket_server.cc", # "null_socket_server.h", # ] } rtc_source_set("socket_server") { # TODO(bugs.webrtc.org/9987): This build target will soon contain # the following files: # sources = [ # "socket_server.h", # ] } rtc_source_set("threading") { visibility = [ "*" ] # TODO(bugs.webrtc.org/9987): This build target will soon contain # the following files: # sources = [ # "asyncresolver.cc", # "asyncresolver.h", # "defaultsocketserver.cc", # "defaultsocketserver.h", # "message_handler.cc", # "message_handler.h", # "network_monitor.cc", # "network_monitor.h", # "network_monitor_factory.cc", # "network_monitor_factory.h", # "physical_socket_server.cc", # "physical_socket_server.h", # "signal_thread.cc", # "signal_thread.h", # "thread.cc", # "thread.h", # ] } rtc_source_set("socket_factory") { # TODO(bugs.webrtc.org/9987): This build target will soon contain # the following files: # sources = [ # "socket_factory.h", # ] } rtc_source_set("async_socket") { # TODO(bugs.webrtc.org/9987): This build target will soon contain # the following files: # sources = [ # "async_socket.cc", # "async_socket.h", # ] } rtc_source_set("socket") { # TODO(bugs.webrtc.org/9987): This build target will soon contain # the following files: # sources = [ # "socket.cc", # "socket.h", # ] } rtc_source_set("network_constants") { # TODO(bugs.webrtc.org/9987): This build target will soon contain # the following files: # sources = [ # "network_constants.h", # ] } if (is_android) { rtc_source_set("ifaddrs_android") { # TODO(bugs.webrtc.org/9987): This build target will soon contain # the following files: # sources = [ # "ifaddrs_android.cc", # "ifaddrs_android.h", # ] } } if (is_win) { rtc_source_set("win32") { sources = [ "win32.cc", "win32.h", "win32_window.cc", "win32_window.h", ] deps = [ ":checks", ":macromagic", ":rtc_base_approved", ] libs = [ "crypt32.lib", "iphlpapi.lib", "secur32.lib", ] defines = [ "_CRT_NONSTDC_NO_DEPRECATE" ] } } rtc_library("rtc_base") { visibility = [ "*" ] cflags = [] cflags_cc = [] libs = [] defines = [] deps = [ ":checks", ":deprecation", ":rtc_task_queue", ":stringutils", "../api:array_view", "../api:function_view", "../api:scoped_refptr", "../api/numerics", "../api/task_queue", "../system_wrappers:field_trial", "network:sent_packet", "synchronization:mutex", "synchronization:sequence_checker", "system:file_wrapper", "system:inline", "system:rtc_export", "task_utils:pending_task_safety_flag", "task_utils:repeating_task", "task_utils:to_queued_task", "third_party/base64", "third_party/sigslot", ] absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container", "//third_party/abseil-cpp/absl/container:flat_hash_map", "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] public_deps = [ ":rtc_base_approved" ] # no-presubmit-check TODO(webrtc:8603) public_configs = [] sources = [ "async_invoker.cc", "async_invoker.h", "async_invoker_inl.h", "async_packet_socket.cc", "async_packet_socket.h", "async_resolver_interface.cc", "async_resolver_interface.h", "async_socket.cc", "async_socket.h", "async_tcp_socket.cc", "async_tcp_socket.h", "async_udp_socket.cc", "async_udp_socket.h", "crc32.cc", "crc32.h", "crypt_string.cc", "crypt_string.h", "data_rate_limiter.cc", "data_rate_limiter.h", "deprecated/signal_thread.cc", "deprecated/signal_thread.h", "dscp.h", "file_rotating_stream.cc", "file_rotating_stream.h", "helpers.cc", "helpers.h", "http_common.cc", "http_common.h", "ip_address.cc", "ip_address.h", "keep_ref_until_done.h", "mdns_responder_interface.h", "message_digest.cc", "message_digest.h", "message_handler.cc", "message_handler.h", "net_helper.cc", "net_helper.h", "net_helpers.cc", "net_helpers.h", "network.cc", "network.h", "network_constants.cc", "network_constants.h", "network_monitor.cc", "network_monitor.h", "network_monitor_factory.cc", "network_monitor_factory.h", "network_route.cc", "network_route.h", "null_socket_server.cc", "null_socket_server.h", "openssl.h", "openssl_adapter.cc", "openssl_adapter.h", "openssl_certificate.cc", "openssl_certificate.h", "openssl_digest.cc", "openssl_digest.h", "openssl_identity.cc", "openssl_identity.h", "openssl_session_cache.cc", "openssl_session_cache.h", "openssl_stream_adapter.cc", "openssl_stream_adapter.h", "openssl_utility.cc", "openssl_utility.h", "physical_socket_server.cc", "physical_socket_server.h", "proxy_info.cc", "proxy_info.h", "rtc_certificate.cc", "rtc_certificate.h", "rtc_certificate_generator.cc", "rtc_certificate_generator.h", "signal_thread.h", "sigslot_repeater.h", "socket.cc", "socket.h", "socket_adapters.cc", "socket_adapters.h", "socket_address.cc", "socket_address.h", "socket_address_pair.cc", "socket_address_pair.h", "socket_factory.h", "socket_server.h", "ssl_adapter.cc", "ssl_adapter.h", "ssl_certificate.cc", "ssl_certificate.h", "ssl_fingerprint.cc", "ssl_fingerprint.h", "ssl_identity.cc", "ssl_identity.h", "ssl_stream_adapter.cc", "ssl_stream_adapter.h", "stream.cc", "stream.h", "thread.cc", "thread.h", "thread_message.h", "unique_id_generator.cc", "unique_id_generator.h", ] if (build_with_chromium) { include_dirs = [ "../../boringssl/src/include" ] public_configs += [ ":rtc_base_chromium_config" ] } else { sources += [ "callback.h", "log_sinks.cc", "log_sinks.h", "rolling_accumulator.h", "ssl_roots.h", ] deps += [ ":rtc_numerics" ] if (is_win) { sources += [ "win32_socket_init.h" ] if (current_os != "winuwp") { sources += [ "win32_socket_server.cc", "win32_socket_server.h", ] } } } # !build_with_chromium if (rtc_build_ssl) { deps += [ "//third_party/boringssl" ] } else { configs += [ ":external_ssl_library" ] } if (is_android) { sources += [ "ifaddrs_android.cc", "ifaddrs_android.h", ] libs += [ "log", "GLESv2", ] } if (is_ios || is_mac) { sources += [ "mac_ifaddrs_converter.cc" ] deps += [ "system:cocoa_threading" ] } if (is_linux || is_chromeos) { libs += [ "dl", "rt", ] } if (is_ios) { frameworks = [ "CFNetwork.framework", "Foundation.framework", "Security.framework", "SystemConfiguration.framework", "UIKit.framework", ] } if (is_win) { deps += [ ":win32" ] } if (is_posix || is_fuchsia) { sources += [ "ifaddrs_converter.cc", "ifaddrs_converter.h", ] } if (is_nacl) { public_deps += # no-presubmit-check TODO(webrtc:8603) [ "//native_client_sdk/src/libraries/nacl_io" ] defines += [ "timezone=_timezone" ] sources -= [ "ifaddrs_converter.cc" ] } } rtc_source_set("gtest_prod") { sources = [ "gtest_prod_util.h" ] } rtc_library("gunit_helpers") { testonly = true sources = [ "gunit.cc", "gunit.h", ] deps = [ ":logging", ":rtc_base", ":rtc_base_tests_utils", ":stringutils", "../test:test_support", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } rtc_library("testclient") { testonly = true sources = [ "test_client.cc", "test_client.h", ] deps = [ ":criticalsection", ":gunit_helpers", ":rtc_base", ":rtc_base_tests_utils", ":timeutils", "synchronization:mutex", ] } rtc_library("robo_caller_unittests") { testonly = true sources = [ "robo_caller_unittest.cc" ] deps = [ ":gunit_helpers", ":robo_caller", ":rtc_base", "../api:function_view", "../test:test_support", ] } rtc_library("rtc_base_tests_utils") { testonly = true sources = [ "cpu_time.cc", "cpu_time.h", "fake_clock.cc", "fake_clock.h", "fake_mdns_responder.h", "fake_network.h", "fake_ssl_identity.cc", "fake_ssl_identity.h", "firewall_socket_server.cc", "firewall_socket_server.h", "memory_stream.cc", "memory_stream.h", "memory_usage.cc", "memory_usage.h", "nat_server.cc", "nat_server.h", "nat_socket_factory.cc", "nat_socket_factory.h", "nat_types.cc", "nat_types.h", "proxy_server.cc", "proxy_server.h", "server_socket_adapters.cc", "server_socket_adapters.h", "sigslot_tester.h", "socket_stream.cc", "socket_stream.h", "test_base64.h", "test_certificate_verifier.h", "test_echo_server.cc", "test_echo_server.h", "test_utils.cc", "test_utils.h", "virtual_socket_server.cc", "virtual_socket_server.h", ] deps = [ ":checks", ":rtc_base", "../api/units:time_delta", "../api/units:timestamp", "memory:fifo_buffer", "synchronization:mutex", "third_party/sigslot", ] absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container", "//third_party/abseil-cpp/absl/memory", ] } rtc_library("task_queue_for_test") { testonly = true sources = [ "task_queue_for_test.cc", "task_queue_for_test.h", ] deps = [ ":checks", ":rtc_base_approved", ":rtc_event", ":rtc_task_queue", "../api/task_queue", "../api/task_queue:default_task_queue_factory", "task_utils:to_queued_task", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } if (rtc_include_tests) { rtc_library("sigslot_unittest") { testonly = true sources = [ "sigslot_unittest.cc" ] deps = [ ":gunit_helpers", ":rtc_base", ":rtc_base_tests_utils", "../test:test_support", "synchronization:mutex", "third_party/sigslot", ] } rtc_library("untyped_function_unittest") { testonly = true sources = [ "untyped_function_unittest.cc" ] deps = [ ":untyped_function", "../test:test_support", ] } rtc_library("rtc_base_nonparallel_tests") { testonly = true sources = [ "cpu_time_unittest.cc", "file_rotating_stream_unittest.cc", "null_socket_server_unittest.cc", "physical_socket_server_unittest.cc", "socket_address_unittest.cc", "socket_unittest.cc", "socket_unittest.h", ] deps = [ ":checks", ":gunit_helpers", ":rtc_base", ":rtc_base_tests_utils", ":testclient", "../system_wrappers", "../test:fileutils", "../test:test_main", "../test:test_support", "third_party/sigslot", "//testing/gtest", ] absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] if (is_win) { sources += [ "win32_socket_server_unittest.cc" ] } } rtc_library("rtc_base_approved_unittests") { testonly = true sources = [ "atomic_ops_unittest.cc", "base64_unittest.cc", "bind_unittest.cc", "bit_buffer_unittest.cc", "bounded_inline_vector_unittest.cc", "buffer_queue_unittest.cc", "buffer_unittest.cc", "byte_buffer_unittest.cc", "byte_order_unittest.cc", "checks_unittest.cc", "copy_on_write_buffer_unittest.cc", "deprecated/recursive_critical_section_unittest.cc", "event_tracer_unittest.cc", "event_unittest.cc", "logging_unittest.cc", "numerics/divide_round_unittest.cc", "numerics/histogram_percentile_counter_unittest.cc", "numerics/mod_ops_unittest.cc", "numerics/moving_max_counter_unittest.cc", "numerics/safe_compare_unittest.cc", "numerics/safe_minmax_unittest.cc", "numerics/sample_counter_unittest.cc", "one_time_event_unittest.cc", "platform_thread_unittest.cc", "random_unittest.cc", "rate_limiter_unittest.cc", "rate_statistics_unittest.cc", "rate_tracker_unittest.cc", "ref_counted_object_unittest.cc", "sanitizer_unittest.cc", "string_encode_unittest.cc", "string_to_number_unittest.cc", "string_utils_unittest.cc", "strings/string_builder_unittest.cc", "strings/string_format_unittest.cc", "swap_queue_unittest.cc", "thread_annotations_unittest.cc", "thread_checker_unittest.cc", "time_utils_unittest.cc", "timestamp_aligner_unittest.cc", "virtual_socket_unittest.cc", "zero_memory_unittest.cc", ] if (is_win) { sources += [ "win/windows_version_unittest.cc" ] } deps = [ ":bounded_inline_vector", ":checks", ":divide_round", ":gunit_helpers", ":rate_limiter", ":rtc_base", ":rtc_base_approved", ":rtc_base_tests_utils", ":rtc_numerics", ":rtc_task_queue", ":safe_compare", ":safe_minmax", ":sanitizer", ":stringutils", ":testclient", "../api:array_view", "../api:scoped_refptr", "../api/numerics", "../api/units:time_delta", "../system_wrappers", "../test:fileutils", "../test:test_main", "../test:test_support", "memory:unittests", "synchronization:mutex", "task_utils:to_queued_task", "third_party/base64", "third_party/sigslot", ] absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers", "//third_party/abseil-cpp/absl/memory", ] } rtc_library("rtc_task_queue_unittests") { testonly = true sources = [ "task_queue_unittest.cc" ] deps = [ ":gunit_helpers", ":rtc_base_approved", ":rtc_base_tests_utils", ":rtc_task_queue", ":task_queue_for_test", "../test:test_main", "../test:test_support", ] absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] } rtc_library("rtc_operations_chain_unittests") { testonly = true sources = [ "operations_chain_unittest.cc" ] deps = [ ":gunit_helpers", ":rtc_base", ":rtc_base_approved", ":rtc_event", ":rtc_operations_chain", "../test:test_support", ] } rtc_library("weak_ptr_unittests") { testonly = true sources = [ "weak_ptr_unittest.cc" ] deps = [ ":gunit_helpers", ":rtc_base_approved", ":rtc_base_tests_utils", ":rtc_event", ":task_queue_for_test", ":weak_ptr", "../test:test_main", "../test:test_support", ] } rtc_library("rtc_numerics_unittests") { testonly = true sources = [ "numerics/event_based_exponential_moving_average_unittest.cc", "numerics/exp_filter_unittest.cc", "numerics/moving_average_unittest.cc", "numerics/moving_median_filter_unittest.cc", "numerics/percentile_filter_unittest.cc", "numerics/running_statistics_unittest.cc", "numerics/sequence_number_util_unittest.cc", ] deps = [ ":rtc_base_approved", ":rtc_numerics", "../test:test_main", "../test:test_support", ] absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container" ] } rtc_library("rtc_json_unittests") { testonly = true sources = [ "strings/json_unittest.cc" ] deps = [ ":gunit_helpers", ":rtc_base_tests_utils", ":rtc_json", "../test:test_main", "../test:test_support", ] } rtc_library("rtc_base_unittests") { testonly = true defines = [] sources = [ "callback_unittest.cc", "crc32_unittest.cc", "data_rate_limiter_unittest.cc", "deprecated/signal_thread_unittest.cc", "fake_clock_unittest.cc", "helpers_unittest.cc", "ip_address_unittest.cc", "memory_usage_unittest.cc", "message_digest_unittest.cc", "nat_unittest.cc", "network_route_unittest.cc", "network_unittest.cc", "proxy_unittest.cc", "rolling_accumulator_unittest.cc", "rtc_certificate_generator_unittest.cc", "rtc_certificate_unittest.cc", "sigslot_tester_unittest.cc", "test_client_unittest.cc", "thread_unittest.cc", "unique_id_generator_unittest.cc", ] deps = [ ":checks", ":gunit_helpers", ":rtc_base_tests_utils", ":stringutils", ":testclient", "../api:array_view", "../api/task_queue", "../api/task_queue:task_queue_test", "../test:field_trial", "../test:fileutils", "../test:rtc_expect_death", "../test:test_main", "../test:test_support", "memory:fifo_buffer", "synchronization:mutex", "synchronization:synchronization_unittests", "task_utils:pending_task_safety_flag", "task_utils:to_queued_task", "third_party/sigslot", ] if (is_win) { sources += [ "win32_unittest.cc", "win32_window_unittest.cc", ] deps += [ ":win32" ] } if (is_posix || is_fuchsia) { sources += [ "openssl_adapter_unittest.cc", "openssl_session_cache_unittest.cc", "openssl_utility_unittest.cc", "ssl_adapter_unittest.cc", "ssl_identity_unittest.cc", "ssl_stream_adapter_unittest.cc", ] } absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container", "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] public_deps = [ ":rtc_base" ] # no-presubmit-check TODO(webrtc:8603) if (build_with_chromium) { include_dirs = [ "../../boringssl/src/include" ] } if (rtc_build_ssl) { deps += [ "//third_party/boringssl" ] } else { configs += [ ":external_ssl_library" ] } } } if (is_android) { rtc_android_library("base_java") { visibility = [ "*" ] sources = [ "java/src/org/webrtc/ContextUtils.java", "java/src/org/webrtc/Loggable.java", "java/src/org/webrtc/Logging.java", "java/src/org/webrtc/Size.java", "java/src/org/webrtc/ThreadUtils.java", ] deps = [ "//third_party/android_deps:com_android_support_support_annotations_java", ] } java_cpp_enum("network_monitor_enums") { sources = [ "network_monitor.h" ] visibility = [ "*" ] } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/arraysize.h0000664000175000017500000000223514475643423022122 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_ARRAYSIZE_H_ #define RTC_BASE_ARRAYSIZE_H_ #include // This file defines the arraysize() macro and is derived from Chromium's // base/macros.h. // The arraysize(arr) macro returns the # of elements in an array arr. // The expression is a compile-time constant, and therefore can be // used in defining new arrays, for example. If you use arraysize on // a pointer by mistake, you will get a compile-time error. // This template function declaration is used in defining arraysize. // Note that the function doesn't need an implementation, as we only // use its type. template char (&ArraySizeHelper(T (&array)[N]))[N]; #define arraysize(array) (sizeof(ArraySizeHelper(array))) #endif // RTC_BASE_ARRAYSIZE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/atomic_ops.h0000664000175000017500000000542114475643423022246 0ustar00arunarun/* * Copyright 2011 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_ATOMIC_OPS_H_ #define RTC_BASE_ATOMIC_OPS_H_ #if defined(WEBRTC_WIN) // clang-format off // clang formating would change include order. // Include winsock2.h before including to maintain consistency with // win32.h. To include win32.h directly, it must be broken out into its own // build target. #include #include // clang-format on #endif // defined(WEBRTC_WIN) namespace rtc { class AtomicOps { public: #if defined(WEBRTC_WIN) // Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64. static int Increment(volatile int* i) { return ::InterlockedIncrement(reinterpret_cast(i)); } static int Decrement(volatile int* i) { return ::InterlockedDecrement(reinterpret_cast(i)); } static int AcquireLoad(volatile const int* i) { return *i; } static void ReleaseStore(volatile int* i, int value) { *i = value; } static int CompareAndSwap(volatile int* i, int old_value, int new_value) { return ::InterlockedCompareExchange(reinterpret_cast(i), new_value, old_value); } // Pointer variants. template static T* AcquireLoadPtr(T* volatile* ptr) { return *ptr; } template static T* CompareAndSwapPtr(T* volatile* ptr, T* old_value, T* new_value) { return static_cast(::InterlockedCompareExchangePointer( reinterpret_cast(ptr), new_value, old_value)); } #else static int Increment(volatile int* i) { return __sync_add_and_fetch(i, 1); } static int Decrement(volatile int* i) { return __sync_sub_and_fetch(i, 1); } static int AcquireLoad(volatile const int* i) { return __atomic_load_n(i, __ATOMIC_ACQUIRE); } static void ReleaseStore(volatile int* i, int value) { __atomic_store_n(i, value, __ATOMIC_RELEASE); } static int CompareAndSwap(volatile int* i, int old_value, int new_value) { return __sync_val_compare_and_swap(i, old_value, new_value); } // Pointer variants. template static T* AcquireLoadPtr(T* volatile* ptr) { return __atomic_load_n(ptr, __ATOMIC_ACQUIRE); } template static T* CompareAndSwapPtr(T* volatile* ptr, T* old_value, T* new_value) { return __sync_val_compare_and_swap(ptr, old_value, new_value); } #endif }; } // namespace rtc #endif // RTC_BASE_ATOMIC_OPS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/buffer.h0000664000175000017500000003463314475643423021371 0ustar00arunarun/* * Copyright 2004 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_BUFFER_H_ #define RTC_BASE_BUFFER_H_ #include #include #include #include #include #include #include "api/array_view.h" #include "rtc_base/checks.h" #include "rtc_base/type_traits.h" #include "rtc_base/zero_memory.h" namespace rtc { namespace internal { // (Internal; please don't use outside this file.) Determines if elements of // type U are compatible with a BufferT. For most types, we just ignore // top-level const and forbid top-level volatile and require T and U to be // otherwise equal, but all byte-sized integers (notably char, int8_t, and // uint8_t) are compatible with each other. (Note: We aim to get rid of this // behavior, and treat all types the same.) template struct BufferCompat { static constexpr bool value = !std::is_volatile::value && ((std::is_integral::value && sizeof(T) == 1) ? (std::is_integral::value && sizeof(U) == 1) : (std::is_same::type>::value)); }; } // namespace internal // Basic buffer class, can be grown and shrunk dynamically. // Unlike std::string/vector, does not initialize data when increasing size. // If "ZeroOnFree" is true, any memory is explicitly cleared before releasing. // The type alias "ZeroOnFreeBuffer" below should be used instead of setting // "ZeroOnFree" in the template manually to "true". template class BufferT { // We want T's destructor and default constructor to be trivial, i.e. perform // no action, so that we don't have to touch the memory we allocate and // deallocate. And we want T to be trivially copyable, so that we can copy T // instances with std::memcpy. This is precisely the definition of a trivial // type. static_assert(std::is_trivial::value, "T must be a trivial type."); // This class relies heavily on being able to mutate its data. static_assert(!std::is_const::value, "T may not be const"); public: using value_type = T; using const_iterator = const T*; // An empty BufferT. BufferT() : size_(0), capacity_(0), data_(nullptr) { RTC_DCHECK(IsConsistent()); } // Disable copy construction and copy assignment, since copying a buffer is // expensive enough that we want to force the user to be explicit about it. BufferT(const BufferT&) = delete; BufferT& operator=(const BufferT&) = delete; BufferT(BufferT&& buf) : size_(buf.size()), capacity_(buf.capacity()), data_(std::move(buf.data_)) { RTC_DCHECK(IsConsistent()); buf.OnMovedFrom(); } // Construct a buffer with the specified number of uninitialized elements. explicit BufferT(size_t size) : BufferT(size, size) {} BufferT(size_t size, size_t capacity) : size_(size), capacity_(std::max(size, capacity)), data_(capacity_ > 0 ? new T[capacity_] : nullptr) { RTC_DCHECK(IsConsistent()); } // Construct a buffer and copy the specified number of elements into it. template ::value>::type* = nullptr> BufferT(const U* data, size_t size) : BufferT(data, size, size) {} template ::value>::type* = nullptr> BufferT(U* data, size_t size, size_t capacity) : BufferT(size, capacity) { static_assert(sizeof(T) == sizeof(U), ""); std::memcpy(data_.get(), data, size * sizeof(U)); } // Construct a buffer from the contents of an array. template ::value>::type* = nullptr> BufferT(U (&array)[N]) : BufferT(array, N) {} ~BufferT() { MaybeZeroCompleteBuffer(); } // Get a pointer to the data. Just .data() will give you a (const) T*, but if // T is a byte-sized integer, you may also use .data() for any other // byte-sized integer U. template ::value>::type* = nullptr> const U* data() const { RTC_DCHECK(IsConsistent()); return reinterpret_cast(data_.get()); } template ::value>::type* = nullptr> U* data() { RTC_DCHECK(IsConsistent()); return reinterpret_cast(data_.get()); } bool empty() const { RTC_DCHECK(IsConsistent()); return size_ == 0; } size_t size() const { RTC_DCHECK(IsConsistent()); return size_; } size_t capacity() const { RTC_DCHECK(IsConsistent()); return capacity_; } BufferT& operator=(BufferT&& buf) { RTC_DCHECK(buf.IsConsistent()); MaybeZeroCompleteBuffer(); size_ = buf.size_; capacity_ = buf.capacity_; using std::swap; swap(data_, buf.data_); buf.data_.reset(); buf.OnMovedFrom(); return *this; } bool operator==(const BufferT& buf) const { RTC_DCHECK(IsConsistent()); if (size_ != buf.size_) { return false; } if (std::is_integral::value) { // Optimization. return std::memcmp(data_.get(), buf.data_.get(), size_ * sizeof(T)) == 0; } for (size_t i = 0; i < size_; ++i) { if (data_[i] != buf.data_[i]) { return false; } } return true; } bool operator!=(const BufferT& buf) const { return !(*this == buf); } T& operator[](size_t index) { RTC_DCHECK_LT(index, size_); return data()[index]; } T operator[](size_t index) const { RTC_DCHECK_LT(index, size_); return data()[index]; } T* begin() { return data(); } T* end() { return data() + size(); } const T* begin() const { return data(); } const T* end() const { return data() + size(); } const T* cbegin() const { return data(); } const T* cend() const { return data() + size(); } // The SetData functions replace the contents of the buffer. They accept the // same input types as the constructors. template ::value>::type* = nullptr> void SetData(const U* data, size_t size) { RTC_DCHECK(IsConsistent()); const size_t old_size = size_; size_ = 0; AppendData(data, size); if (ZeroOnFree && size_ < old_size) { ZeroTrailingData(old_size - size_); } } template ::value>::type* = nullptr> void SetData(const U (&array)[N]) { SetData(array, N); } template ::value>::type* = nullptr> void SetData(const W& w) { SetData(w.data(), w.size()); } // Replaces the data in the buffer with at most |max_elements| of data, using // the function |setter|, which should have the following signature: // // size_t setter(ArrayView view) // // |setter| is given an appropriately typed ArrayView of length exactly // |max_elements| that describes the area where it should write the data; it // should return the number of elements actually written. (If it doesn't fill // the whole ArrayView, it should leave the unused space at the end.) template ::value>::type* = nullptr> size_t SetData(size_t max_elements, F&& setter) { RTC_DCHECK(IsConsistent()); const size_t old_size = size_; size_ = 0; const size_t written = AppendData(max_elements, std::forward(setter)); if (ZeroOnFree && size_ < old_size) { ZeroTrailingData(old_size - size_); } return written; } // The AppendData functions add data to the end of the buffer. They accept // the same input types as the constructors. template ::value>::type* = nullptr> void AppendData(const U* data, size_t size) { RTC_DCHECK(IsConsistent()); const size_t new_size = size_ + size; EnsureCapacityWithHeadroom(new_size, true); static_assert(sizeof(T) == sizeof(U), ""); std::memcpy(data_.get() + size_, data, size * sizeof(U)); size_ = new_size; RTC_DCHECK(IsConsistent()); } template ::value>::type* = nullptr> void AppendData(const U (&array)[N]) { AppendData(array, N); } template ::value>::type* = nullptr> void AppendData(const W& w) { AppendData(w.data(), w.size()); } template ::value>::type* = nullptr> void AppendData(const U& item) { AppendData(&item, 1); } // Appends at most |max_elements| to the end of the buffer, using the function // |setter|, which should have the following signature: // // size_t setter(ArrayView view) // // |setter| is given an appropriately typed ArrayView of length exactly // |max_elements| that describes the area where it should write the data; it // should return the number of elements actually written. (If it doesn't fill // the whole ArrayView, it should leave the unused space at the end.) template ::value>::type* = nullptr> size_t AppendData(size_t max_elements, F&& setter) { RTC_DCHECK(IsConsistent()); const size_t old_size = size_; SetSize(old_size + max_elements); U* base_ptr = data() + old_size; size_t written_elements = setter(rtc::ArrayView(base_ptr, max_elements)); RTC_CHECK_LE(written_elements, max_elements); size_ = old_size + written_elements; RTC_DCHECK(IsConsistent()); return written_elements; } // Sets the size of the buffer. If the new size is smaller than the old, the // buffer contents will be kept but truncated; if the new size is greater, // the existing contents will be kept and the new space will be // uninitialized. void SetSize(size_t size) { const size_t old_size = size_; EnsureCapacityWithHeadroom(size, true); size_ = size; if (ZeroOnFree && size_ < old_size) { ZeroTrailingData(old_size - size_); } } // Ensure that the buffer size can be increased to at least capacity without // further reallocation. (Of course, this operation might need to reallocate // the buffer.) void EnsureCapacity(size_t capacity) { // Don't allocate extra headroom, since the user is asking for a specific // capacity. EnsureCapacityWithHeadroom(capacity, false); } // Resets the buffer to zero size without altering capacity. Works even if the // buffer has been moved from. void Clear() { MaybeZeroCompleteBuffer(); size_ = 0; RTC_DCHECK(IsConsistent()); } // Swaps two buffers. Also works for buffers that have been moved from. friend void swap(BufferT& a, BufferT& b) { using std::swap; swap(a.size_, b.size_); swap(a.capacity_, b.capacity_); swap(a.data_, b.data_); } private: void EnsureCapacityWithHeadroom(size_t capacity, bool extra_headroom) { RTC_DCHECK(IsConsistent()); if (capacity <= capacity_) return; // If the caller asks for extra headroom, ensure that the new capacity is // >= 1.5 times the old capacity. Any constant > 1 is sufficient to prevent // quadratic behavior; as to why we pick 1.5 in particular, see // https://github.com/facebook/folly/blob/master/folly/docs/FBVector.md and // http://www.gahcep.com/cpp-internals-stl-vector-part-1/. const size_t new_capacity = extra_headroom ? std::max(capacity, capacity_ + capacity_ / 2) : capacity; std::unique_ptr new_data(new T[new_capacity]); if (data_ != nullptr) { std::memcpy(new_data.get(), data_.get(), size_ * sizeof(T)); } MaybeZeroCompleteBuffer(); data_ = std::move(new_data); capacity_ = new_capacity; RTC_DCHECK(IsConsistent()); } // Zero the complete buffer if template argument "ZeroOnFree" is true. void MaybeZeroCompleteBuffer() { if (ZeroOnFree && capacity_ > 0) { // It would be sufficient to only zero "size_" elements, as all other // methods already ensure that the unused capacity contains no sensitive // data---but better safe than sorry. ExplicitZeroMemory(data_.get(), capacity_ * sizeof(T)); } } // Zero the first "count" elements of unused capacity. void ZeroTrailingData(size_t count) { RTC_DCHECK(IsConsistent()); RTC_DCHECK_LE(count, capacity_ - size_); ExplicitZeroMemory(data_.get() + size_, count * sizeof(T)); } // Precondition for all methods except Clear, operator= and the destructor. // Postcondition for all methods except move construction and move // assignment, which leave the moved-from object in a possibly inconsistent // state. bool IsConsistent() const { return (data_ || capacity_ == 0) && capacity_ >= size_; } // Called when *this has been moved from. Conceptually it's a no-op, but we // can mutate the state slightly to help subsequent sanity checks catch bugs. void OnMovedFrom() { RTC_DCHECK(!data_); // Our heap block should have been stolen. #if RTC_DCHECK_IS_ON // Ensure that *this is always inconsistent, to provoke bugs. size_ = 1; capacity_ = 0; #else // Make *this consistent and empty. Shouldn't be necessary, but better safe // than sorry. size_ = 0; capacity_ = 0; #endif } size_t size_; size_t capacity_; std::unique_ptr data_; }; // By far the most common sort of buffer. using Buffer = BufferT; // A buffer that zeros memory before releasing it. template using ZeroOnFreeBuffer = BufferT; } // namespace rtc #endif // RTC_BASE_BUFFER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/checks.cc0000664000175000017500000001340414475643423021507 0ustar00arunarun/* * Copyright 2006 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Most of this was borrowed (with minor modifications) from V8's and Chromium's // src/base/logging.cc. #include #include #include #if defined(WEBRTC_ANDROID) #define RTC_LOG_TAG_ANDROID "rtc" #include // NOLINT #endif #if defined(WEBRTC_WIN) #include #endif #if defined(WEBRTC_WIN) #define LAST_SYSTEM_ERROR (::GetLastError()) #elif defined(__native_client__) && __native_client__ #define LAST_SYSTEM_ERROR (0) #elif defined(WEBRTC_POSIX) #include #define LAST_SYSTEM_ERROR (errno) #endif // WEBRTC_WIN #include "rtc_base/checks.h" namespace { #if defined(__GNUC__) __attribute__((__format__(__printf__, 2, 3))) #endif void AppendFormat(std::string* s, const char* fmt, ...) { va_list args, copy; va_start(args, fmt); va_copy(copy, args); const int predicted_length = std::vsnprintf(nullptr, 0, fmt, copy); va_end(copy); if (predicted_length > 0) { const size_t size = s->size(); s->resize(size + predicted_length); // Pass "+ 1" to vsnprintf to include space for the '\0'. std::vsnprintf(&((*s)[size]), predicted_length + 1, fmt, args); } va_end(args); } } // namespace namespace rtc { namespace webrtc_checks_impl { #if RTC_CHECK_MSG_ENABLED // Reads one argument from args, appends it to s and advances fmt. // Returns true iff an argument was sucessfully parsed. bool ParseArg(va_list* args, const CheckArgType** fmt, std::string* s) { if (**fmt == CheckArgType::kEnd) return false; switch (**fmt) { case CheckArgType::kInt: AppendFormat(s, "%d", va_arg(*args, int)); break; case CheckArgType::kLong: AppendFormat(s, "%ld", va_arg(*args, long)); break; case CheckArgType::kLongLong: AppendFormat(s, "%lld", va_arg(*args, long long)); break; case CheckArgType::kUInt: AppendFormat(s, "%u", va_arg(*args, unsigned)); break; case CheckArgType::kULong: AppendFormat(s, "%lu", va_arg(*args, unsigned long)); break; case CheckArgType::kULongLong: AppendFormat(s, "%llu", va_arg(*args, unsigned long long)); break; case CheckArgType::kDouble: AppendFormat(s, "%g", va_arg(*args, double)); break; case CheckArgType::kLongDouble: AppendFormat(s, "%Lg", va_arg(*args, long double)); break; case CheckArgType::kCharP: s->append(va_arg(*args, const char*)); break; case CheckArgType::kStdString: s->append(*va_arg(*args, const std::string*)); break; case CheckArgType::kStringView: { const absl::string_view sv = *va_arg(*args, const absl::string_view*); s->append(sv.data(), sv.size()); break; } case CheckArgType::kVoidP: AppendFormat(s, "%p", va_arg(*args, const void*)); break; default: s->append("[Invalid CheckArgType]"); return false; } (*fmt)++; return true; } RTC_NORETURN void FatalLog(const char* file, int line, const char* message, const CheckArgType* fmt, ...) { va_list args; va_start(args, fmt); std::string s; AppendFormat(&s, "\n\n" "#\n" "# Fatal error in: %s, line %d\n" "# last system error: %u\n" "# Check failed: %s", file, line, LAST_SYSTEM_ERROR, message); if (*fmt == CheckArgType::kCheckOp) { // This log message was generated by RTC_CHECK_OP, so we have to complete // the error message using the operands that have been passed as the first // two arguments. fmt++; std::string s1, s2; if (ParseArg(&args, &fmt, &s1) && ParseArg(&args, &fmt, &s2)) AppendFormat(&s, " (%s vs. %s)\n# ", s1.c_str(), s2.c_str()); } else { s.append("\n# "); } // Append all the user-supplied arguments to the message. while (ParseArg(&args, &fmt, &s)) ; va_end(args); const char* output = s.c_str(); #if defined(WEBRTC_ANDROID) __android_log_print(ANDROID_LOG_ERROR, RTC_LOG_TAG_ANDROID, "%s\n", output); #endif fflush(stdout); fprintf(stderr, "%s", output); fflush(stderr); #if defined(WEBRTC_WIN) DebugBreak(); #endif abort(); } #else // RTC_CHECK_MSG_ENABLED RTC_NORETURN void FatalLog(const char* file, int line) { std::string s; AppendFormat(&s, "\n\n" "#\n" "# Fatal error in: %s, line %d\n" "# last system error: %u\n" "# Check failed.\n" "# ", file, line, LAST_SYSTEM_ERROR); const char* output = s.c_str(); #if defined(WEBRTC_ANDROID) __android_log_print(ANDROID_LOG_ERROR, RTC_LOG_TAG_ANDROID, "%s\n", output); #endif fflush(stdout); fprintf(stderr, "%s", output); fflush(stderr); #if defined(WEBRTC_WIN) DebugBreak(); #endif abort(); } #endif // RTC_CHECK_MSG_ENABLED } // namespace webrtc_checks_impl } // namespace rtc // Function to call from the C version of the RTC_CHECK and RTC_DCHECK macros. RTC_NORETURN void rtc_FatalMessage(const char* file, int line, const char* msg) { #if RTC_CHECK_MSG_ENABLED static constexpr rtc::webrtc_checks_impl::CheckArgType t[] = { rtc::webrtc_checks_impl::CheckArgType::kEnd}; rtc::webrtc_checks_impl::FatalLog(file, line, msg, t); #else rtc::webrtc_checks_impl::FatalLog(file, line); #endif } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/checks.h0000664000175000017500000004524014475643423021354 0ustar00arunarun/* * Copyright 2006 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_CHECKS_H_ #define RTC_BASE_CHECKS_H_ // If you for some reson need to know if DCHECKs are on, test the value of // RTC_DCHECK_IS_ON. (Test its value, not if it's defined; it'll always be // defined, to either a true or a false value.) #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) #define RTC_DCHECK_IS_ON 1 #else #define RTC_DCHECK_IS_ON 0 #endif // Annotate a function that will not return control flow to the caller. #if defined(_MSC_VER) #define RTC_NORETURN __declspec(noreturn) #elif defined(__GNUC__) #define RTC_NORETURN __attribute__((__noreturn__)) #else #define RTC_NORETURN #endif #ifdef __cplusplus extern "C" { #endif RTC_NORETURN void rtc_FatalMessage(const char* file, int line, const char* msg); #ifdef __cplusplus } // extern "C" #endif #ifdef RTC_DISABLE_CHECK_MSG #define RTC_CHECK_MSG_ENABLED 0 #else #define RTC_CHECK_MSG_ENABLED 1 #endif #if RTC_CHECK_MSG_ENABLED #define RTC_CHECK_EVAL_MESSAGE(message) message #else #define RTC_CHECK_EVAL_MESSAGE(message) "" #endif #ifdef __cplusplus // C++ version. #include #include "absl/meta/type_traits.h" #include "absl/strings/string_view.h" #include "rtc_base/numerics/safe_compare.h" #include "rtc_base/system/inline.h" #include "rtc_base/system/rtc_export.h" // The macros here print a message to stderr and abort under various // conditions. All will accept additional stream messages. For example: // RTC_DCHECK_EQ(foo, bar) << "I'm printed when foo != bar."; // // - RTC_CHECK(x) is an assertion that x is always true, and that if it isn't, // it's better to terminate the process than to continue. During development, // the reason that it's better to terminate might simply be that the error // handling code isn't in place yet; in production, the reason might be that // the author of the code truly believes that x will always be true, but that // they recognizes that if they are wrong, abrupt and unpleasant process // termination is still better than carrying on with the assumption violated. // // RTC_CHECK always evaluates its argument, so it's OK for x to have side // effects. // // - RTC_DCHECK(x) is the same as RTC_CHECK(x)---an assertion that x is always // true---except that x will only be evaluated in debug builds; in production // builds, x is simply assumed to be true. This is useful if evaluating x is // expensive and the expected cost of failing to detect the violated // assumption is acceptable. You should not handle cases where a production // build fails to spot a violated condition, even those that would result in // crashes. If the code needs to cope with the error, make it cope, but don't // call RTC_DCHECK; if the condition really can't occur, but you'd sleep // better at night knowing that the process will suicide instead of carrying // on in case you were wrong, use RTC_CHECK instead of RTC_DCHECK. // // RTC_DCHECK only evaluates its argument in debug builds, so if x has visible // side effects, you need to write e.g. // bool w = x; RTC_DCHECK(w); // // - RTC_CHECK_EQ, _NE, _GT, ..., and RTC_DCHECK_EQ, _NE, _GT, ... are // specialized variants of RTC_CHECK and RTC_DCHECK that print prettier // messages if the condition doesn't hold. Prefer them to raw RTC_CHECK and // RTC_DCHECK. // // - FATAL() aborts unconditionally. namespace rtc { namespace webrtc_checks_impl { enum class CheckArgType : int8_t { kEnd = 0, kInt, kLong, kLongLong, kUInt, kULong, kULongLong, kDouble, kLongDouble, kCharP, kStdString, kStringView, kVoidP, // kCheckOp doesn't represent an argument type. Instead, it is sent as the // first argument from RTC_CHECK_OP to make FatalLog use the next two // arguments to build the special CHECK_OP error message // (the "a == b (1 vs. 2)" bit). kCheckOp, }; #if RTC_CHECK_MSG_ENABLED RTC_NORETURN RTC_EXPORT void FatalLog(const char* file, int line, const char* message, const CheckArgType* fmt, ...); #else RTC_NORETURN RTC_EXPORT void FatalLog(const char* file, int line); #endif // Wrapper for log arguments. Only ever make values of this type with the // MakeVal() functions. template struct Val { static constexpr CheckArgType Type() { return N; } T GetVal() const { return val; } T val; }; // Case for when we need to construct a temp string and then print that. // (We can't use Val // because we need somewhere to store the temp string.) struct ToStringVal { static constexpr CheckArgType Type() { return CheckArgType::kStdString; } const std::string* GetVal() const { return &val; } std::string val; }; inline Val MakeVal(int x) { return {x}; } inline Val MakeVal(long x) { return {x}; } inline Val MakeVal(long long x) { return {x}; } inline Val MakeVal(unsigned int x) { return {x}; } inline Val MakeVal(unsigned long x) { return {x}; } inline Val MakeVal( unsigned long long x) { return {x}; } inline Val MakeVal(double x) { return {x}; } inline Val MakeVal(long double x) { return {x}; } inline Val MakeVal(const char* x) { return {x}; } inline Val MakeVal( const std::string& x) { return {&x}; } inline Val MakeVal( const absl::string_view& x) { return {&x}; } inline Val MakeVal(const void* x) { return {x}; } // The enum class types are not implicitly convertible to arithmetic types. template ::value && !std::is_arithmetic::value>* = nullptr> inline decltype(MakeVal(std::declval>())) MakeVal( T x) { return {static_cast>(x)}; } template ()))* = nullptr> ToStringVal MakeVal(const T& x) { return {ToLogString(x)}; } // Ephemeral type that represents the result of the logging << operator. template class LogStreamer; // Base case: Before the first << argument. template <> class LogStreamer<> final { public: template ())), absl::enable_if_t::value || std::is_enum::value>* = nullptr> RTC_FORCE_INLINE LogStreamer operator<<(U arg) const { return LogStreamer(MakeVal(arg), this); } template ())), absl::enable_if_t::value && !std::is_enum::value>* = nullptr> RTC_FORCE_INLINE LogStreamer operator<<(const U& arg) const { return LogStreamer(MakeVal(arg), this); } #if RTC_CHECK_MSG_ENABLED template RTC_NORETURN RTC_FORCE_INLINE static void Call(const char* file, const int line, const char* message, const Us&... args) { static constexpr CheckArgType t[] = {Us::Type()..., CheckArgType::kEnd}; FatalLog(file, line, message, t, args.GetVal()...); } template RTC_NORETURN RTC_FORCE_INLINE static void CallCheckOp(const char* file, const int line, const char* message, const Us&... args) { static constexpr CheckArgType t[] = {CheckArgType::kCheckOp, Us::Type()..., CheckArgType::kEnd}; FatalLog(file, line, message, t, args.GetVal()...); } #else template RTC_NORETURN RTC_FORCE_INLINE static void Call(const char* file, const int line) { FatalLog(file, line); } #endif }; // Inductive case: We've already seen at least one << argument. The most recent // one had type `T`, and the earlier ones had types `Ts`. template class LogStreamer final { public: RTC_FORCE_INLINE LogStreamer(T arg, const LogStreamer* prior) : arg_(arg), prior_(prior) {} template ())), absl::enable_if_t::value || std::is_enum::value>* = nullptr> RTC_FORCE_INLINE LogStreamer operator<<(U arg) const { return LogStreamer(MakeVal(arg), this); } template ())), absl::enable_if_t::value && !std::is_enum::value>* = nullptr> RTC_FORCE_INLINE LogStreamer operator<<(const U& arg) const { return LogStreamer(MakeVal(arg), this); } #if RTC_CHECK_MSG_ENABLED template RTC_NORETURN RTC_FORCE_INLINE void Call(const char* file, const int line, const char* message, const Us&... args) const { prior_->Call(file, line, message, arg_, args...); } template RTC_NORETURN RTC_FORCE_INLINE void CallCheckOp(const char* file, const int line, const char* message, const Us&... args) const { prior_->CallCheckOp(file, line, message, arg_, args...); } #else template RTC_NORETURN RTC_FORCE_INLINE void Call(const char* file, const int line) const { prior_->Call(file, line); } #endif private: // The most recent argument. T arg_; // Earlier arguments. const LogStreamer* prior_; }; template class FatalLogCall final { public: FatalLogCall(const char* file, int line, const char* message) : file_(file), line_(line), message_(message) {} // This can be any binary operator with precedence lower than <<. template RTC_NORETURN RTC_FORCE_INLINE void operator&( const LogStreamer& streamer) { #if RTC_CHECK_MSG_ENABLED isCheckOp ? streamer.CallCheckOp(file_, line_, message_) : streamer.Call(file_, line_, message_); #else streamer.Call(file_, line_); #endif } private: const char* file_; int line_; const char* message_; }; } // namespace webrtc_checks_impl // The actual stream used isn't important. We reference |ignored| in the code // but don't evaluate it; this is to avoid "unused variable" warnings (we do so // in a particularly convoluted way with an extra ?: because that appears to be // the simplest construct that keeps Visual Studio from complaining about // condition being unused). #define RTC_EAT_STREAM_PARAMETERS(ignored) \ (true ? true : ((void)(ignored), true)) \ ? static_cast(0) \ : ::rtc::webrtc_checks_impl::FatalLogCall("", 0, "") & \ ::rtc::webrtc_checks_impl::LogStreamer<>() // Call RTC_EAT_STREAM_PARAMETERS with an argument that fails to compile if // values of the same types as |a| and |b| can't be compared with the given // operation, and that would evaluate |a| and |b| if evaluated. #define RTC_EAT_STREAM_PARAMETERS_OP(op, a, b) \ RTC_EAT_STREAM_PARAMETERS(((void)::rtc::Safe##op(a, b))) // RTC_CHECK dies with a fatal error if condition is not true. It is *not* // controlled by NDEBUG or anything else, so the check will be executed // regardless of compilation mode. // // We make sure RTC_CHECK et al. always evaluates |condition|, as // doing RTC_CHECK(FunctionWithSideEffect()) is a common idiom. // // RTC_CHECK_OP is a helper macro for binary operators. // Don't use this macro directly in your code, use RTC_CHECK_EQ et al below. #if RTC_CHECK_MSG_ENABLED #define RTC_CHECK(condition) \ (condition) ? static_cast(0) \ : ::rtc::webrtc_checks_impl::FatalLogCall( \ __FILE__, __LINE__, #condition) & \ ::rtc::webrtc_checks_impl::LogStreamer<>() #define RTC_CHECK_OP(name, op, val1, val2) \ ::rtc::Safe##name((val1), (val2)) \ ? static_cast(0) \ : ::rtc::webrtc_checks_impl::FatalLogCall( \ __FILE__, __LINE__, #val1 " " #op " " #val2) & \ ::rtc::webrtc_checks_impl::LogStreamer<>() << (val1) << (val2) #else #define RTC_CHECK(condition) \ (condition) \ ? static_cast(0) \ : true ? ::rtc::webrtc_checks_impl::FatalLogCall(__FILE__, \ __LINE__, "") & \ ::rtc::webrtc_checks_impl::LogStreamer<>() \ : ::rtc::webrtc_checks_impl::FatalLogCall("", 0, "") & \ ::rtc::webrtc_checks_impl::LogStreamer<>() #define RTC_CHECK_OP(name, op, val1, val2) \ ::rtc::Safe##name((val1), (val2)) \ ? static_cast(0) \ : true ? ::rtc::webrtc_checks_impl::FatalLogCall(__FILE__, \ __LINE__, "") & \ ::rtc::webrtc_checks_impl::LogStreamer<>() \ : ::rtc::webrtc_checks_impl::FatalLogCall("", 0, "") & \ ::rtc::webrtc_checks_impl::LogStreamer<>() #endif #define RTC_CHECK_EQ(val1, val2) RTC_CHECK_OP(Eq, ==, val1, val2) #define RTC_CHECK_NE(val1, val2) RTC_CHECK_OP(Ne, !=, val1, val2) #define RTC_CHECK_LE(val1, val2) RTC_CHECK_OP(Le, <=, val1, val2) #define RTC_CHECK_LT(val1, val2) RTC_CHECK_OP(Lt, <, val1, val2) #define RTC_CHECK_GE(val1, val2) RTC_CHECK_OP(Ge, >=, val1, val2) #define RTC_CHECK_GT(val1, val2) RTC_CHECK_OP(Gt, >, val1, val2) // The RTC_DCHECK macro is equivalent to RTC_CHECK except that it only generates // code in debug builds. It does reference the condition parameter in all cases, // though, so callers won't risk getting warnings about unused variables. #if RTC_DCHECK_IS_ON #define RTC_DCHECK(condition) RTC_CHECK(condition) #define RTC_DCHECK_EQ(v1, v2) RTC_CHECK_EQ(v1, v2) #define RTC_DCHECK_NE(v1, v2) RTC_CHECK_NE(v1, v2) #define RTC_DCHECK_LE(v1, v2) RTC_CHECK_LE(v1, v2) #define RTC_DCHECK_LT(v1, v2) RTC_CHECK_LT(v1, v2) #define RTC_DCHECK_GE(v1, v2) RTC_CHECK_GE(v1, v2) #define RTC_DCHECK_GT(v1, v2) RTC_CHECK_GT(v1, v2) #else #define RTC_DCHECK(condition) RTC_EAT_STREAM_PARAMETERS(condition) #define RTC_DCHECK_EQ(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Eq, v1, v2) #define RTC_DCHECK_NE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Ne, v1, v2) #define RTC_DCHECK_LE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Le, v1, v2) #define RTC_DCHECK_LT(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Lt, v1, v2) #define RTC_DCHECK_GE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Ge, v1, v2) #define RTC_DCHECK_GT(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Gt, v1, v2) #endif #define RTC_UNREACHABLE_CODE_HIT false #define RTC_NOTREACHED() RTC_DCHECK(RTC_UNREACHABLE_CODE_HIT) // TODO(bugs.webrtc.org/8454): Add an RTC_ prefix or rename differently. #define FATAL() \ ::rtc::webrtc_checks_impl::FatalLogCall(__FILE__, __LINE__, \ "FATAL()") & \ ::rtc::webrtc_checks_impl::LogStreamer<>() // Performs the integer division a/b and returns the result. CHECKs that the // remainder is zero. template inline T CheckedDivExact(T a, T b) { RTC_CHECK_EQ(a % b, 0) << a << " is not evenly divisible by " << b; return a / b; } } // namespace rtc #else // __cplusplus not defined // C version. Lacks many features compared to the C++ version, but usage // guidelines are the same. #define RTC_CHECK(condition) \ do { \ if (!(condition)) { \ rtc_FatalMessage(__FILE__, __LINE__, \ RTC_CHECK_EVAL_MESSAGE("CHECK failed: " #condition)); \ } \ } while (0) #define RTC_CHECK_EQ(a, b) RTC_CHECK((a) == (b)) #define RTC_CHECK_NE(a, b) RTC_CHECK((a) != (b)) #define RTC_CHECK_LE(a, b) RTC_CHECK((a) <= (b)) #define RTC_CHECK_LT(a, b) RTC_CHECK((a) < (b)) #define RTC_CHECK_GE(a, b) RTC_CHECK((a) >= (b)) #define RTC_CHECK_GT(a, b) RTC_CHECK((a) > (b)) #define RTC_DCHECK(condition) \ do { \ if (RTC_DCHECK_IS_ON && !(condition)) { \ rtc_FatalMessage(__FILE__, __LINE__, \ RTC_CHECK_EVAL_MESSAGE("DCHECK failed: " #condition)); \ } \ } while (0) #define RTC_DCHECK_EQ(a, b) RTC_DCHECK((a) == (b)) #define RTC_DCHECK_NE(a, b) RTC_DCHECK((a) != (b)) #define RTC_DCHECK_LE(a, b) RTC_DCHECK((a) <= (b)) #define RTC_DCHECK_LT(a, b) RTC_DCHECK((a) < (b)) #define RTC_DCHECK_GE(a, b) RTC_DCHECK((a) >= (b)) #define RTC_DCHECK_GT(a, b) RTC_DCHECK((a) > (b)) #endif // __cplusplus #endif // RTC_BASE_CHECKS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/compile_assert_c.h0000664000175000017500000000164414475643423023427 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_COMPILE_ASSERT_C_H_ #define RTC_BASE_COMPILE_ASSERT_C_H_ // Use this macro to verify at compile time that certain restrictions are met. // The argument is the boolean expression to evaluate. // Example: // RTC_COMPILE_ASSERT(sizeof(foo) < 128); // Note: In C++, use static_assert instead! #define RTC_COMPILE_ASSERT(expression) \ switch (0) { \ case 0: \ case expression:; \ } #endif // RTC_BASE_COMPILE_ASSERT_C_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/constructor_magic.h0000664000175000017500000000144014475643423023633 0ustar00arunarun/* * Copyright 2004 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_CONSTRUCTOR_MAGIC_H_ #define RTC_BASE_CONSTRUCTOR_MAGIC_H_ // A macro to disallow the copy constructor and operator= functions. This should // be used in the declarations for a class. #define RTC_DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&) = delete; \ TypeName& operator=(const TypeName&) = delete #endif // RTC_BASE_CONSTRUCTOR_MAGIC_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/deprecation.h0000664000175000017500000000330614475643423022406 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_DEPRECATION_H_ #define RTC_BASE_DEPRECATION_H_ // Annotate the declarations of deprecated functions with this to cause a // compiler warning when they're used. Like so: // // RTC_DEPRECATED std::pony PonyPlz(const std::pony_spec& ps); // // NOTE 1: The annotation goes on the declaration in the .h file, not the // definition in the .cc file! // // NOTE 2: In order to keep unit testing the deprecated function without // getting warnings, do something like this: // // std::pony DEPRECATED_PonyPlz(const std::pony_spec& ps); // RTC_DEPRECATED inline std::pony PonyPlz(const std::pony_spec& ps) { // return DEPRECATED_PonyPlz(ps); // } // // In other words, rename the existing function, and provide an inline wrapper // using the original name that calls it. That way, callers who are willing to // call it using the DEPRECATED_-prefixed name don't get the warning. // // TODO(kwiberg): Remove this when we can use [[deprecated]] from C++14. #if defined(_MSC_VER) // Note: Deprecation warnings seem to fail to trigger on Windows // (https://bugs.chromium.org/p/webrtc/issues/detail?id=5368). #define RTC_DEPRECATED __declspec(deprecated) #elif defined(__GNUC__) #define RTC_DEPRECATED __attribute__((__deprecated__)) #else #define RTC_DEPRECATED #endif #endif // RTC_BASE_DEPRECATION_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/event.cc0000664000175000017500000001360714475643423021375 0ustar00arunarun/* * Copyright 2004 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/event.h" #if defined(WEBRTC_WIN) #include #elif defined(WEBRTC_POSIX) #include #include #include #include #else #error "Must define either WEBRTC_WIN or WEBRTC_POSIX." #endif #include "absl/types/optional.h" #include "rtc_base/checks.h" #include "rtc_base/synchronization/yield_policy.h" #include "rtc_base/system/warn_current_thread_is_deadlocked.h" namespace rtc { Event::Event() : Event(false, false) {} #if defined(WEBRTC_WIN) Event::Event(bool manual_reset, bool initially_signaled) { event_handle_ = ::CreateEvent(nullptr, // Security attributes. manual_reset, initially_signaled, nullptr); // Name. RTC_CHECK(event_handle_); } Event::~Event() { CloseHandle(event_handle_); } void Event::Set() { SetEvent(event_handle_); } void Event::Reset() { ResetEvent(event_handle_); } bool Event::Wait(const int give_up_after_ms, int /*warn_after_ms*/) { ScopedYieldPolicy::YieldExecution(); const DWORD ms = give_up_after_ms == kForever ? INFINITE : give_up_after_ms; return (WaitForSingleObject(event_handle_, ms) == WAIT_OBJECT_0); } #elif defined(WEBRTC_POSIX) // On MacOS, clock_gettime is available from version 10.12, and on // iOS, from version 10.0. So we can't use it yet. #if defined(WEBRTC_MAC) || defined(WEBRTC_IOS) #define USE_CLOCK_GETTIME 0 #define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 0 // On Android, pthread_condattr_setclock is available from version 21. By // default, we target a new enough version for 64-bit platforms but not for // 32-bit platforms. For older versions, use // pthread_cond_timedwait_monotonic_np. #elif defined(WEBRTC_ANDROID) && (__ANDROID_API__ < 21) #define USE_CLOCK_GETTIME 1 #define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 1 #else #define USE_CLOCK_GETTIME 1 #define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 0 #endif Event::Event(bool manual_reset, bool initially_signaled) : is_manual_reset_(manual_reset), event_status_(initially_signaled) { RTC_CHECK(pthread_mutex_init(&event_mutex_, nullptr) == 0); pthread_condattr_t cond_attr; RTC_CHECK(pthread_condattr_init(&cond_attr) == 0); #if USE_CLOCK_GETTIME && !USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP RTC_CHECK(pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC) == 0); #endif RTC_CHECK(pthread_cond_init(&event_cond_, &cond_attr) == 0); pthread_condattr_destroy(&cond_attr); } Event::~Event() { pthread_mutex_destroy(&event_mutex_); pthread_cond_destroy(&event_cond_); } void Event::Set() { pthread_mutex_lock(&event_mutex_); event_status_ = true; pthread_cond_broadcast(&event_cond_); pthread_mutex_unlock(&event_mutex_); } void Event::Reset() { pthread_mutex_lock(&event_mutex_); event_status_ = false; pthread_mutex_unlock(&event_mutex_); } namespace { timespec GetTimespec(const int milliseconds_from_now) { timespec ts; // Get the current time. #if USE_CLOCK_GETTIME clock_gettime(CLOCK_MONOTONIC, &ts); #else timeval tv; gettimeofday(&tv, nullptr); ts.tv_sec = tv.tv_sec; ts.tv_nsec = tv.tv_usec * 1000; #endif // Add the specified number of milliseconds to it. ts.tv_sec += (milliseconds_from_now / 1000); ts.tv_nsec += (milliseconds_from_now % 1000) * 1000000; // Normalize. if (ts.tv_nsec >= 1000000000) { ts.tv_sec++; ts.tv_nsec -= 1000000000; } return ts; } } // namespace bool Event::Wait(const int give_up_after_ms, const int warn_after_ms) { // Instant when we'll log a warning message (because we've been waiting so // long it might be a bug), but not yet give up waiting. nullopt if we // shouldn't log a warning. const absl::optional warn_ts = warn_after_ms == kForever || (give_up_after_ms != kForever && warn_after_ms > give_up_after_ms) ? absl::nullopt : absl::make_optional(GetTimespec(warn_after_ms)); // Instant when we'll stop waiting and return an error. nullopt if we should // never give up. const absl::optional give_up_ts = give_up_after_ms == kForever ? absl::nullopt : absl::make_optional(GetTimespec(give_up_after_ms)); ScopedYieldPolicy::YieldExecution(); pthread_mutex_lock(&event_mutex_); // Wait for `event_cond_` to trigger and `event_status_` to be set, with the // given timeout (or without a timeout if none is given). const auto wait = [&](const absl::optional timeout_ts) { int error = 0; while (!event_status_ && error == 0) { if (timeout_ts == absl::nullopt) { error = pthread_cond_wait(&event_cond_, &event_mutex_); } else { #if USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP error = pthread_cond_timedwait_monotonic_np(&event_cond_, &event_mutex_, &*timeout_ts); #else error = pthread_cond_timedwait(&event_cond_, &event_mutex_, &*timeout_ts); #endif } } return error; }; int error; if (warn_ts == absl::nullopt) { error = wait(give_up_ts); } else { error = wait(warn_ts); if (error == ETIMEDOUT) { webrtc::WarnThatTheCurrentThreadIsProbablyDeadlocked(); error = wait(give_up_ts); } } // NOTE(liulk): Exactly one thread will auto-reset this event. All // the other threads will think it's unsignaled. This seems to be // consistent with auto-reset events in WEBRTC_WIN if (error == 0 && !is_manual_reset_) event_status_ = false; pthread_mutex_unlock(&event_mutex_); return (error == 0); } #endif } // namespace rtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/event.h0000664000175000017500000000515414475643423021235 0ustar00arunarun/* * Copyright 2004 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_EVENT_H_ #define RTC_BASE_EVENT_H_ #if defined(WEBRTC_WIN) #include #elif defined(WEBRTC_POSIX) #include #else #error "Must define either WEBRTC_WIN or WEBRTC_POSIX." #endif namespace rtc { class Event { public: static const int kForever = -1; Event(); Event(bool manual_reset, bool initially_signaled); Event(const Event&) = delete; Event& operator=(const Event&) = delete; ~Event(); void Set(); void Reset(); // Waits for the event to become signaled, but logs a warning if it takes more // than `warn_after_ms` milliseconds, and gives up completely if it takes more // than `give_up_after_ms` milliseconds. (If `warn_after_ms >= // give_up_after_ms`, no warning will be logged.) Either or both may be // `kForever`, which means wait indefinitely. // // Returns true if the event was signaled, false if there was a timeout or // some other error. bool Wait(int give_up_after_ms, int warn_after_ms); // Waits with the given timeout and a reasonable default warning timeout. bool Wait(int give_up_after_ms) { return Wait(give_up_after_ms, give_up_after_ms == kForever ? 3000 : kForever); } private: #if defined(WEBRTC_WIN) HANDLE event_handle_; #elif defined(WEBRTC_POSIX) pthread_mutex_t event_mutex_; pthread_cond_t event_cond_; const bool is_manual_reset_; bool event_status_; #endif }; // These classes are provided for compatibility with Chromium. // The rtc::Event implementation is overriden inside of Chromium for the // purposes of detecting when threads are blocked that shouldn't be as well as // to use the more accurate event implementation that's there than is provided // by default on some platforms (e.g. Windows). // When building with standalone WebRTC, this class is a noop. // For further information, please see the // ScopedAllowBaseSyncPrimitives(ForTesting) classes in Chromium. class ScopedAllowBaseSyncPrimitives { public: ScopedAllowBaseSyncPrimitives() {} ~ScopedAllowBaseSyncPrimitives() {} }; class ScopedAllowBaseSyncPrimitivesForTesting { public: ScopedAllowBaseSyncPrimitivesForTesting() {} ~ScopedAllowBaseSyncPrimitivesForTesting() {} }; } // namespace rtc #endif // RTC_BASE_EVENT_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/event_tracer.cc0000664000175000017500000003311514475643423022731 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/event_tracer.h" #include #include #include #include #include #include #include "rtc_base/atomic_ops.h" #include "rtc_base/checks.h" #include "rtc_base/event.h" #include "rtc_base/logging.h" #include "rtc_base/platform_thread.h" #include "rtc_base/platform_thread_types.h" #include "rtc_base/synchronization/mutex.h" #include "rtc_base/thread_annotations.h" #include "rtc_base/thread_checker.h" #include "rtc_base/time_utils.h" #include "rtc_base/trace_event.h" // This is a guesstimate that should be enough in most cases. static const size_t kEventLoggerArgsStrBufferInitialSize = 256; static const size_t kTraceArgBufferLength = 32; namespace webrtc { namespace { GetCategoryEnabledPtr g_get_category_enabled_ptr = nullptr; AddTraceEventPtr g_add_trace_event_ptr = nullptr; } // namespace void SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr, AddTraceEventPtr add_trace_event_ptr) { g_get_category_enabled_ptr = get_category_enabled_ptr; g_add_trace_event_ptr = add_trace_event_ptr; } const unsigned char* EventTracer::GetCategoryEnabled(const char* name) { if (g_get_category_enabled_ptr) return g_get_category_enabled_ptr(name); // A string with null terminator means category is disabled. return reinterpret_cast("\0"); } // Arguments to this function (phase, etc.) are as defined in // webrtc/rtc_base/trace_event.h. void EventTracer::AddTraceEvent(char phase, const unsigned char* category_enabled, const char* name, unsigned long long id, int num_args, const char** arg_names, const unsigned char* arg_types, const unsigned long long* arg_values, unsigned char flags) { if (g_add_trace_event_ptr) { g_add_trace_event_ptr(phase, category_enabled, name, id, num_args, arg_names, arg_types, arg_values, flags); } } } // namespace webrtc namespace rtc { namespace tracing { namespace { static void EventTracingThreadFunc(void* params); // Atomic-int fast path for avoiding logging when disabled. static volatile int g_event_logging_active = 0; // TODO(pbos): Log metadata for all threads, etc. class EventLogger final { public: EventLogger() : logging_thread_(EventTracingThreadFunc, this, "EventTracingThread", kLowPriority) {} ~EventLogger() { RTC_DCHECK(thread_checker_.IsCurrent()); } void AddTraceEvent(const char* name, const unsigned char* category_enabled, char phase, int num_args, const char** arg_names, const unsigned char* arg_types, const unsigned long long* arg_values, uint64_t timestamp, int pid, rtc::PlatformThreadId thread_id) { std::vector args(num_args); for (int i = 0; i < num_args; ++i) { TraceArg& arg = args[i]; arg.name = arg_names[i]; arg.type = arg_types[i]; arg.value.as_uint = arg_values[i]; // Value is a pointer to a temporary string, so we have to make a copy. if (arg.type == TRACE_VALUE_TYPE_COPY_STRING) { // Space for the string and for the terminating null character. size_t str_length = strlen(arg.value.as_string) + 1; char* str_copy = new char[str_length]; memcpy(str_copy, arg.value.as_string, str_length); arg.value.as_string = str_copy; } } webrtc::MutexLock lock(&mutex_); trace_events_.push_back( {name, category_enabled, phase, args, timestamp, 1, thread_id}); } // The TraceEvent format is documented here: // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview void Log() { RTC_DCHECK(output_file_); static const int kLoggingIntervalMs = 100; fprintf(output_file_, "{ \"traceEvents\": [\n"); bool has_logged_event = false; while (true) { bool shutting_down = shutdown_event_.Wait(kLoggingIntervalMs); std::vector events; { webrtc::MutexLock lock(&mutex_); trace_events_.swap(events); } std::string args_str; args_str.reserve(kEventLoggerArgsStrBufferInitialSize); for (TraceEvent& e : events) { args_str.clear(); if (!e.args.empty()) { args_str += ", \"args\": {"; bool is_first_argument = true; for (TraceArg& arg : e.args) { if (!is_first_argument) args_str += ","; is_first_argument = false; args_str += " \""; args_str += arg.name; args_str += "\": "; args_str += TraceArgValueAsString(arg); // Delete our copy of the string. if (arg.type == TRACE_VALUE_TYPE_COPY_STRING) { delete[] arg.value.as_string; arg.value.as_string = nullptr; } } args_str += " }"; } fprintf(output_file_, "%s{ \"name\": \"%s\"" ", \"cat\": \"%s\"" ", \"ph\": \"%c\"" ", \"ts\": %" PRIu64 ", \"pid\": %d" #if defined(WEBRTC_WIN) ", \"tid\": %lu" #else ", \"tid\": %d" #endif // defined(WEBRTC_WIN) "%s" "}\n", has_logged_event ? "," : " ", e.name, e.category_enabled, e.phase, e.timestamp, e.pid, e.tid, args_str.c_str()); has_logged_event = true; } if (shutting_down) break; } fprintf(output_file_, "]}\n"); if (output_file_owned_) fclose(output_file_); output_file_ = nullptr; } void Start(FILE* file, bool owned) { RTC_DCHECK(thread_checker_.IsCurrent()); RTC_DCHECK(file); RTC_DCHECK(!output_file_); output_file_ = file; output_file_owned_ = owned; { webrtc::MutexLock lock(&mutex_); // Since the atomic fast-path for adding events to the queue can be // bypassed while the logging thread is shutting down there may be some // stale events in the queue, hence the vector needs to be cleared to not // log events from a previous logging session (which may be days old). trace_events_.clear(); } // Enable event logging (fast-path). This should be disabled since starting // shouldn't be done twice. RTC_CHECK_EQ(0, rtc::AtomicOps::CompareAndSwap(&g_event_logging_active, 0, 1)); // Finally start, everything should be set up now. logging_thread_.Start(); TRACE_EVENT_INSTANT0("webrtc", "EventLogger::Start"); } void Stop() { RTC_DCHECK(thread_checker_.IsCurrent()); TRACE_EVENT_INSTANT0("webrtc", "EventLogger::Stop"); // Try to stop. Abort if we're not currently logging. if (rtc::AtomicOps::CompareAndSwap(&g_event_logging_active, 1, 0) == 0) return; // Wake up logging thread to finish writing. shutdown_event_.Set(); // Join the logging thread. logging_thread_.Stop(); } private: struct TraceArg { const char* name; unsigned char type; // Copied from webrtc/rtc_base/trace_event.h TraceValueUnion. union TraceArgValue { bool as_bool; unsigned long long as_uint; long long as_int; double as_double; const void* as_pointer; const char* as_string; } value; // Assert that the size of the union is equal to the size of the as_uint // field since we are assigning to arbitrary types using it. static_assert(sizeof(TraceArgValue) == sizeof(unsigned long long), "Size of TraceArg value union is not equal to the size of " "the uint field of that union."); }; struct TraceEvent { const char* name; const unsigned char* category_enabled; char phase; std::vector args; uint64_t timestamp; int pid; rtc::PlatformThreadId tid; }; static std::string TraceArgValueAsString(TraceArg arg) { std::string output; if (arg.type == TRACE_VALUE_TYPE_STRING || arg.type == TRACE_VALUE_TYPE_COPY_STRING) { // Space for every character to be an espaced character + two for // quatation marks. output.reserve(strlen(arg.value.as_string) * 2 + 2); output += '\"'; const char* c = arg.value.as_string; do { if (*c == '"' || *c == '\\') { output += '\\'; output += *c; } else { output += *c; } } while (*++c); output += '\"'; } else { output.resize(kTraceArgBufferLength); size_t print_length = 0; switch (arg.type) { case TRACE_VALUE_TYPE_BOOL: if (arg.value.as_bool) { strcpy(&output[0], "true"); print_length = 4; } else { strcpy(&output[0], "false"); print_length = 5; } break; case TRACE_VALUE_TYPE_UINT: print_length = snprintf(&output[0], kTraceArgBufferLength, "%llu", arg.value.as_uint); break; case TRACE_VALUE_TYPE_INT: print_length = snprintf(&output[0], kTraceArgBufferLength, "%lld", arg.value.as_int); break; case TRACE_VALUE_TYPE_DOUBLE: print_length = snprintf(&output[0], kTraceArgBufferLength, "%f", arg.value.as_double); break; case TRACE_VALUE_TYPE_POINTER: print_length = snprintf(&output[0], kTraceArgBufferLength, "\"%p\"", arg.value.as_pointer); break; } size_t output_length = print_length < kTraceArgBufferLength ? print_length : kTraceArgBufferLength - 1; // This will hopefully be very close to nop. On most implementations, it // just writes null byte and sets the length field of the string. output.resize(output_length); } return output; } webrtc::Mutex mutex_; std::vector trace_events_ RTC_GUARDED_BY(mutex_); rtc::PlatformThread logging_thread_; rtc::Event shutdown_event_; rtc::ThreadChecker thread_checker_; FILE* output_file_ = nullptr; bool output_file_owned_ = false; }; static void EventTracingThreadFunc(void* params) { static_cast(params)->Log(); } static EventLogger* volatile g_event_logger = nullptr; static const char* const kDisabledTracePrefix = TRACE_DISABLED_BY_DEFAULT(""); const unsigned char* InternalGetCategoryEnabled(const char* name) { const char* prefix_ptr = &kDisabledTracePrefix[0]; const char* name_ptr = name; // Check whether name contains the default-disabled prefix. while (*prefix_ptr == *name_ptr && *prefix_ptr != '\0') { ++prefix_ptr; ++name_ptr; } return reinterpret_cast(*prefix_ptr == '\0' ? "" : name); } void InternalAddTraceEvent(char phase, const unsigned char* category_enabled, const char* name, unsigned long long id, int num_args, const char** arg_names, const unsigned char* arg_types, const unsigned long long* arg_values, unsigned char flags) { // Fast path for when event tracing is inactive. if (rtc::AtomicOps::AcquireLoad(&g_event_logging_active) == 0) return; g_event_logger->AddTraceEvent(name, category_enabled, phase, num_args, arg_names, arg_types, arg_values, rtc::TimeMicros(), 1, rtc::CurrentThreadId()); } } // namespace void SetupInternalTracer() { RTC_CHECK(rtc::AtomicOps::CompareAndSwapPtr( &g_event_logger, static_cast(nullptr), new EventLogger()) == nullptr); webrtc::SetupEventTracer(InternalGetCategoryEnabled, InternalAddTraceEvent); } void StartInternalCaptureToFile(FILE* file) { if (g_event_logger) { g_event_logger->Start(file, false); } } bool StartInternalCapture(const char* filename) { if (!g_event_logger) return false; FILE* file = fopen(filename, "w"); if (!file) { RTC_LOG(LS_ERROR) << "Failed to open trace file '" << filename << "' for writing."; return false; } g_event_logger->Start(file, true); return true; } void StopInternalCapture() { if (g_event_logger) { g_event_logger->Stop(); } } void ShutdownInternalTracer() { StopInternalCapture(); EventLogger* old_logger = rtc::AtomicOps::AcquireLoadPtr(&g_event_logger); RTC_DCHECK(old_logger); RTC_CHECK(rtc::AtomicOps::CompareAndSwapPtr( &g_event_logger, old_logger, static_cast(nullptr)) == old_logger); delete old_logger; webrtc::SetupEventTracer(nullptr, nullptr); } } // namespace tracing } // namespace rtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/event_tracer.h0000664000175000017500000000600214475643423022566 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // This file defines the interface for event tracing in WebRTC. // // Event log handlers are set through SetupEventTracer(). User of this API will // provide two function pointers to handle event tracing calls. // // * GetCategoryEnabledPtr // Event tracing system calls this function to determine if a particular // event category is enabled. // // * AddTraceEventPtr // Adds a tracing event. It is the user's responsibility to log the data // provided. // // Parameters for the above two functions are described in trace_event.h. #ifndef RTC_BASE_EVENT_TRACER_H_ #define RTC_BASE_EVENT_TRACER_H_ #include namespace webrtc { typedef const unsigned char* (*GetCategoryEnabledPtr)(const char* name); typedef void (*AddTraceEventPtr)(char phase, const unsigned char* category_enabled, const char* name, unsigned long long id, int num_args, const char** arg_names, const unsigned char* arg_types, const unsigned long long* arg_values, unsigned char flags); // User of WebRTC can call this method to setup event tracing. // // This method must be called before any WebRTC methods. Functions // provided should be thread-safe. void SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr, AddTraceEventPtr add_trace_event_ptr); // This class defines interface for the event tracing system to call // internally. Do not call these methods directly. class EventTracer { public: static const unsigned char* GetCategoryEnabled(const char* name); static void AddTraceEvent(char phase, const unsigned char* category_enabled, const char* name, unsigned long long id, int num_args, const char** arg_names, const unsigned char* arg_types, const unsigned long long* arg_values, unsigned char flags); }; } // namespace webrtc namespace rtc { namespace tracing { // Set up internal event tracer. void SetupInternalTracer(); bool StartInternalCapture(const char* filename); void StartInternalCaptureToFile(FILE* file); void StopInternalCapture(); // Make sure we run this, this will tear down the internal tracing. void ShutdownInternalTracer(); } // namespace tracing } // namespace rtc #endif // RTC_BASE_EVENT_TRACER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/experiments/0000775000175000017500000000000014475643423022301 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/experiments/field_trial_parser.cc0000664000175000017500000001650514475643423026451 0ustar00arunarun/* * Copyright 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/experiments/field_trial_parser.h" #include #include #include #include #include #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_conversions.h" namespace webrtc { namespace { int FindOrEnd(std::string str, size_t start, char delimiter) { size_t pos = str.find(delimiter, start); pos = (pos == std::string::npos) ? str.length() : pos; return static_cast(pos); } } // namespace FieldTrialParameterInterface::FieldTrialParameterInterface(std::string key) : key_(key) {} FieldTrialParameterInterface::~FieldTrialParameterInterface() { RTC_DCHECK(used_) << "Field trial parameter with key: '" << key_ << "' never used."; } void ParseFieldTrial( std::initializer_list fields, std::string trial_string) { std::map field_map; FieldTrialParameterInterface* keyless_field = nullptr; for (FieldTrialParameterInterface* field : fields) { field->MarkAsUsed(); if (!field->sub_parameters_.empty()) { for (FieldTrialParameterInterface* sub_field : field->sub_parameters_) { RTC_DCHECK(!sub_field->key_.empty()); sub_field->MarkAsUsed(); field_map[sub_field->key_] = sub_field; } continue; } if (field->key_.empty()) { RTC_DCHECK(!keyless_field); keyless_field = field; } else { field_map[field->key_] = field; } } size_t i = 0; while (i < trial_string.length()) { int val_end = FindOrEnd(trial_string, i, ','); int colon_pos = FindOrEnd(trial_string, i, ':'); int key_end = std::min(val_end, colon_pos); int val_begin = key_end + 1; std::string key = trial_string.substr(i, key_end - i); absl::optional opt_value; if (val_end >= val_begin) opt_value = trial_string.substr(val_begin, val_end - val_begin); i = val_end + 1; auto field = field_map.find(key); if (field != field_map.end()) { if (!field->second->Parse(std::move(opt_value))) { RTC_LOG(LS_WARNING) << "Failed to read field with key: '" << key << "' in trial: \"" << trial_string << "\""; } } else if (!opt_value && keyless_field && !key.empty()) { if (!keyless_field->Parse(key)) { RTC_LOG(LS_WARNING) << "Failed to read empty key field with value '" << key << "' in trial: \"" << trial_string << "\""; } } else { RTC_LOG(LS_INFO) << "No field with key: '" << key << "' (found in trial: \"" << trial_string << "\")"; std::string valid_keys; for (const auto& f : field_map) { valid_keys += f.first; valid_keys += ", "; } RTC_LOG(LS_INFO) << "Valid keys are: " << valid_keys; } } for (FieldTrialParameterInterface* field : fields) { field->ParseDone(); } } template <> absl::optional ParseTypedParameter(std::string str) { if (str == "true" || str == "1") { return true; } else if (str == "false" || str == "0") { return false; } return absl::nullopt; } template <> absl::optional ParseTypedParameter(std::string str) { double value; char unit[2]{0, 0}; if (sscanf(str.c_str(), "%lf%1s", &value, unit) >= 1) { if (unit[0] == '%') return value / 100; return value; } else { return absl::nullopt; } } template <> absl::optional ParseTypedParameter(std::string str) { int64_t value; if (sscanf(str.c_str(), "%" SCNd64, &value) == 1) { if (rtc::IsValueInRangeForNumericType(value)) { return static_cast(value); } } return absl::nullopt; } template <> absl::optional ParseTypedParameter(std::string str) { int64_t value; if (sscanf(str.c_str(), "%" SCNd64, &value) == 1) { if (rtc::IsValueInRangeForNumericType(value)) { return static_cast(value); } } return absl::nullopt; } template <> absl::optional ParseTypedParameter(std::string str) { return std::move(str); } template <> absl::optional> ParseTypedParameter>( std::string str) { return ParseOptionalParameter(str); } template <> absl::optional> ParseTypedParameter>( std::string str) { return ParseOptionalParameter(str); } template <> absl::optional> ParseTypedParameter>(std::string str) { return ParseOptionalParameter(str); } template <> absl::optional> ParseTypedParameter>(std::string str) { return ParseOptionalParameter(str); } FieldTrialFlag::FieldTrialFlag(std::string key) : FieldTrialFlag(key, false) {} FieldTrialFlag::FieldTrialFlag(std::string key, bool default_value) : FieldTrialParameterInterface(key), value_(default_value) {} bool FieldTrialFlag::Get() const { return value_; } webrtc::FieldTrialFlag::operator bool() const { return value_; } bool FieldTrialFlag::Parse(absl::optional str_value) { // Only set the flag if there is no argument provided. if (str_value) { absl::optional opt_value = ParseTypedParameter(*str_value); if (!opt_value) return false; value_ = *opt_value; } else { value_ = true; } return true; } AbstractFieldTrialEnum::AbstractFieldTrialEnum( std::string key, int default_value, std::map mapping) : FieldTrialParameterInterface(key), value_(default_value), enum_mapping_(mapping) { for (auto& key_val : enum_mapping_) valid_values_.insert(key_val.second); } AbstractFieldTrialEnum::AbstractFieldTrialEnum(const AbstractFieldTrialEnum&) = default; AbstractFieldTrialEnum::~AbstractFieldTrialEnum() = default; bool AbstractFieldTrialEnum::Parse(absl::optional str_value) { if (str_value) { auto it = enum_mapping_.find(*str_value); if (it != enum_mapping_.end()) { value_ = it->second; return true; } absl::optional value = ParseTypedParameter(*str_value); if (value.has_value() && (valid_values_.find(*value) != valid_values_.end())) { value_ = *value; return true; } } return false; } template class FieldTrialParameter; template class FieldTrialParameter; template class FieldTrialParameter; template class FieldTrialParameter; template class FieldTrialParameter; template class FieldTrialConstrained; template class FieldTrialConstrained; template class FieldTrialConstrained; template class FieldTrialOptional; template class FieldTrialOptional; template class FieldTrialOptional; template class FieldTrialOptional; template class FieldTrialOptional; } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/experiments/field_trial_parser.h0000664000175000017500000002320714475643423026310 0ustar00arunarun/* * Copyright 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_ #define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_ #include #include #include #include #include #include #include "absl/types/optional.h" // Field trial parser functionality. Provides funcitonality to parse field trial // argument strings in key:value format. Each parameter is described using // key:value, parameters are separated with a ,. Values can't include the comma // character, since there's no quote facility. For most types, white space is // ignored. Parameters are declared with a given type for which an // implementation of ParseTypedParameter should be provided. The // ParseTypedParameter implementation is given whatever is between the : and the // ,. If the key is provided without : a FieldTrialOptional will use nullopt. // Example string: "my_optional,my_int:3,my_string:hello" // For further description of usage and behavior, see the examples in the unit // tests. namespace webrtc { class FieldTrialParameterInterface { public: virtual ~FieldTrialParameterInterface(); std::string key() const { return key_; } protected: // Protected to allow implementations to provide assignment and copy. FieldTrialParameterInterface(const FieldTrialParameterInterface&) = default; FieldTrialParameterInterface& operator=(const FieldTrialParameterInterface&) = default; explicit FieldTrialParameterInterface(std::string key); friend void ParseFieldTrial( std::initializer_list fields, std::string raw_string); void MarkAsUsed() { used_ = true; } virtual bool Parse(absl::optional str_value) = 0; virtual void ParseDone() {} std::vector sub_parameters_; private: std::string key_; bool used_ = false; }; // ParseFieldTrial function parses the given string and fills the given fields // with extracted values if available. void ParseFieldTrial( std::initializer_list fields, std::string raw_string); // Specialize this in code file for custom types. Should return absl::nullopt if // the given string cannot be properly parsed. template absl::optional ParseTypedParameter(std::string); // This class uses the ParseTypedParameter function to implement a parameter // implementation with an enforced default value. template class FieldTrialParameter : public FieldTrialParameterInterface { public: FieldTrialParameter(std::string key, T default_value) : FieldTrialParameterInterface(key), value_(default_value) {} T Get() const { return value_; } operator T() const { return Get(); } const T* operator->() const { return &value_; } void SetForTest(T value) { value_ = value; } protected: bool Parse(absl::optional str_value) override { if (str_value) { absl::optional value = ParseTypedParameter(*str_value); if (value.has_value()) { value_ = value.value(); return true; } } return false; } private: T value_; }; // This class uses the ParseTypedParameter function to implement a parameter // implementation with an enforced default value and a range constraint. Values // outside the configured range will be ignored. template class FieldTrialConstrained : public FieldTrialParameterInterface { public: FieldTrialConstrained(std::string key, T default_value, absl::optional lower_limit, absl::optional upper_limit) : FieldTrialParameterInterface(key), value_(default_value), lower_limit_(lower_limit), upper_limit_(upper_limit) {} T Get() const { return value_; } operator T() const { return Get(); } const T* operator->() const { return &value_; } protected: bool Parse(absl::optional str_value) override { if (str_value) { absl::optional value = ParseTypedParameter(*str_value); if (value && (!lower_limit_ || *value >= *lower_limit_) && (!upper_limit_ || *value <= *upper_limit_)) { value_ = *value; return true; } } return false; } private: T value_; absl::optional lower_limit_; absl::optional upper_limit_; }; class AbstractFieldTrialEnum : public FieldTrialParameterInterface { public: AbstractFieldTrialEnum(std::string key, int default_value, std::map mapping); ~AbstractFieldTrialEnum() override; AbstractFieldTrialEnum(const AbstractFieldTrialEnum&); protected: bool Parse(absl::optional str_value) override; protected: int value_; std::map enum_mapping_; std::set valid_values_; }; // The FieldTrialEnum class can be used to quickly define a parser for a // specific enum. It handles values provided as integers and as strings if a // mapping is provided. template class FieldTrialEnum : public AbstractFieldTrialEnum { public: FieldTrialEnum(std::string key, T default_value, std::map mapping) : AbstractFieldTrialEnum(key, static_cast(default_value), ToIntMap(mapping)) {} T Get() const { return static_cast(value_); } operator T() const { return Get(); } private: static std::map ToIntMap(std::map mapping) { std::map res; for (const auto& it : mapping) res[it.first] = static_cast(it.second); return res; } }; // This class uses the ParseTypedParameter function to implement an optional // parameter implementation that can default to absl::nullopt. template class FieldTrialOptional : public FieldTrialParameterInterface { public: explicit FieldTrialOptional(std::string key) : FieldTrialParameterInterface(key) {} FieldTrialOptional(std::string key, absl::optional default_value) : FieldTrialParameterInterface(key), value_(default_value) {} absl::optional GetOptional() const { return value_; } const T& Value() const { return value_.value(); } const T& operator*() const { return value_.value(); } const T* operator->() const { return &value_.value(); } explicit operator bool() const { return value_.has_value(); } protected: bool Parse(absl::optional str_value) override { if (str_value) { absl::optional value = ParseTypedParameter(*str_value); if (!value.has_value()) return false; value_ = value.value(); } else { value_ = absl::nullopt; } return true; } private: absl::optional value_; }; // Equivalent to a FieldTrialParameter in the case that both key and value // are present. If key is missing, evaluates to false. If key is present, but no // explicit value is provided, the flag evaluates to true. class FieldTrialFlag : public FieldTrialParameterInterface { public: explicit FieldTrialFlag(std::string key); FieldTrialFlag(std::string key, bool default_value); bool Get() const; operator bool() const; protected: bool Parse(absl::optional str_value) override; private: bool value_; }; template absl::optional> ParseOptionalParameter(std::string str) { if (str.empty()) return absl::optional(); auto parsed = ParseTypedParameter(str); if (parsed.has_value()) return parsed; return absl::nullopt; } template <> absl::optional ParseTypedParameter(std::string str); template <> absl::optional ParseTypedParameter(std::string str); template <> absl::optional ParseTypedParameter(std::string str); template <> absl::optional ParseTypedParameter(std::string str); template <> absl::optional ParseTypedParameter(std::string str); template <> absl::optional> ParseTypedParameter>( std::string str); template <> absl::optional> ParseTypedParameter>( std::string str); template <> absl::optional> ParseTypedParameter>(std::string str); template <> absl::optional> ParseTypedParameter>(std::string str); // Accepts true, false, else parsed with sscanf %i, true if != 0. extern template class FieldTrialParameter; // Interpreted using sscanf %lf. extern template class FieldTrialParameter; // Interpreted using sscanf %i. extern template class FieldTrialParameter; // Interpreted using sscanf %u. extern template class FieldTrialParameter; // Using the given value as is. extern template class FieldTrialParameter; extern template class FieldTrialConstrained; extern template class FieldTrialConstrained; extern template class FieldTrialConstrained; extern template class FieldTrialOptional; extern template class FieldTrialOptional; extern template class FieldTrialOptional; extern template class FieldTrialOptional; extern template class FieldTrialOptional; } // namespace webrtc #endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/gtest_prod_util.h0000664000175000017500000000274014475643423023321 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_GTEST_PROD_UTIL_H_ #define RTC_BASE_GTEST_PROD_UTIL_H_ // Define our own version of FRIEND_TEST here rather than including // gtest_prod.h to avoid depending on any part of GTest in production code. #define FRIEND_TEST_WEBRTC(test_case_name, test_name) \ friend class test_case_name##_##test_name##_Test // This file is a plain copy of Chromium's base/gtest_prod_util.h. // // This is a wrapper for gtest's FRIEND_TEST macro that friends // test with all possible prefixes. This is very helpful when changing the test // prefix, because the friend declarations don't need to be updated. // // Example usage: // // class MyClass { // private: // void MyMethod(); // FRIEND_TEST_ALL_PREFIXES(MyClassTest, MyMethod); // }; #define FRIEND_TEST_ALL_PREFIXES(test_case_name, test_name) \ FRIEND_TEST_WEBRTC(test_case_name, test_name); \ FRIEND_TEST_WEBRTC(test_case_name, DISABLED_##test_name); \ FRIEND_TEST_WEBRTC(test_case_name, FLAKY_##test_name); \ FRIEND_TEST_WEBRTC(test_case_name, FAILS_##test_name) #endif // RTC_BASE_GTEST_PROD_UTIL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/ignore_wundef.h0000664000175000017500000000221314475643423022740 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_IGNORE_WUNDEF_H_ #define RTC_BASE_IGNORE_WUNDEF_H_ // If a header file uses #if on possibly undefined macros (and it's for some // reason not possible to just fix the header file), include it like this: // // RTC_PUSH_IGNORING_WUNDEF() // #include "misbehaving_header.h" // RTC_POP_IGNORING_WUNDEF() // // This will cause the compiler to not emit -Wundef warnings for that file. #ifdef __clang__ #define RTC_PUSH_IGNORING_WUNDEF() \ _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Wundef\"") #define RTC_POP_IGNORING_WUNDEF() _Pragma("clang diagnostic pop") #else #define RTC_PUSH_IGNORING_WUNDEF() #define RTC_POP_IGNORING_WUNDEF() #endif // __clang__ #endif // RTC_BASE_IGNORE_WUNDEF_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/logging.cc0000664000175000017500000004025514475643423021701 0ustar00arunarun/* * Copyright 2004 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/logging.h" #include #if RTC_LOG_ENABLED() #if defined(WEBRTC_WIN) #include #include #if _MSC_VER < 1900 #define snprintf _snprintf #endif #undef ERROR // wingdi.h #endif #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) #include #elif defined(WEBRTC_ANDROID) #include // Android has a 1024 limit on log inputs. We use 60 chars as an // approx for the header/tag portion. // See android/system/core/liblog/logd_write.c static const int kMaxLogLineSize = 1024 - 60; #endif // WEBRTC_MAC && !defined(WEBRTC_IOS) || WEBRTC_ANDROID #include #include #include #include #include #include #include "absl/base/attributes.h" #include "rtc_base/checks.h" #include "rtc_base/platform_thread_types.h" #include "rtc_base/string_encode.h" #include "rtc_base/string_utils.h" #include "rtc_base/strings/string_builder.h" #include "rtc_base/synchronization/mutex.h" #include "rtc_base/thread_annotations.h" #include "rtc_base/time_utils.h" namespace rtc { namespace { // By default, release builds don't log, debug builds at info level #if !defined(NDEBUG) static LoggingSeverity g_min_sev = LS_INFO; static LoggingSeverity g_dbg_sev = LS_INFO; #else static LoggingSeverity g_min_sev = LS_NONE; static LoggingSeverity g_dbg_sev = LS_NONE; #endif // Return the filename portion of the string (that following the last slash). const char* FilenameFromPath(const char* file) { const char* end1 = ::strrchr(file, '/'); const char* end2 = ::strrchr(file, '\\'); if (!end1 && !end2) return file; else return (end1 > end2) ? end1 + 1 : end2 + 1; } // Global lock for log subsystem, only needed to serialize access to streams_. // TODO(bugs.webrtc.org/11665): this is not currently constant initialized and // trivially destructible. webrtc::Mutex g_log_mutex_; } // namespace ///////////////////////////////////////////////////////////////////////////// // LogMessage ///////////////////////////////////////////////////////////////////////////// bool LogMessage::log_to_stderr_ = true; // The list of logging streams currently configured. // Note: we explicitly do not clean this up, because of the uncertain ordering // of destructors at program exit. Let the person who sets the stream trigger // cleanup by setting to null, or let it leak (safe at program exit). ABSL_CONST_INIT LogSink* LogMessage::streams_ RTC_GUARDED_BY(g_log_mutex_) = nullptr; ABSL_CONST_INIT std::atomic LogMessage::streams_empty_ = {true}; // Boolean options default to false (0) bool LogMessage::thread_, LogMessage::timestamp_; LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev) : LogMessage(file, line, sev, ERRCTX_NONE, 0) {} LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev, LogErrorContext err_ctx, int err) : severity_(sev) { if (timestamp_) { // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp // in log messages represents the real system time. int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime()); // Also ensure WallClockStartTime is initialized, so that it matches // LogStartTime. WallClockStartTime(); // TODO(kwiberg): Switch to absl::StrFormat, if binary size is ok. char timestamp[50]; // Maximum string length of an int64_t is 20. int len = snprintf(timestamp, sizeof(timestamp), "[%03" PRId64 ":%03" PRId64 "]", time / 1000, time % 1000); RTC_DCHECK_LT(len, sizeof(timestamp)); print_stream_ << timestamp; } if (thread_) { PlatformThreadId id = CurrentThreadId(); print_stream_ << "[" << id << "] "; } if (file != nullptr) { #if defined(WEBRTC_ANDROID) tag_ = FilenameFromPath(file); print_stream_ << "(line " << line << "): "; #else print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): "; #endif } if (err_ctx != ERRCTX_NONE) { char tmp_buf[1024]; SimpleStringBuilder tmp(tmp_buf); tmp.AppendFormat("[0x%08X]", err); switch (err_ctx) { case ERRCTX_ERRNO: tmp << " " << strerror(err); break; #ifdef WEBRTC_WIN case ERRCTX_HRESULT: { char msgbuf[256]; DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; if (DWORD len = FormatMessageA( flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) { while ((len > 0) && isspace(static_cast(msgbuf[len - 1]))) { msgbuf[--len] = 0; } tmp << " " << msgbuf; } break; } #endif // WEBRTC_WIN default: break; } extra_ = tmp.str(); } } #if defined(WEBRTC_ANDROID) LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev, const char* tag) : LogMessage(file, line, sev, ERRCTX_NONE, 0 /* err */) { tag_ = tag; print_stream_ << tag << ": "; } #endif // DEPRECATED. Currently only used by downstream projects that use // implementation details of logging.h. Work is ongoing to remove those // dependencies. LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev, const std::string& tag) : LogMessage(file, line, sev) { print_stream_ << tag << ": "; } LogMessage::~LogMessage() { FinishPrintStream(); const std::string str = print_stream_.Release(); if (severity_ >= g_dbg_sev) { #if defined(WEBRTC_ANDROID) OutputToDebug(str, severity_, tag_); #else OutputToDebug(str, severity_); #endif } webrtc::MutexLock lock(&g_log_mutex_); for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) { if (severity_ >= entry->min_severity_) { #if defined(WEBRTC_ANDROID) entry->OnLogMessage(str, severity_, tag_); #else entry->OnLogMessage(str, severity_); #endif } } } void LogMessage::AddTag(const char* tag) { #ifdef WEBRTC_ANDROID tag_ = tag; #endif } rtc::StringBuilder& LogMessage::stream() { return print_stream_; } int LogMessage::GetMinLogSeverity() { return g_min_sev; } LoggingSeverity LogMessage::GetLogToDebug() { return g_dbg_sev; } int64_t LogMessage::LogStartTime() { static const int64_t g_start = SystemTimeMillis(); return g_start; } uint32_t LogMessage::WallClockStartTime() { static const uint32_t g_start_wallclock = time(nullptr); return g_start_wallclock; } void LogMessage::LogThreads(bool on) { thread_ = on; } void LogMessage::LogTimestamps(bool on) { timestamp_ = on; } void LogMessage::LogToDebug(LoggingSeverity min_sev) { g_dbg_sev = min_sev; webrtc::MutexLock lock(&g_log_mutex_); UpdateMinLogSeverity(); } void LogMessage::SetLogToStderr(bool log_to_stderr) { log_to_stderr_ = log_to_stderr; } int LogMessage::GetLogToStream(LogSink* stream) { webrtc::MutexLock lock(&g_log_mutex_); LoggingSeverity sev = LS_NONE; for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) { if (stream == nullptr || stream == entry) { sev = std::min(sev, entry->min_severity_); } } return sev; } void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) { webrtc::MutexLock lock(&g_log_mutex_); stream->min_severity_ = min_sev; stream->next_ = streams_; streams_ = stream; streams_empty_.store(false, std::memory_order_relaxed); UpdateMinLogSeverity(); } void LogMessage::RemoveLogToStream(LogSink* stream) { webrtc::MutexLock lock(&g_log_mutex_); for (LogSink** entry = &streams_; *entry != nullptr; entry = &(*entry)->next_) { if (*entry == stream) { *entry = (*entry)->next_; break; } } streams_empty_.store(streams_ == nullptr, std::memory_order_relaxed); UpdateMinLogSeverity(); } void LogMessage::ConfigureLogging(const char* params) { LoggingSeverity current_level = LS_VERBOSE; LoggingSeverity debug_level = GetLogToDebug(); std::vector tokens; tokenize(params, ' ', &tokens); for (const std::string& token : tokens) { if (token.empty()) continue; // Logging features if (token == "tstamp") { LogTimestamps(); } else if (token == "thread") { LogThreads(); // Logging levels } else if (token == "verbose") { current_level = LS_VERBOSE; } else if (token == "info") { current_level = LS_INFO; } else if (token == "warning") { current_level = LS_WARNING; } else if (token == "error") { current_level = LS_ERROR; } else if (token == "none") { current_level = LS_NONE; // Logging targets } else if (token == "debug") { debug_level = current_level; } } #if defined(WEBRTC_WIN) && !defined(WINUWP) if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) { // First, attempt to attach to our parent's console... so if you invoke // from the command line, we'll see the output there. Otherwise, create // our own console window. // Note: These methods fail if a console already exists, which is fine. if (!AttachConsole(ATTACH_PARENT_PROCESS)) ::AllocConsole(); } #endif // defined(WEBRTC_WIN) && !defined(WINUWP) LogToDebug(debug_level); } void LogMessage::UpdateMinLogSeverity() RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_mutex_) { LoggingSeverity min_sev = g_dbg_sev; for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) { min_sev = std::min(min_sev, entry->min_severity_); } g_min_sev = min_sev; } #if defined(WEBRTC_ANDROID) void LogMessage::OutputToDebug(const std::string& str, LoggingSeverity severity, const char* tag) { #else void LogMessage::OutputToDebug(const std::string& str, LoggingSeverity severity) { #endif bool log_to_stderr = log_to_stderr_; #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG) // On the Mac, all stderr output goes to the Console log and causes clutter. // So in opt builds, don't log to stderr unless the user specifically sets // a preference to do so. CFStringRef key = CFStringCreateWithCString( kCFAllocatorDefault, "logToStdErr", kCFStringEncodingUTF8); CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle()); if (key != nullptr && domain != nullptr) { Boolean exists_and_is_valid; Boolean should_log = CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid); // If the key doesn't exist or is invalid or is false, we will not log to // stderr. log_to_stderr = exists_and_is_valid && should_log; } if (key != nullptr) { CFRelease(key); } #endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG) #if defined(WEBRTC_WIN) // Always log to the debugger. // Perhaps stderr should be controlled by a preference, as on Mac? OutputDebugStringA(str.c_str()); if (log_to_stderr) { // This handles dynamically allocated consoles, too. if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) { log_to_stderr = false; DWORD written = 0; ::WriteFile(error_handle, str.data(), static_cast(str.size()), &written, 0); } } #endif // WEBRTC_WIN #if defined(WEBRTC_ANDROID) // Android's logging facility uses severity to log messages but we // need to map libjingle's severity levels to Android ones first. // Also write to stderr which maybe available to executable started // from the shell. int prio; switch (severity) { case LS_VERBOSE: prio = ANDROID_LOG_VERBOSE; break; case LS_INFO: prio = ANDROID_LOG_INFO; break; case LS_WARNING: prio = ANDROID_LOG_WARN; break; case LS_ERROR: prio = ANDROID_LOG_ERROR; break; default: prio = ANDROID_LOG_UNKNOWN; } int size = str.size(); int line = 0; int idx = 0; const int max_lines = size / kMaxLogLineSize + 1; if (max_lines == 1) { __android_log_print(prio, tag, "%.*s", size, str.c_str()); } else { while (size > 0) { const int len = std::min(size, kMaxLogLineSize); // Use the size of the string in the format (str may have \0 in the // middle). __android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len, str.c_str() + idx); idx += len; size -= len; ++line; } } #endif // WEBRTC_ANDROID if (log_to_stderr) { fprintf(stderr, "%s", str.c_str()); fflush(stderr); } } // static bool LogMessage::IsNoop(LoggingSeverity severity) { if (severity >= g_dbg_sev || severity >= g_min_sev) return false; return streams_empty_.load(std::memory_order_relaxed); } void LogMessage::FinishPrintStream() { if (!extra_.empty()) print_stream_ << " : " << extra_; print_stream_ << "\n"; } namespace webrtc_logging_impl { void Log(const LogArgType* fmt, ...) { va_list args; va_start(args, fmt); LogMetadataErr meta; const char* tag = nullptr; switch (*fmt) { case LogArgType::kLogMetadata: { meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0}; break; } case LogArgType::kLogMetadataErr: { meta = va_arg(args, LogMetadataErr); break; } #ifdef WEBRTC_ANDROID case LogArgType::kLogMetadataTag: { const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag); meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0}; tag = tag_meta.tag; break; } #endif default: { RTC_NOTREACHED(); va_end(args); return; } } LogMessage log_message(meta.meta.File(), meta.meta.Line(), meta.meta.Severity(), meta.err_ctx, meta.err); if (tag) { log_message.AddTag(tag); } for (++fmt; *fmt != LogArgType::kEnd; ++fmt) { switch (*fmt) { case LogArgType::kInt: log_message.stream() << va_arg(args, int); break; case LogArgType::kLong: log_message.stream() << va_arg(args, long); break; case LogArgType::kLongLong: log_message.stream() << va_arg(args, long long); break; case LogArgType::kUInt: log_message.stream() << va_arg(args, unsigned); break; case LogArgType::kULong: log_message.stream() << va_arg(args, unsigned long); break; case LogArgType::kULongLong: log_message.stream() << va_arg(args, unsigned long long); break; case LogArgType::kDouble: log_message.stream() << va_arg(args, double); break; case LogArgType::kLongDouble: log_message.stream() << va_arg(args, long double); break; case LogArgType::kCharP: { const char* s = va_arg(args, const char*); log_message.stream() << (s ? s : "(null)"); break; } case LogArgType::kStdString: log_message.stream() << *va_arg(args, const std::string*); break; case LogArgType::kStringView: log_message.stream() << *va_arg(args, const absl::string_view*); break; case LogArgType::kVoidP: log_message.stream() << rtc::ToHex( reinterpret_cast(va_arg(args, const void*))); break; default: RTC_NOTREACHED(); va_end(args); return; } } va_end(args); } } // namespace webrtc_logging_impl } // namespace rtc #endif namespace rtc { // Inefficient default implementation, override is recommended. void LogSink::OnLogMessage(const std::string& msg, LoggingSeverity severity, const char* tag) { OnLogMessage(tag + (": " + msg), severity); } void LogSink::OnLogMessage(const std::string& msg, LoggingSeverity /* severity */) { OnLogMessage(msg); } } // namespace rtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/logging.h0000664000175000017500000006127314475643423021546 0ustar00arunarun/* * Copyright 2004 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // RTC_LOG(...) an ostream target that can be used to send formatted // output to a variety of logging targets, such as debugger console, stderr, // or any LogSink. // The severity level passed as the first argument to the logging // functions is used as a filter, to limit the verbosity of the logging. // Static members of LogMessage documented below are used to control the // verbosity and target of the output. // There are several variations on the RTC_LOG macro which facilitate logging // of common error conditions, detailed below. // RTC_LOG(sev) logs the given stream at severity "sev", which must be a // compile-time constant of the LoggingSeverity type, without the namespace // prefix. // RTC_LOG_V(sev) Like RTC_LOG(), but sev is a run-time variable of the // LoggingSeverity type (basically, it just doesn't prepend the namespace). // RTC_LOG_F(sev) Like RTC_LOG(), but includes the name of the current function. // RTC_LOG_T(sev) Like RTC_LOG(), but includes the this pointer. // RTC_LOG_T_F(sev) Like RTC_LOG_F(), but includes the this pointer. // RTC_LOG_GLE(sev [, mod]) attempt to add a string description of the // HRESULT returned by GetLastError. // RTC_LOG_ERRNO(sev) attempts to add a string description of an errno-derived // error. errno and associated facilities exist on both Windows and POSIX, // but on Windows they only apply to the C/C++ runtime. // RTC_LOG_ERR(sev) is an alias for the platform's normal error system, i.e. // _GLE on Windows and _ERRNO on POSIX. // (The above three also all have _EX versions that let you specify the error // code, rather than using the last one.) // RTC_LOG_E(sev, ctx, err, ...) logs a detailed error interpreted using the // specified context. // RTC_LOG_CHECK_LEVEL(sev) (and RTC_LOG_CHECK_LEVEL_V(sev)) can be used as a // test before performing expensive or sensitive operations whose sole // purpose is to output logging data at the desired level. #ifndef RTC_BASE_LOGGING_H_ #define RTC_BASE_LOGGING_H_ #include #include #include // no-presubmit-check TODO(webrtc:8982) #include #include #include "absl/meta/type_traits.h" #include "absl/strings/string_view.h" #include "rtc_base/constructor_magic.h" #include "rtc_base/deprecation.h" #include "rtc_base/strings/string_builder.h" #include "rtc_base/system/inline.h" #if !defined(NDEBUG) || defined(DLOG_ALWAYS_ON) #define RTC_DLOG_IS_ON 1 #else #define RTC_DLOG_IS_ON 0 #endif #if defined(RTC_DISABLE_LOGGING) #define RTC_LOG_ENABLED() 0 #else #define RTC_LOG_ENABLED() 1 #endif namespace rtc { ////////////////////////////////////////////////////////////////////// // Note that the non-standard LoggingSeverity aliases exist because they are // still in broad use. The meanings of the levels are: // LS_VERBOSE: This level is for data which we do not want to appear in the // normal debug log, but should appear in diagnostic logs. // LS_INFO: Chatty level used in debugging for all sorts of things, the default // in debug builds. // LS_WARNING: Something that may warrant investigation. // LS_ERROR: Something that should not have occurred. // LS_NONE: Don't log. enum LoggingSeverity { LS_VERBOSE, LS_INFO, LS_WARNING, LS_ERROR, LS_NONE, INFO = LS_INFO, WARNING = LS_WARNING, LERROR = LS_ERROR }; // LogErrorContext assists in interpreting the meaning of an error value. enum LogErrorContext { ERRCTX_NONE, ERRCTX_ERRNO, // System-local errno ERRCTX_HRESULT, // Windows HRESULT // Abbreviations for LOG_E macro ERRCTX_EN = ERRCTX_ERRNO, // LOG_E(sev, EN, x) ERRCTX_HR = ERRCTX_HRESULT, // LOG_E(sev, HR, x) }; class LogMessage; // Virtual sink interface that can receive log messages. class LogSink { public: LogSink() {} virtual ~LogSink() {} virtual void OnLogMessage(const std::string& msg, LoggingSeverity severity, const char* tag); virtual void OnLogMessage(const std::string& message, LoggingSeverity severity); virtual void OnLogMessage(const std::string& message) = 0; private: friend class ::rtc::LogMessage; #if RTC_LOG_ENABLED() // Members for LogMessage class to keep linked list of the registered sinks. LogSink* next_ = nullptr; LoggingSeverity min_severity_; #endif }; namespace webrtc_logging_impl { class LogMetadata { public: LogMetadata(const char* file, int line, LoggingSeverity severity) : file_(file), line_and_sev_(static_cast(line) << 3 | severity) {} LogMetadata() = default; const char* File() const { return file_; } int Line() const { return line_and_sev_ >> 3; } LoggingSeverity Severity() const { return static_cast(line_and_sev_ & 0x7); } private: const char* file_; // Line number and severity, the former in the most significant 29 bits, the // latter in the least significant 3 bits. (This is an optimization; since // both numbers are usually compile-time constants, this way we can load them // both with a single instruction.) uint32_t line_and_sev_; }; static_assert(std::is_trivial::value, ""); struct LogMetadataErr { LogMetadata meta; LogErrorContext err_ctx; int err; }; #ifdef WEBRTC_ANDROID struct LogMetadataTag { LoggingSeverity severity; const char* tag; }; #endif enum class LogArgType : int8_t { kEnd = 0, kInt, kLong, kLongLong, kUInt, kULong, kULongLong, kDouble, kLongDouble, kCharP, kStdString, kStringView, kVoidP, kLogMetadata, kLogMetadataErr, #ifdef WEBRTC_ANDROID kLogMetadataTag, #endif }; // Wrapper for log arguments. Only ever make values of this type with the // MakeVal() functions. template struct Val { static constexpr LogArgType Type() { return N; } T GetVal() const { return val; } T val; }; // Case for when we need to construct a temp string and then print that. // (We can't use Val // because we need somewhere to store the temp string.) struct ToStringVal { static constexpr LogArgType Type() { return LogArgType::kStdString; } const std::string* GetVal() const { return &val; } std::string val; }; inline Val MakeVal(int x) { return {x}; } inline Val MakeVal(long x) { return {x}; } inline Val MakeVal(long long x) { return {x}; } inline Val MakeVal(unsigned int x) { return {x}; } inline Val MakeVal(unsigned long x) { return {x}; } inline Val MakeVal( unsigned long long x) { return {x}; } inline Val MakeVal(double x) { return {x}; } inline Val MakeVal(long double x) { return {x}; } inline Val MakeVal(const char* x) { return {x}; } inline Val MakeVal( const std::string& x) { return {&x}; } inline Val MakeVal( const absl::string_view& x) { return {&x}; } inline Val MakeVal(const void* x) { return {x}; } inline Val MakeVal( const LogMetadata& x) { return {x}; } inline Val MakeVal( const LogMetadataErr& x) { return {x}; } // The enum class types are not implicitly convertible to arithmetic types. template ::value && !std::is_arithmetic::value>* = nullptr> inline decltype(MakeVal(std::declval>())) MakeVal( T x) { return {static_cast>(x)}; } #ifdef WEBRTC_ANDROID inline Val MakeVal( const LogMetadataTag& x) { return {x}; } #endif template struct has_to_log_string : std::false_type {}; template struct has_to_log_string()))> : std::true_type {}; // Handle arbitrary types other than the above by falling back to stringstream. // TODO(bugs.webrtc.org/9278): Get rid of this overload when callers don't need // it anymore. No in-tree caller does, but some external callers still do. template < typename T, typename T1 = absl::decay_t, absl::enable_if_t::value && !std::is_same::value && !std::is_same::value && !has_to_log_string::value && #ifdef WEBRTC_ANDROID !std::is_same::value && #endif !std::is_same::value>* = nullptr> ToStringVal MakeVal(const T& x) { std::ostringstream os; // no-presubmit-check TODO(webrtc:8982) os << x; return {os.str()}; } template ::value>* = nullptr> ToStringVal MakeVal(const T& x) { return {ToLogString(x)}; } #if RTC_LOG_ENABLED() void Log(const LogArgType* fmt, ...); #else inline void Log(const LogArgType* fmt, ...) { // Do nothing, shouldn't be invoked } #endif // Ephemeral type that represents the result of the logging << operator. template class LogStreamer; // Base case: Before the first << argument. template <> class LogStreamer<> final { public: template ())), absl::enable_if_t::value || std::is_enum::value>* = nullptr> RTC_FORCE_INLINE LogStreamer operator<<(U arg) const { return LogStreamer(MakeVal(arg), this); } template ())), absl::enable_if_t::value && !std::is_enum::value>* = nullptr> RTC_FORCE_INLINE LogStreamer operator<<(const U& arg) const { return LogStreamer(MakeVal(arg), this); } template RTC_FORCE_INLINE static void Call(const Us&... args) { static constexpr LogArgType t[] = {Us::Type()..., LogArgType::kEnd}; Log(t, args.GetVal()...); } }; // Inductive case: We've already seen at least one << argument. The most recent // one had type `T`, and the earlier ones had types `Ts`. template class LogStreamer final { public: RTC_FORCE_INLINE LogStreamer(T arg, const LogStreamer* prior) : arg_(arg), prior_(prior) {} template ())), absl::enable_if_t::value || std::is_enum::value>* = nullptr> RTC_FORCE_INLINE LogStreamer operator<<(U arg) const { return LogStreamer(MakeVal(arg), this); } template ())), absl::enable_if_t::value && !std::is_enum::value>* = nullptr> RTC_FORCE_INLINE LogStreamer operator<<(const U& arg) const { return LogStreamer(MakeVal(arg), this); } template RTC_FORCE_INLINE void Call(const Us&... args) const { prior_->Call(arg_, args...); } private: // The most recent argument. T arg_; // Earlier arguments. const LogStreamer* prior_; }; class LogCall final { public: // This can be any binary operator with precedence lower than <<. // We return bool here to be able properly remove logging if // RTC_DISABLE_LOGGING is defined. template RTC_FORCE_INLINE bool operator&(const LogStreamer& streamer) { streamer.Call(); return true; } }; // This class is used to explicitly ignore values in the conditional // logging macros. This avoids compiler warnings like "value computed // is not used" and "statement has no effect". class LogMessageVoidify { public: LogMessageVoidify() = default; // This has to be an operator with a precedence lower than << but // higher than ?: template void operator&(LogStreamer&& streamer) {} }; } // namespace webrtc_logging_impl // Direct use of this class is deprecated; please use the logging macros // instead. // TODO(bugs.webrtc.org/9278): Move this class to an unnamed namespace in the // .cc file. class LogMessage { public: // Same as the above, but using a compile-time constant for the logging // severity. This saves space at the call site, since passing an empty struct // is generally the same as not passing an argument at all. template RTC_NO_INLINE LogMessage(const char* file, int line, std::integral_constant) : LogMessage(file, line, S) {} #if RTC_LOG_ENABLED() LogMessage(const char* file, int line, LoggingSeverity sev); LogMessage(const char* file, int line, LoggingSeverity sev, LogErrorContext err_ctx, int err); #if defined(WEBRTC_ANDROID) LogMessage(const char* file, int line, LoggingSeverity sev, const char* tag); #endif // DEPRECATED - DO NOT USE - PLEASE USE THE MACROS INSTEAD OF THE CLASS. // Android code should use the 'const char*' version since tags are static // and we want to avoid allocating a std::string copy per log line. RTC_DEPRECATED LogMessage(const char* file, int line, LoggingSeverity sev, const std::string& tag); ~LogMessage(); void AddTag(const char* tag); rtc::StringBuilder& stream(); // Returns the time at which this function was called for the first time. // The time will be used as the logging start time. // If this is not called externally, the LogMessage ctor also calls it, in // which case the logging start time will be the time of the first LogMessage // instance is created. static int64_t LogStartTime(); // Returns the wall clock equivalent of |LogStartTime|, in seconds from the // epoch. static uint32_t WallClockStartTime(); // LogThreads: Display the thread identifier of the current thread static void LogThreads(bool on = true); // LogTimestamps: Display the elapsed time of the program static void LogTimestamps(bool on = true); // These are the available logging channels // Debug: Debug console on Windows, otherwise stderr static void LogToDebug(LoggingSeverity min_sev); static LoggingSeverity GetLogToDebug(); // Sets whether logs will be directed to stderr in debug mode. static void SetLogToStderr(bool log_to_stderr); // Stream: Any non-blocking stream interface. // Installs the |stream| to collect logs with severtiy |min_sev| or higher. // |stream| must live until deinstalled by RemoveLogToStream. // If |stream| is the first stream added to the system, we might miss some // early concurrent log statement happening from another thread happening near // this instant. static void AddLogToStream(LogSink* stream, LoggingSeverity min_sev); // Removes the specified stream, without destroying it. When the method // has completed, it's guaranteed that |stream| will receive no more logging // calls. static void RemoveLogToStream(LogSink* stream); // Returns the severity for the specified stream, of if none is specified, // the minimum stream severity. static int GetLogToStream(LogSink* stream = nullptr); // Testing against MinLogSeverity allows code to avoid potentially expensive // logging operations by pre-checking the logging level. static int GetMinLogSeverity(); // Parses the provided parameter stream to configure the options above. // Useful for configuring logging from the command line. static void ConfigureLogging(const char* params); // Checks the current global debug severity and if the |streams_| collection // is empty. If |severity| is smaller than the global severity and if the // |streams_| collection is empty, the LogMessage will be considered a noop // LogMessage. static bool IsNoop(LoggingSeverity severity); // Version of IsNoop that uses fewer instructions at the call site, since the // caller doesn't have to pass an argument. template RTC_NO_INLINE static bool IsNoop() { return IsNoop(S); } #else // Next methods do nothing; no one will call these functions. LogMessage(const char* file, int line, LoggingSeverity sev) {} LogMessage(const char* file, int line, LoggingSeverity sev, LogErrorContext err_ctx, int err) {} #if defined(WEBRTC_ANDROID) LogMessage(const char* file, int line, LoggingSeverity sev, const char* tag) { } #endif // DEPRECATED - DO NOT USE - PLEASE USE THE MACROS INSTEAD OF THE CLASS. // Android code should use the 'const char*' version since tags are static // and we want to avoid allocating a std::string copy per log line. RTC_DEPRECATED LogMessage(const char* file, int line, LoggingSeverity sev, const std::string& tag) {} ~LogMessage() = default; inline void AddTag(const char* tag) {} inline rtc::StringBuilder& stream() { return print_stream_; } inline static int64_t LogStartTime() { return 0; } inline static uint32_t WallClockStartTime() { return 0; } inline static void LogThreads(bool on = true) {} inline static void LogTimestamps(bool on = true) {} inline static void LogToDebug(LoggingSeverity min_sev) {} inline static LoggingSeverity GetLogToDebug() { return LoggingSeverity::LS_INFO; } inline static void SetLogToStderr(bool log_to_stderr) {} inline static void AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {} inline static void RemoveLogToStream(LogSink* stream) {} inline static int GetLogToStream(LogSink* stream = nullptr) { return 0; } inline static int GetMinLogSeverity() { return 0; } inline static void ConfigureLogging(const char* params) {} static constexpr bool IsNoop(LoggingSeverity severity) { return true; } template static constexpr bool IsNoop() { return IsNoop(S); } #endif // RTC_LOG_ENABLED() private: friend class LogMessageForTesting; #if RTC_LOG_ENABLED() // Updates min_sev_ appropriately when debug sinks change. static void UpdateMinLogSeverity(); // These write out the actual log messages. #if defined(WEBRTC_ANDROID) static void OutputToDebug(const std::string& msg, LoggingSeverity severity, const char* tag); #else static void OutputToDebug(const std::string& msg, LoggingSeverity severity); #endif // defined(WEBRTC_ANDROID) // Called from the dtor (or from a test) to append optional extra error // information to the log stream and a newline character. void FinishPrintStream(); // The severity level of this message LoggingSeverity severity_; #if defined(WEBRTC_ANDROID) // The default Android debug output tag. const char* tag_ = "libjingle"; #endif // String data generated in the constructor, that should be appended to // the message before output. std::string extra_; // The output streams and their associated severities static LogSink* streams_; // Holds true with high probability if |streams_| is empty, false with high // probability otherwise. Operated on with std::memory_order_relaxed because // it's ok to lose or log some additional statements near the instant streams // are added/removed. static std::atomic streams_empty_; // Flags for formatting options static bool thread_, timestamp_; // Determines if logs will be directed to stderr in debug mode. static bool log_to_stderr_; #else // RTC_LOG_ENABLED() // Next methods do nothing; no one will call these functions. inline static void UpdateMinLogSeverity() {} #if defined(WEBRTC_ANDROID) inline static void OutputToDebug(const std::string& msg, LoggingSeverity severity, const char* tag) {} #else inline static void OutputToDebug(const std::string& msg, LoggingSeverity severity) {} #endif // defined(WEBRTC_ANDROID) inline void FinishPrintStream() {} #endif // RTC_LOG_ENABLED() // The stringbuilder that buffers the formatted message before output rtc::StringBuilder print_stream_; RTC_DISALLOW_COPY_AND_ASSIGN(LogMessage); }; ////////////////////////////////////////////////////////////////////// // Logging Helpers ////////////////////////////////////////////////////////////////////// #define RTC_LOG_FILE_LINE(sev, file, line) \ ::rtc::webrtc_logging_impl::LogCall() & \ ::rtc::webrtc_logging_impl::LogStreamer<>() \ << ::rtc::webrtc_logging_impl::LogMetadata(file, line, sev) #define RTC_LOG(sev) \ !rtc::LogMessage::IsNoop<::rtc::sev>() && \ RTC_LOG_FILE_LINE(::rtc::sev, __FILE__, __LINE__) // The _V version is for when a variable is passed in. #define RTC_LOG_V(sev) \ !rtc::LogMessage::IsNoop(sev) && RTC_LOG_FILE_LINE(sev, __FILE__, __LINE__) // The _F version prefixes the message with the current function name. #if (defined(__GNUC__) && !defined(NDEBUG)) || defined(WANT_PRETTY_LOG_F) #define RTC_LOG_F(sev) RTC_LOG(sev) << __PRETTY_FUNCTION__ << ": " #define RTC_LOG_T_F(sev) \ RTC_LOG(sev) << this << ": " << __PRETTY_FUNCTION__ << ": " #else #define RTC_LOG_F(sev) RTC_LOG(sev) << __FUNCTION__ << ": " #define RTC_LOG_T_F(sev) RTC_LOG(sev) << this << ": " << __FUNCTION__ << ": " #endif #define RTC_LOG_CHECK_LEVEL(sev) ::rtc::LogCheckLevel(::rtc::sev) #define RTC_LOG_CHECK_LEVEL_V(sev) ::rtc::LogCheckLevel(sev) inline bool LogCheckLevel(LoggingSeverity sev) { return (LogMessage::GetMinLogSeverity() <= sev); } #define RTC_LOG_E(sev, ctx, err) \ !rtc::LogMessage::IsNoop<::rtc::sev>() && \ ::rtc::webrtc_logging_impl::LogCall() & \ ::rtc::webrtc_logging_impl::LogStreamer<>() \ << ::rtc::webrtc_logging_impl::LogMetadataErr { \ {__FILE__, __LINE__, ::rtc::sev}, ::rtc::ERRCTX_##ctx, (err) \ } #define RTC_LOG_T(sev) RTC_LOG(sev) << this << ": " #define RTC_LOG_ERRNO_EX(sev, err) RTC_LOG_E(sev, ERRNO, err) #define RTC_LOG_ERRNO(sev) RTC_LOG_ERRNO_EX(sev, errno) #if defined(WEBRTC_WIN) #define RTC_LOG_GLE_EX(sev, err) RTC_LOG_E(sev, HRESULT, err) #define RTC_LOG_GLE(sev) RTC_LOG_GLE_EX(sev, static_cast(GetLastError())) #define RTC_LOG_ERR_EX(sev, err) RTC_LOG_GLE_EX(sev, err) #define RTC_LOG_ERR(sev) RTC_LOG_GLE(sev) #elif defined(__native_client__) && __native_client__ #define RTC_LOG_ERR_EX(sev, err) RTC_LOG(sev) #define RTC_LOG_ERR(sev) RTC_LOG(sev) #elif defined(WEBRTC_POSIX) #define RTC_LOG_ERR_EX(sev, err) RTC_LOG_ERRNO_EX(sev, err) #define RTC_LOG_ERR(sev) RTC_LOG_ERRNO(sev) #endif // WEBRTC_WIN #ifdef WEBRTC_ANDROID namespace webrtc_logging_impl { // TODO(kwiberg): Replace these with absl::string_view. inline const char* AdaptString(const char* str) { return str; } inline const char* AdaptString(const std::string& str) { return str.c_str(); } } // namespace webrtc_logging_impl #define RTC_LOG_TAG(sev, tag) \ !rtc::LogMessage::IsNoop(sev) && \ ::rtc::webrtc_logging_impl::LogCall() & \ ::rtc::webrtc_logging_impl::LogStreamer<>() \ << ::rtc::webrtc_logging_impl::LogMetadataTag { \ sev, ::rtc::webrtc_logging_impl::AdaptString(tag) \ } #else // DEPRECATED. This macro is only intended for Android. #define RTC_LOG_TAG(sev, tag) RTC_LOG_V(sev) #endif // The RTC_DLOG macros are equivalent to their RTC_LOG counterparts except that // they only generate code in debug builds. #if RTC_DLOG_IS_ON #define RTC_DLOG(sev) RTC_LOG(sev) #define RTC_DLOG_V(sev) RTC_LOG_V(sev) #define RTC_DLOG_F(sev) RTC_LOG_F(sev) #else #define RTC_DLOG_EAT_STREAM_PARAMS() \ while (false) \ ::rtc::webrtc_logging_impl::LogMessageVoidify() & \ (::rtc::webrtc_logging_impl::LogStreamer<>()) #define RTC_DLOG(sev) RTC_DLOG_EAT_STREAM_PARAMS() #define RTC_DLOG_V(sev) RTC_DLOG_EAT_STREAM_PARAMS() #define RTC_DLOG_F(sev) RTC_DLOG_EAT_STREAM_PARAMS() #endif } // namespace rtc #endif // RTC_BASE_LOGGING_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/memory/0000775000175000017500000000000014475643423021246 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/memory/BUILD.gn0000664000175000017500000000254214475643423022436 0ustar00arunarun# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../../webrtc.gni") if (is_android) { import("//build/config/android/config.gni") import("//build/config/android/rules.gni") } rtc_library("aligned_malloc") { sources = [ "aligned_malloc.cc", "aligned_malloc.h", ] deps = [ "..:checks" ] } # Test only utility. # TODO: Tag with `testonly = true` once all depending targets are correctly # tagged. rtc_library("fifo_buffer") { visibility = [ ":unittests", "..:rtc_base_tests_utils", "..:rtc_base_unittests", "../../p2p:rtc_p2p", # This needs to be fixed. ] sources = [ "fifo_buffer.cc", "fifo_buffer.h", ] deps = [ "..:rtc_base", "../synchronization:mutex", "../task_utils:pending_task_safety_flag", "../task_utils:to_queued_task", ] } rtc_library("unittests") { testonly = true sources = [ "aligned_malloc_unittest.cc", "fifo_buffer_unittest.cc", ] deps = [ ":aligned_malloc", ":fifo_buffer", "../../test:test_support", ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/memory/aligned_malloc.cc0000664000175000017500000000632614475643423024516 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/memory/aligned_malloc.h" #include // for free, malloc #include // for memcpy #include "rtc_base/checks.h" #ifdef _WIN32 #include #else #include #endif // Reference on memory alignment: // http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me namespace webrtc { uintptr_t GetRightAlign(uintptr_t start_pos, size_t alignment) { // The pointer should be aligned with |alignment| bytes. The - 1 guarantees // that it is aligned towards the closest higher (right) address. return (start_pos + alignment - 1) & ~(alignment - 1); } // Alignment must be an integer power of two. bool ValidAlignment(size_t alignment) { if (!alignment) { return false; } return (alignment & (alignment - 1)) == 0; } void* GetRightAlign(const void* pointer, size_t alignment) { if (!pointer) { return NULL; } if (!ValidAlignment(alignment)) { return NULL; } uintptr_t start_pos = reinterpret_cast(pointer); return reinterpret_cast(GetRightAlign(start_pos, alignment)); } void* AlignedMalloc(size_t size, size_t alignment) { if (size == 0) { return NULL; } if (!ValidAlignment(alignment)) { return NULL; } // The memory is aligned towards the lowest address that so only // alignment - 1 bytes needs to be allocated. // A pointer to the start of the memory must be stored so that it can be // retreived for deletion, ergo the sizeof(uintptr_t). void* memory_pointer = malloc(size + sizeof(uintptr_t) + alignment - 1); RTC_CHECK(memory_pointer) << "Couldn't allocate memory in AlignedMalloc"; // Aligning after the sizeof(uintptr_t) bytes will leave room for the header // in the same memory block. uintptr_t align_start_pos = reinterpret_cast(memory_pointer); align_start_pos += sizeof(uintptr_t); uintptr_t aligned_pos = GetRightAlign(align_start_pos, alignment); void* aligned_pointer = reinterpret_cast(aligned_pos); // Store the address to the beginning of the memory just before the aligned // memory. uintptr_t header_pos = aligned_pos - sizeof(uintptr_t); void* header_pointer = reinterpret_cast(header_pos); uintptr_t memory_start = reinterpret_cast(memory_pointer); memcpy(header_pointer, &memory_start, sizeof(uintptr_t)); return aligned_pointer; } void AlignedFree(void* mem_block) { if (mem_block == NULL) { return; } uintptr_t aligned_pos = reinterpret_cast(mem_block); uintptr_t header_pos = aligned_pos - sizeof(uintptr_t); // Read out the address of the AlignedMemory struct from the header. uintptr_t memory_start_pos = *reinterpret_cast(header_pos); void* memory_start = reinterpret_cast(memory_start_pos); free(memory_start); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/memory/aligned_malloc.h0000664000175000017500000000403014475643423024346 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_MEMORY_ALIGNED_MALLOC_H_ #define RTC_BASE_MEMORY_ALIGNED_MALLOC_H_ // The functions declared here // 1) Allocates block of aligned memory. // 2) Re-calculates a pointer such that it is aligned to a higher or equal // address. // Note: alignment must be a power of two. The alignment is in bytes. #include namespace webrtc { // Returns a pointer to the first boundry of |alignment| bytes following the // address of |ptr|. // Note that there is no guarantee that the memory in question is available. // |ptr| has no requirements other than it can't be NULL. void* GetRightAlign(const void* ptr, size_t alignment); // Allocates memory of |size| bytes aligned on an |alignment| boundry. // The return value is a pointer to the memory. Note that the memory must // be de-allocated using AlignedFree. void* AlignedMalloc(size_t size, size_t alignment); // De-allocates memory created using the AlignedMalloc() API. void AlignedFree(void* mem_block); // Templated versions to facilitate usage of aligned malloc without casting // to and from void*. template T* GetRightAlign(const T* ptr, size_t alignment) { return reinterpret_cast( GetRightAlign(reinterpret_cast(ptr), alignment)); } template T* AlignedMalloc(size_t size, size_t alignment) { return reinterpret_cast(AlignedMalloc(size, alignment)); } // Deleter for use with unique_ptr. E.g., use as // std::unique_ptr foo; struct AlignedFreeDeleter { inline void operator()(void* ptr) const { AlignedFree(ptr); } }; } // namespace webrtc #endif // RTC_BASE_MEMORY_ALIGNED_MALLOC_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/meson.build0000664000175000017500000000324714475643423022106 0ustar00arunarunbase_sources = [ 'checks.cc', 'event.cc', 'event_tracer.cc', 'experiments/field_trial_parser.cc', 'logging.cc', 'memory/aligned_malloc.cc', 'platform_thread.cc', 'platform_thread_types.cc', 'race_checker.cc', 'string_encode.cc', 'string_to_number.cc', 'string_utils.cc', 'strings/string_builder.cc', 'synchronization/mutex.cc', 'synchronization/rw_lock_wrapper.cc', 'synchronization/yield.cc', 'synchronization/yield_policy.cc', 'system/file_wrapper.cc', 'time_utils.cc', 'zero_memory.cc', ] base_headers = [ [ '', 'arraysize.h' ], [ '', 'checks.h' ], [ '', 'constructor_magic.h' ], [ '', 'deprecation.h' ], [ '', 'ref_count.h' ], [ '', 'type_traits.h' ], [ 'numerics', 'safe_compare.h' ], [ 'system', 'file_wrapper.h' ], [ 'system', 'inline.h' ], [ 'system', 'rtc_export.h' ], ] if have_posix base_sources += [ 'synchronization/rw_lock_posix.cc', ] elif have_win base_sources += [ 'synchronization/rw_lock_win.cc', ] endif foreach h : base_headers install_headers( join_paths(h[0], h[1]), subdir: join_paths(include_subdir, 'rtc_base', h[0]) ) endforeach base_os_deps = [] if host_system == 'darwin' base_os_deps += dependency('appleframeworks', modules: [ 'Foundation' ]) elif host_system == 'ios' base_os_deps += dependency('appleframeworks', modules: [ 'CFNetwork', 'Foundation', 'Security', 'SystemConfiguration', 'UIKit', ] ) endif libbase = static_library('libbase', base_sources, dependencies: common_deps + base_os_deps, include_directories: webrtc_inc, cpp_args : common_cxxflags ) base_dep = declare_dependency( link_with: libbase ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/numerics/0000775000175000017500000000000014475643423021563 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/numerics/safe_compare.h0000664000175000017500000001475014475643423024367 0ustar00arunarun/* * Copyright 2016 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // This file defines six constexpr functions: // // rtc::SafeEq // == // rtc::SafeNe // != // rtc::SafeLt // < // rtc::SafeLe // <= // rtc::SafeGt // > // rtc::SafeGe // >= // // They each accept two arguments of arbitrary types, and in almost all cases, // they simply call the appropriate comparison operator. However, if both // arguments are integers, they don't compare them using C++'s quirky rules, // but instead adhere to the true mathematical definitions. It is as if the // arguments were first converted to infinite-range signed integers, and then // compared, although of course nothing expensive like that actually takes // place. In practice, for signed/signed and unsigned/unsigned comparisons and // some mixed-signed comparisons with a compile-time constant, the overhead is // zero; in the remaining cases, it is just a few machine instructions (no // branches). #ifndef RTC_BASE_NUMERICS_SAFE_COMPARE_H_ #define RTC_BASE_NUMERICS_SAFE_COMPARE_H_ #include #include #include #include #include "rtc_base/type_traits.h" namespace rtc { namespace safe_cmp_impl { template struct LargerIntImpl : std::false_type {}; template <> struct LargerIntImpl : std::true_type { using type = int16_t; }; template <> struct LargerIntImpl : std::true_type { using type = int32_t; }; template <> struct LargerIntImpl : std::true_type { using type = int64_t; }; // LargerInt::value is true iff there's a signed type that's larger // than T1 (and no larger than the larger of T2 and int*, for performance // reasons); and if there is such a type, LargerInt::type is an alias // for it. template struct LargerInt : LargerIntImpl {}; template constexpr typename std::make_unsigned::type MakeUnsigned(T a) { return static_cast::type>(a); } // Overload for when both T1 and T2 have the same signedness. template ::value == std::is_signed::value>::type* = nullptr> constexpr bool Cmp(T1 a, T2 b) { return Op::Op(a, b); } // Overload for signed - unsigned comparison that can be promoted to a bigger // signed type. template ::value && std::is_unsigned::value && LargerInt::value>::type* = nullptr> constexpr bool Cmp(T1 a, T2 b) { return Op::Op(a, static_cast::type>(b)); } // Overload for unsigned - signed comparison that can be promoted to a bigger // signed type. template ::value && std::is_signed::value && LargerInt::value>::type* = nullptr> constexpr bool Cmp(T1 a, T2 b) { return Op::Op(static_cast::type>(a), b); } // Overload for signed - unsigned comparison that can't be promoted to a bigger // signed type. template ::value && std::is_unsigned::value && !LargerInt::value>::type* = nullptr> constexpr bool Cmp(T1 a, T2 b) { return a < 0 ? Op::Op(-1, 0) : Op::Op(safe_cmp_impl::MakeUnsigned(a), b); } // Overload for unsigned - signed comparison that can't be promoted to a bigger // signed type. template ::value && std::is_signed::value && !LargerInt::value>::type* = nullptr> constexpr bool Cmp(T1 a, T2 b) { return b < 0 ? Op::Op(0, -1) : Op::Op(a, safe_cmp_impl::MakeUnsigned(b)); } #define RTC_SAFECMP_MAKE_OP(name, op) \ struct name { \ template \ static constexpr bool Op(T1 a, T2 b) { \ return a op b; \ } \ }; RTC_SAFECMP_MAKE_OP(EqOp, ==) RTC_SAFECMP_MAKE_OP(NeOp, !=) RTC_SAFECMP_MAKE_OP(LtOp, <) RTC_SAFECMP_MAKE_OP(LeOp, <=) RTC_SAFECMP_MAKE_OP(GtOp, >) RTC_SAFECMP_MAKE_OP(GeOp, >=) #undef RTC_SAFECMP_MAKE_OP } // namespace safe_cmp_impl #define RTC_SAFECMP_MAKE_FUN(name) \ template \ constexpr \ typename std::enable_if::value && IsIntlike::value, \ bool>::type Safe##name(T1 a, T2 b) { \ /* Unary plus here turns enums into real integral types. */ \ return safe_cmp_impl::Cmp(+a, +b); \ } \ template \ constexpr \ typename std::enable_if::value || !IsIntlike::value, \ bool>::type Safe##name(const T1& a, \ const T2& b) { \ return safe_cmp_impl::name##Op::Op(a, b); \ } RTC_SAFECMP_MAKE_FUN(Eq) RTC_SAFECMP_MAKE_FUN(Ne) RTC_SAFECMP_MAKE_FUN(Lt) RTC_SAFECMP_MAKE_FUN(Le) RTC_SAFECMP_MAKE_FUN(Gt) RTC_SAFECMP_MAKE_FUN(Ge) #undef RTC_SAFECMP_MAKE_FUN } // namespace rtc #endif // RTC_BASE_NUMERICS_SAFE_COMPARE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/numerics/safe_conversions.h0000664000175000017500000000505214475643423025304 0ustar00arunarun/* * Copyright 2014 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Borrowed from Chromium's src/base/numerics/safe_conversions.h. #ifndef RTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_ #define RTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_ #include #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_conversions_impl.h" namespace rtc { // Convenience function that returns true if the supplied value is in range // for the destination type. template inline constexpr bool IsValueInRangeForNumericType(Src value) { return internal::RangeCheck(value) == internal::TYPE_VALID; } // checked_cast<> and dchecked_cast<> are analogous to static_cast<> for // numeric types, except that they [D]CHECK that the specified numeric // conversion will not overflow or underflow. NaN source will always trigger // the [D]CHECK. template inline constexpr Dst checked_cast(Src value) { RTC_CHECK(IsValueInRangeForNumericType(value)); return static_cast(value); } template inline constexpr Dst dchecked_cast(Src value) { RTC_DCHECK(IsValueInRangeForNumericType(value)); return static_cast(value); } // saturated_cast<> is analogous to static_cast<> for numeric types, except // that the specified numeric conversion will saturate rather than overflow or // underflow. NaN assignment to an integral will trigger a RTC_CHECK condition. template inline constexpr Dst saturated_cast(Src value) { // Optimization for floating point values, which already saturate. if (std::numeric_limits::is_iec559) return static_cast(value); switch (internal::RangeCheck(value)) { case internal::TYPE_VALID: return static_cast(value); case internal::TYPE_UNDERFLOW: return std::numeric_limits::min(); case internal::TYPE_OVERFLOW: return std::numeric_limits::max(); // Should fail only on attempting to assign NaN to a saturated integer. case internal::TYPE_INVALID: FATAL(); return std::numeric_limits::max(); } FATAL(); return static_cast(value); } } // namespace rtc #endif // RTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/numerics/safe_conversions_impl.h0000664000175000017500000001573314475643423026334 0ustar00arunarun/* * Copyright 2014 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Borrowed from Chromium's src/base/numerics/safe_conversions_impl.h. #ifndef RTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ #define RTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ #include namespace rtc { namespace internal { enum DstSign { DST_UNSIGNED, DST_SIGNED }; enum SrcSign { SRC_UNSIGNED, SRC_SIGNED }; enum DstRange { OVERLAPS_RANGE, CONTAINS_RANGE }; // Helper templates to statically determine if our destination type can contain // all values represented by the source type. template ::is_signed ? DST_SIGNED : DST_UNSIGNED, SrcSign IsSrcSigned = std::numeric_limits::is_signed ? SRC_SIGNED : SRC_UNSIGNED> struct StaticRangeCheck {}; template struct StaticRangeCheck { typedef std::numeric_limits DstLimits; typedef std::numeric_limits SrcLimits; // Compare based on max_exponent, which we must compute for integrals. static const size_t kDstMaxExponent = DstLimits::is_iec559 ? DstLimits::max_exponent : (sizeof(Dst) * 8 - 1); static const size_t kSrcMaxExponent = SrcLimits::is_iec559 ? SrcLimits::max_exponent : (sizeof(Src) * 8 - 1); static const DstRange value = kDstMaxExponent >= kSrcMaxExponent ? CONTAINS_RANGE : OVERLAPS_RANGE; }; template struct StaticRangeCheck { static const DstRange value = sizeof(Dst) >= sizeof(Src) ? CONTAINS_RANGE : OVERLAPS_RANGE; }; template struct StaticRangeCheck { typedef std::numeric_limits DstLimits; typedef std::numeric_limits SrcLimits; // Compare based on max_exponent, which we must compute for integrals. static const size_t kDstMaxExponent = DstLimits::is_iec559 ? DstLimits::max_exponent : (sizeof(Dst) * 8 - 1); static const size_t kSrcMaxExponent = sizeof(Src) * 8; static const DstRange value = kDstMaxExponent >= kSrcMaxExponent ? CONTAINS_RANGE : OVERLAPS_RANGE; }; template struct StaticRangeCheck { static const DstRange value = OVERLAPS_RANGE; }; enum RangeCheckResult { TYPE_VALID = 0, // Value can be represented by the destination type. TYPE_UNDERFLOW = 1, // Value would overflow. TYPE_OVERFLOW = 2, // Value would underflow. TYPE_INVALID = 3 // Source value is invalid (i.e. NaN). }; // This macro creates a RangeCheckResult from an upper and lower bound // check by taking advantage of the fact that only NaN can be out of range in // both directions at once. #define BASE_NUMERIC_RANGE_CHECK_RESULT(is_in_upper_bound, is_in_lower_bound) \ RangeCheckResult(((is_in_upper_bound) ? 0 : TYPE_OVERFLOW) | \ ((is_in_lower_bound) ? 0 : TYPE_UNDERFLOW)) template ::is_signed ? DST_SIGNED : DST_UNSIGNED, SrcSign IsSrcSigned = std::numeric_limits::is_signed ? SRC_SIGNED : SRC_UNSIGNED, DstRange IsSrcRangeContained = StaticRangeCheck::value> struct RangeCheckImpl {}; // The following templates are for ranges that must be verified at runtime. We // split it into checks based on signedness to avoid confusing casts and // compiler warnings on signed an unsigned comparisons. // Dst range always contains the result: nothing to check. template struct RangeCheckImpl { static constexpr RangeCheckResult Check(Src value) { return TYPE_VALID; } }; // Signed to signed narrowing. template struct RangeCheckImpl { static constexpr RangeCheckResult Check(Src value) { typedef std::numeric_limits DstLimits; return DstLimits::is_iec559 ? BASE_NUMERIC_RANGE_CHECK_RESULT( value <= static_cast(DstLimits::max()), value >= static_cast(DstLimits::max() * -1)) : BASE_NUMERIC_RANGE_CHECK_RESULT( value <= static_cast(DstLimits::max()), value >= static_cast(DstLimits::min())); } }; // Unsigned to unsigned narrowing. template struct RangeCheckImpl { static constexpr RangeCheckResult Check(Src value) { typedef std::numeric_limits DstLimits; return BASE_NUMERIC_RANGE_CHECK_RESULT( value <= static_cast(DstLimits::max()), true); } }; // Unsigned to signed. template struct RangeCheckImpl { static constexpr RangeCheckResult Check(Src value) { typedef std::numeric_limits DstLimits; return sizeof(Dst) > sizeof(Src) ? TYPE_VALID : BASE_NUMERIC_RANGE_CHECK_RESULT( value <= static_cast(DstLimits::max()), true); } }; // Signed to unsigned. template struct RangeCheckImpl { typedef std::numeric_limits DstLimits; typedef std::numeric_limits SrcLimits; // Compare based on max_exponent, which we must compute for integrals. static constexpr size_t DstMaxExponent() { return sizeof(Dst) * 8; } static constexpr size_t SrcMaxExponent() { return SrcLimits::is_iec559 ? SrcLimits::max_exponent : (sizeof(Src) * 8 - 1); } static constexpr RangeCheckResult Check(Src value) { return (DstMaxExponent() >= SrcMaxExponent()) ? BASE_NUMERIC_RANGE_CHECK_RESULT(true, value >= static_cast(0)) : BASE_NUMERIC_RANGE_CHECK_RESULT( value <= static_cast(DstLimits::max()), value >= static_cast(0)); } }; template inline constexpr RangeCheckResult RangeCheck(Src value) { static_assert(std::numeric_limits::is_specialized, "argument must be numeric"); static_assert(std::numeric_limits::is_specialized, "result must be numeric"); return RangeCheckImpl::Check(value); } } // namespace internal } // namespace rtc #endif // RTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/numerics/safe_minmax.h0000664000175000017500000003260414475643423024230 0ustar00arunarun/* * Copyright 2017 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Minimum and maximum // =================== // // rtc::SafeMin(x, y) // rtc::SafeMax(x, y) // // (These are both constexpr.) // // Accept two arguments of either any two integral or any two floating-point // types, and return the smaller and larger value, respectively, with no // truncation or wrap-around. If only one of the input types is statically // guaranteed to be able to represent the result, the return type is that type; // if either one would do, the result type is the smaller type. (One of these // two cases always applies.) // // * The case with one floating-point and one integral type is not allowed, // because the floating-point type will have greater range, but may not // have sufficient precision to represent the integer value exactly.) // // Clamp (a.k.a. constrain to a given interval) // ============================================ // // rtc::SafeClamp(x, a, b) // // Accepts three arguments of any mix of integral types or any mix of // floating-point types, and returns the value in the closed interval [a, b] // that is closest to x (that is, if x < a it returns a; if x > b it returns b; // and if a <= x <= b it returns x). As for SafeMin() and SafeMax(), there is // no truncation or wrap-around. The result type // // 1. is statically guaranteed to be able to represent the result; // // 2. is no larger than the largest of the three argument types; and // // 3. has the same signedness as the type of the first argument, if this is // possible without violating the First or Second Law. // // There is always at least one type that meets criteria 1 and 2. If more than // one type meets these criteria equally well, the result type is one of the // types that is smallest. Note that unlike SafeMin() and SafeMax(), // SafeClamp() will sometimes pick a return type that isn't the type of any of // its arguments. // // * In this context, a type A is smaller than a type B if it has a smaller // range; that is, if A::max() - A::min() < B::max() - B::min(). For // example, int8_t < int16_t == uint16_t < int32_t, and all integral types // are smaller than all floating-point types.) // // * As for SafeMin and SafeMax, mixing integer and floating-point arguments // is not allowed, because floating-point types have greater range than // integer types, but do not have sufficient precision to represent the // values of most integer types exactly. // // Requesting a specific return type // ================================= // // All three functions allow callers to explicitly specify the return type as a // template parameter, overriding the default return type. E.g. // // rtc::SafeMin(x, y) // returns an int // // If the requested type is statically guaranteed to be able to represent the // result, then everything's fine, and the return type is as requested. But if // the requested type is too small, a static_assert is triggered. #ifndef RTC_BASE_NUMERICS_SAFE_MINMAX_H_ #define RTC_BASE_NUMERICS_SAFE_MINMAX_H_ #include #include #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_compare.h" #include "rtc_base/type_traits.h" namespace rtc { namespace safe_minmax_impl { // Make the range of a type available via something other than a constexpr // function, to work around MSVC limitations. See // https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ template struct Limits { static constexpr T lowest = std::numeric_limits::lowest(); static constexpr T max = std::numeric_limits::max(); }; template ::value> struct UnderlyingType; template struct UnderlyingType { using type = T; }; template struct UnderlyingType { using type = typename std::underlying_type::type; }; // Given two types T1 and T2, find types that can hold the smallest (in // ::min_t) and the largest (in ::max_t) of the two values. template ::value, bool int2 = IsIntlike::value> struct MType { static_assert(int1 == int2, "You may not mix integral and floating-point arguments"); }; // Specialization for when neither type is integral (and therefore presumably // floating-point). template struct MType { using min_t = typename std::common_type::type; static_assert(std::is_same::value || std::is_same::value, ""); using max_t = typename std::common_type::type; static_assert(std::is_same::value || std::is_same::value, ""); }; // Specialization for when both types are integral. template struct MType { // The type with the lowest minimum value. In case of a tie, the type with // the lowest maximum value. In case that too is a tie, the types have the // same range, and we arbitrarily pick T1. using min_t = typename std::conditional< SafeLt(Limits::lowest, Limits::lowest), T1, typename std::conditional< SafeGt(Limits::lowest, Limits::lowest), T2, typename std::conditional::max, Limits::max), T1, T2>::type>::type>::type; static_assert(std::is_same::value || std::is_same::value, ""); // The type with the highest maximum value. In case of a tie, the types have // the same range (because in C++, integer types with the same maximum also // have the same minimum). static_assert(SafeNe(Limits::max, Limits::max) || SafeEq(Limits::lowest, Limits::lowest), "integer types with the same max should have the same min"); using max_t = typename std:: conditional::max, Limits::max), T1, T2>::type; static_assert(std::is_same::value || std::is_same::value, ""); }; // A dummy type that we pass around at compile time but never actually use. // Declared but not defined. struct DefaultType; // ::type is A, except we fall back to B if A is DefaultType. We static_assert // that the chosen type can hold all values that B can hold. template struct TypeOr { using type = typename std:: conditional::value, B, A>::type; static_assert(SafeLe(Limits::lowest, Limits::lowest) && SafeGe(Limits::max, Limits::max), "The specified type isn't large enough"); static_assert(IsIntlike::value == IsIntlike::value && std::is_floating_point::value == std::is_floating_point::value, "float<->int conversions not allowed"); }; } // namespace safe_minmax_impl template < typename R = safe_minmax_impl::DefaultType, typename T1 = safe_minmax_impl::DefaultType, typename T2 = safe_minmax_impl::DefaultType, typename R2 = typename safe_minmax_impl::TypeOr< R, typename safe_minmax_impl::MType< typename safe_minmax_impl::UnderlyingType::type, typename safe_minmax_impl::UnderlyingType::type>::min_t>::type> constexpr R2 SafeMin(T1 a, T2 b) { static_assert(IsIntlike::value || std::is_floating_point::value, "The first argument must be integral or floating-point"); static_assert(IsIntlike::value || std::is_floating_point::value, "The second argument must be integral or floating-point"); return SafeLt(a, b) ? static_cast(a) : static_cast(b); } template < typename R = safe_minmax_impl::DefaultType, typename T1 = safe_minmax_impl::DefaultType, typename T2 = safe_minmax_impl::DefaultType, typename R2 = typename safe_minmax_impl::TypeOr< R, typename safe_minmax_impl::MType< typename safe_minmax_impl::UnderlyingType::type, typename safe_minmax_impl::UnderlyingType::type>::max_t>::type> constexpr R2 SafeMax(T1 a, T2 b) { static_assert(IsIntlike::value || std::is_floating_point::value, "The first argument must be integral or floating-point"); static_assert(IsIntlike::value || std::is_floating_point::value, "The second argument must be integral or floating-point"); return SafeGt(a, b) ? static_cast(a) : static_cast(b); } namespace safe_minmax_impl { // Given three types T, L, and H, let ::type be a suitable return value for // SafeClamp(T, L, H). See the docs at the top of this file for details. template ::value, bool int2 = IsIntlike::value, bool int3 = IsIntlike::value> struct ClampType { static_assert(int1 == int2 && int1 == int3, "You may not mix integral and floating-point arguments"); }; // Specialization for when all three types are floating-point. template struct ClampType { using type = typename std::common_type::type; }; // Specialization for when all three types are integral. template struct ClampType { private: // Range of the return value. The return type must be able to represent this // full range. static constexpr auto r_min = SafeMax(Limits::lowest, SafeMin(Limits::lowest, Limits::lowest)); static constexpr auto r_max = SafeMin(Limits::max, SafeMax(Limits::max, Limits::max)); // Is the given type an acceptable return type? (That is, can it represent // all possible return values, and is it no larger than the largest of the // input types?) template struct AcceptableType { private: static constexpr bool not_too_large = sizeof(A) <= sizeof(L) || sizeof(A) <= sizeof(H) || sizeof(A) <= sizeof(T); static constexpr bool range_contained = SafeLe(Limits::lowest, r_min) && SafeLe(r_max, Limits::max); public: static constexpr bool value = not_too_large && range_contained; }; using best_signed_type = typename std::conditional< AcceptableType::value, int8_t, typename std::conditional< AcceptableType::value, int16_t, typename std::conditional::value, int32_t, int64_t>::type>::type>::type; using best_unsigned_type = typename std::conditional< AcceptableType::value, uint8_t, typename std::conditional< AcceptableType::value, uint16_t, typename std::conditional::value, uint32_t, uint64_t>::type>::type>::type; public: // Pick the best type, preferring the same signedness as T but falling back // to the other one if necessary. using type = typename std::conditional< std::is_signed::value, typename std::conditional::value, best_signed_type, best_unsigned_type>::type, typename std::conditional::value, best_unsigned_type, best_signed_type>::type>::type; static_assert(AcceptableType::value, ""); }; } // namespace safe_minmax_impl template < typename R = safe_minmax_impl::DefaultType, typename T = safe_minmax_impl::DefaultType, typename L = safe_minmax_impl::DefaultType, typename H = safe_minmax_impl::DefaultType, typename R2 = typename safe_minmax_impl::TypeOr< R, typename safe_minmax_impl::ClampType< typename safe_minmax_impl::UnderlyingType::type, typename safe_minmax_impl::UnderlyingType::type, typename safe_minmax_impl::UnderlyingType::type>::type>::type> R2 SafeClamp(T x, L min, H max) { static_assert(IsIntlike::value || std::is_floating_point::value, "The first argument must be integral or floating-point"); static_assert(IsIntlike::value || std::is_floating_point::value, "The second argument must be integral or floating-point"); static_assert(IsIntlike::value || std::is_floating_point::value, "The third argument must be integral or floating-point"); RTC_DCHECK_LE(min, max); return SafeLe(x, min) ? static_cast(min) : SafeGe(x, max) ? static_cast(max) : static_cast(x); } } // namespace rtc #endif // RTC_BASE_NUMERICS_SAFE_MINMAX_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/platform_thread.cc0000664000175000017500000001324014475643423023420 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/platform_thread.h" #if !defined(WEBRTC_WIN) #include #endif #include #include #include #include "rtc_base/checks.h" namespace rtc { namespace { #if !defined(WEBRTC_WIN) struct ThreadAttributes { ThreadAttributes() { pthread_attr_init(&attr); } ~ThreadAttributes() { pthread_attr_destroy(&attr); } pthread_attr_t* operator&() { return &attr; } pthread_attr_t attr; }; #endif // defined(WEBRTC_WIN) } // namespace PlatformThread::PlatformThread(ThreadRunFunction func, void* obj, absl::string_view thread_name, ThreadPriority priority /*= kNormalPriority*/) : run_function_(func), priority_(priority), obj_(obj), name_(thread_name) { RTC_DCHECK(func); RTC_DCHECK(!name_.empty()); // TODO(tommi): Consider lowering the limit to 15 (limit on Linux). RTC_DCHECK(name_.length() < 64); spawned_thread_checker_.Detach(); } PlatformThread::~PlatformThread() { RTC_DCHECK(thread_checker_.IsCurrent()); #if defined(WEBRTC_WIN) RTC_DCHECK(!thread_); RTC_DCHECK(!thread_id_); #endif // defined(WEBRTC_WIN) } #if defined(WEBRTC_WIN) DWORD WINAPI PlatformThread::StartThread(void* param) { // The GetLastError() function only returns valid results when it is called // after a Win32 API function that returns a "failed" result. A crash dump // contains the result from GetLastError() and to make sure it does not // falsely report a Windows error we call SetLastError here. ::SetLastError(ERROR_SUCCESS); static_cast(param)->Run(); return 0; } #else void* PlatformThread::StartThread(void* param) { static_cast(param)->Run(); return 0; } #endif // defined(WEBRTC_WIN) void PlatformThread::Start() { RTC_DCHECK(thread_checker_.IsCurrent()); RTC_DCHECK(!thread_) << "Thread already started?"; #if defined(WEBRTC_WIN) // See bug 2902 for background on STACK_SIZE_PARAM_IS_A_RESERVATION. // Set the reserved stack stack size to 1M, which is the default on Windows // and Linux. thread_ = ::CreateThread(nullptr, 1024 * 1024, &StartThread, this, STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_id_); RTC_CHECK(thread_) << "CreateThread failed"; RTC_DCHECK(thread_id_); #else ThreadAttributes attr; // Set the stack stack size to 1M. pthread_attr_setstacksize(&attr, 1024 * 1024); RTC_CHECK_EQ(0, pthread_create(&thread_, &attr, &StartThread, this)); #endif // defined(WEBRTC_WIN) } bool PlatformThread::IsRunning() const { RTC_DCHECK(thread_checker_.IsCurrent()); #if defined(WEBRTC_WIN) return thread_ != nullptr; #else return thread_ != 0; #endif // defined(WEBRTC_WIN) } PlatformThreadRef PlatformThread::GetThreadRef() const { #if defined(WEBRTC_WIN) return thread_id_; #else return thread_; #endif // defined(WEBRTC_WIN) } void PlatformThread::Stop() { RTC_DCHECK(thread_checker_.IsCurrent()); if (!IsRunning()) return; #if defined(WEBRTC_WIN) WaitForSingleObject(thread_, INFINITE); CloseHandle(thread_); thread_ = nullptr; thread_id_ = 0; #else RTC_CHECK_EQ(0, pthread_join(thread_, nullptr)); thread_ = 0; #endif // defined(WEBRTC_WIN) spawned_thread_checker_.Detach(); } void PlatformThread::Run() { // Attach the worker thread checker to this thread. RTC_DCHECK(spawned_thread_checker_.IsCurrent()); rtc::SetCurrentThreadName(name_.c_str()); SetPriority(priority_); run_function_(obj_); } bool PlatformThread::SetPriority(ThreadPriority priority) { RTC_DCHECK(spawned_thread_checker_.IsCurrent()); #if defined(WEBRTC_WIN) return SetThreadPriority(thread_, priority) != FALSE; #elif defined(__native_client__) || defined(WEBRTC_FUCHSIA) // Setting thread priorities is not supported in NaCl or Fuchsia. return true; #elif defined(WEBRTC_CHROMIUM_BUILD) && defined(WEBRTC_LINUX) // TODO(tommi): Switch to the same mechanism as Chromium uses for changing // thread priorities. return true; #else const int policy = SCHED_FIFO; const int min_prio = sched_get_priority_min(policy); const int max_prio = sched_get_priority_max(policy); if (min_prio == -1 || max_prio == -1) { return false; } if (max_prio - min_prio <= 2) return false; // Convert webrtc priority to system priorities: sched_param param; const int top_prio = max_prio - 1; const int low_prio = min_prio + 1; switch (priority) { case kLowPriority: param.sched_priority = low_prio; break; case kNormalPriority: // The -1 ensures that the kHighPriority is always greater or equal to // kNormalPriority. param.sched_priority = (low_prio + top_prio - 1) / 2; break; case kHighPriority: param.sched_priority = std::max(top_prio - 2, low_prio); break; case kHighestPriority: param.sched_priority = std::max(top_prio - 1, low_prio); break; case kRealtimePriority: param.sched_priority = top_prio; break; } return pthread_setschedparam(thread_, policy, ¶m) == 0; #endif // defined(WEBRTC_WIN) } #if defined(WEBRTC_WIN) bool PlatformThread::QueueAPC(PAPCFUNC function, ULONG_PTR data) { RTC_DCHECK(thread_checker_.IsCurrent()); RTC_DCHECK(IsRunning()); return QueueUserAPC(function, thread_, data) != FALSE; } #endif } // namespace rtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/platform_thread.h0000664000175000017500000000574214475643423023272 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_PLATFORM_THREAD_H_ #define RTC_BASE_PLATFORM_THREAD_H_ #ifndef WEBRTC_WIN #include #endif #include #include "absl/strings/string_view.h" #include "rtc_base/constructor_magic.h" #include "rtc_base/platform_thread_types.h" #include "rtc_base/thread_checker.h" namespace rtc { // Callback function that the spawned thread will enter once spawned. typedef void (*ThreadRunFunction)(void*); enum ThreadPriority { #ifdef WEBRTC_WIN kLowPriority = THREAD_PRIORITY_BELOW_NORMAL, kNormalPriority = THREAD_PRIORITY_NORMAL, kHighPriority = THREAD_PRIORITY_ABOVE_NORMAL, kHighestPriority = THREAD_PRIORITY_HIGHEST, kRealtimePriority = THREAD_PRIORITY_TIME_CRITICAL #else kLowPriority = 1, kNormalPriority = 2, kHighPriority = 3, kHighestPriority = 4, kRealtimePriority = 5 #endif }; // Represents a simple worker thread. The implementation must be assumed // to be single threaded, meaning that all methods of the class, must be // called from the same thread, including instantiation. class PlatformThread { public: PlatformThread(ThreadRunFunction func, void* obj, absl::string_view thread_name, ThreadPriority priority = kNormalPriority); virtual ~PlatformThread(); const std::string& name() const { return name_; } // Spawns a thread and tries to set thread priority according to the priority // from when CreateThread was called. void Start(); bool IsRunning() const; // Returns an identifier for the worker thread that can be used to do // thread checks. PlatformThreadRef GetThreadRef() const; // Stops (joins) the spawned thread. void Stop(); protected: #if defined(WEBRTC_WIN) // Exposed to derived classes to allow for special cases specific to Windows. bool QueueAPC(PAPCFUNC apc_function, ULONG_PTR data); #endif private: void Run(); bool SetPriority(ThreadPriority priority); ThreadRunFunction const run_function_ = nullptr; const ThreadPriority priority_ = kNormalPriority; void* const obj_; // TODO(pbos): Make sure call sites use string literals and update to a const // char* instead of a std::string. const std::string name_; rtc::ThreadChecker thread_checker_; rtc::ThreadChecker spawned_thread_checker_; #if defined(WEBRTC_WIN) static DWORD WINAPI StartThread(void* param); HANDLE thread_ = nullptr; DWORD thread_id_ = 0; #else static void* StartThread(void* param); pthread_t thread_ = 0; #endif // defined(WEBRTC_WIN) RTC_DISALLOW_COPY_AND_ASSIGN(PlatformThread); }; } // namespace rtc #endif // RTC_BASE_PLATFORM_THREAD_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/platform_thread_types.cc0000664000175000017500000000725614475643423024656 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/platform_thread_types.h" #if defined(WEBRTC_LINUX) #include #include #endif #if defined(WEBRTC_WIN) #include "rtc_base/arraysize.h" // The SetThreadDescription API was brought in version 1607 of Windows 10. // For compatibility with various versions of winuser and avoid clashing with // a potentially defined type, we use the RTC_ prefix. typedef HRESULT(WINAPI* RTC_SetThreadDescription)(HANDLE hThread, PCWSTR lpThreadDescription); #endif namespace rtc { PlatformThreadId CurrentThreadId() { #if defined(WEBRTC_WIN) return GetCurrentThreadId(); #elif defined(WEBRTC_POSIX) #if defined(WEBRTC_MAC) || defined(WEBRTC_IOS) return pthread_mach_thread_np(pthread_self()); #elif defined(WEBRTC_ANDROID) return gettid(); #elif defined(WEBRTC_FUCHSIA) return zx_thread_self(); #elif defined(WEBRTC_LINUX) return syscall(__NR_gettid); #elif defined(__EMSCRIPTEN__) return static_cast(pthread_self()); #else // Default implementation for nacl and solaris. return reinterpret_cast(pthread_self()); #endif #endif // defined(WEBRTC_POSIX) } PlatformThreadRef CurrentThreadRef() { #if defined(WEBRTC_WIN) return GetCurrentThreadId(); #elif defined(WEBRTC_FUCHSIA) return zx_thread_self(); #elif defined(WEBRTC_POSIX) return pthread_self(); #endif } bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b) { #if defined(WEBRTC_WIN) || defined(WEBRTC_FUCHSIA) return a == b; #elif defined(WEBRTC_POSIX) return pthread_equal(a, b); #endif } void SetCurrentThreadName(const char* name) { #if defined(WEBRTC_WIN) // The SetThreadDescription API works even if no debugger is attached. // The names set with this API also show up in ETW traces. Very handy. static auto set_thread_description_func = reinterpret_cast(::GetProcAddress( ::GetModuleHandleA("Kernel32.dll"), "SetThreadDescription")); if (set_thread_description_func) { // Convert from ASCII to UTF-16. wchar_t wide_thread_name[64]; for (size_t i = 0; i < arraysize(wide_thread_name) - 1; ++i) { wide_thread_name[i] = name[i]; if (wide_thread_name[i] == L'\0') break; } // Guarantee null-termination. wide_thread_name[arraysize(wide_thread_name) - 1] = L'\0'; set_thread_description_func(::GetCurrentThread(), wide_thread_name); } // For details see: // https://docs.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code #pragma pack(push, 8) struct { DWORD dwType; LPCSTR szName; DWORD dwThreadID; DWORD dwFlags; } threadname_info = {0x1000, name, static_cast(-1), 0}; #pragma pack(pop) #pragma warning(push) #pragma warning(disable : 6320 6322) #ifndef __MINGW32__ __try { ::RaiseException(0x406D1388, 0, sizeof(threadname_info) / sizeof(ULONG_PTR), reinterpret_cast(&threadname_info)); } __except (EXCEPTION_EXECUTE_HANDLER) { // NOLINT } #endif #pragma warning(pop) #elif defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID) prctl(PR_SET_NAME, reinterpret_cast(name)); // NOLINT #elif defined(WEBRTC_MAC) || defined(WEBRTC_IOS) pthread_setname_np(name); #endif } } // namespace rtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/platform_thread_types.h0000664000175000017500000000360114475643423024506 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_PLATFORM_THREAD_TYPES_H_ #define RTC_BASE_PLATFORM_THREAD_TYPES_H_ // clang-format off // clang formating would change include order. #if defined(WEBRTC_WIN) // Include winsock2.h before including to maintain consistency with // win32.h. To include win32.h directly, it must be broken out into its own // build target. #include #include #elif defined(WEBRTC_FUCHSIA) #include #include #elif defined(WEBRTC_POSIX) #include #include #if defined(WEBRTC_MAC) #include #endif #endif // clang-format on namespace rtc { #if defined(WEBRTC_WIN) typedef DWORD PlatformThreadId; typedef DWORD PlatformThreadRef; #elif defined(WEBRTC_FUCHSIA) typedef zx_handle_t PlatformThreadId; typedef zx_handle_t PlatformThreadRef; #elif defined(WEBRTC_POSIX) typedef pid_t PlatformThreadId; typedef pthread_t PlatformThreadRef; #endif // Retrieve the ID of the current thread. PlatformThreadId CurrentThreadId(); // Retrieves a reference to the current thread. On Windows, this is the same // as CurrentThreadId. On other platforms it's the pthread_t returned by // pthread_self(). PlatformThreadRef CurrentThreadRef(); // Compares two thread identifiers for equality. bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b); // Sets the current thread name. void SetCurrentThreadName(const char* name); } // namespace rtc #endif // RTC_BASE_PLATFORM_THREAD_TYPES_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/race_checker.cc0000664000175000017500000000406614475643423022651 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/race_checker.h" namespace rtc { RaceChecker::RaceChecker() {} // Note that the implementation here is in itself racy, but we pretend it does // not matter because we want this useful in release builds without having to // pay the cost of using atomics. A race hitting the race checker is likely to // cause access_count_ to diverge from zero and therefore cause the ThreadRef // comparison to fail, signaling a race, although it may not be in the exact // spot where a race *first* appeared in the code we're trying to protect. There // is also a chance that an actual race is missed, however the probability of // that has been considered small enough to be an acceptable trade off. bool RaceChecker::Acquire() const { const PlatformThreadRef current_thread = CurrentThreadRef(); // Set new accessing thread if this is a new use. if (access_count_++ == 0) accessing_thread_ = current_thread; // If this is being used concurrently this check will fail for the second // thread entering since it won't set the thread. Recursive use of checked // methods are OK since the accessing thread remains the same. const PlatformThreadRef accessing_thread = accessing_thread_; return IsThreadRefEqual(accessing_thread, current_thread); } void RaceChecker::Release() const { --access_count_; } namespace internal { RaceCheckerScope::RaceCheckerScope(const RaceChecker* race_checker) : race_checker_(race_checker), race_check_ok_(race_checker->Acquire()) {} bool RaceCheckerScope::RaceDetected() const { return !race_check_ok_; } RaceCheckerScope::~RaceCheckerScope() { race_checker_->Release(); } } // namespace internal } // namespace rtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/race_checker.h0000664000175000017500000000442214475643423022507 0ustar00arunarun/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_RACE_CHECKER_H_ #define RTC_BASE_RACE_CHECKER_H_ #include "rtc_base/checks.h" #include "rtc_base/platform_thread_types.h" #include "rtc_base/thread_annotations.h" namespace rtc { namespace internal { class RaceCheckerScope; } // namespace internal // Best-effort race-checking implementation. This primitive uses no // synchronization at all to be as-fast-as-possible in the non-racy case. class RTC_LOCKABLE RaceChecker { public: friend class internal::RaceCheckerScope; RaceChecker(); private: bool Acquire() const RTC_EXCLUSIVE_LOCK_FUNCTION(); void Release() const RTC_UNLOCK_FUNCTION(); // Volatile to prevent code being optimized away in Acquire()/Release(). mutable volatile int access_count_ = 0; mutable volatile PlatformThreadRef accessing_thread_; }; namespace internal { class RTC_SCOPED_LOCKABLE RaceCheckerScope { public: explicit RaceCheckerScope(const RaceChecker* race_checker) RTC_EXCLUSIVE_LOCK_FUNCTION(race_checker); bool RaceDetected() const; ~RaceCheckerScope() RTC_UNLOCK_FUNCTION(); private: const RaceChecker* const race_checker_; const bool race_check_ok_; }; class RTC_SCOPED_LOCKABLE RaceCheckerScopeDoNothing { public: explicit RaceCheckerScopeDoNothing(const RaceChecker* race_checker) RTC_EXCLUSIVE_LOCK_FUNCTION(race_checker) {} ~RaceCheckerScopeDoNothing() RTC_UNLOCK_FUNCTION() {} }; } // namespace internal } // namespace rtc #define RTC_CHECK_RUNS_SERIALIZED(x) \ rtc::internal::RaceCheckerScope race_checker(x); \ RTC_CHECK(!race_checker.RaceDetected()) #if RTC_DCHECK_IS_ON #define RTC_DCHECK_RUNS_SERIALIZED(x) \ rtc::internal::RaceCheckerScope race_checker(x); \ RTC_DCHECK(!race_checker.RaceDetected()) #else #define RTC_DCHECK_RUNS_SERIALIZED(x) \ rtc::internal::RaceCheckerScopeDoNothing race_checker(x) #endif #endif // RTC_BASE_RACE_CHECKER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/ref_count.h0000664000175000017500000000563314475643423022102 0ustar00arunarun/* * Copyright 2011 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_REF_COUNT_H_ #define RTC_BASE_REF_COUNT_H_ namespace rtc { // Refcounted objects should implement the following informal interface: // // void AddRef() const ; // RefCountReleaseStatus Release() const; // // You may access members of a reference-counted object, including the AddRef() // and Release() methods, only if you already own a reference to it, or if // you're borrowing someone else's reference. (A newly created object is a // special case: the reference count is zero on construction, and the code that // creates the object should immediately call AddRef(), bringing the reference // count from zero to one, e.g., by constructing an rtc::scoped_refptr). // // AddRef() creates a new reference to the object. // // Release() releases a reference to the object; the caller now has one less // reference than before the call. Returns kDroppedLastRef if the number of // references dropped to zero because of this (in which case the object destroys // itself). Otherwise, returns kOtherRefsRemained, to signal that at the precise // time the caller's reference was dropped, other references still remained (but // if other threads own references, this may of course have changed by the time // Release() returns). // // The caller of Release() must treat it in the same way as a delete operation: // Regardless of the return value from Release(), the caller mustn't access the // object. The object might still be alive, due to references held by other // users of the object, but the object can go away at any time, e.g., as the // result of another thread calling Release(). // // Calling AddRef() and Release() manually is discouraged. It's recommended to // use rtc::scoped_refptr to manage all pointers to reference counted objects. // Note that rtc::scoped_refptr depends on compile-time duck-typing; formally // implementing the below RefCountInterface is not required. enum class RefCountReleaseStatus { kDroppedLastRef, kOtherRefsRemained }; // Interfaces where refcounting is part of the public api should // inherit this abstract interface. The implementation of these // methods is usually provided by the RefCountedObject template class, // applied as a leaf in the inheritance tree. class RefCountInterface { public: virtual void AddRef() const = 0; virtual RefCountReleaseStatus Release() const = 0; // Non-public destructor, because Release() has exclusive responsibility for // destroying the object. protected: virtual ~RefCountInterface() {} }; } // namespace rtc #endif // RTC_BASE_REF_COUNT_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/ref_counted_object.h0000664000175000017500000000374114475643423023737 0ustar00arunarun/* * Copyright 2016 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_REF_COUNTED_OBJECT_H_ #define RTC_BASE_REF_COUNTED_OBJECT_H_ #include #include #include "rtc_base/constructor_magic.h" #include "rtc_base/ref_count.h" #include "rtc_base/ref_counter.h" namespace rtc { template class RefCountedObject : public T { public: RefCountedObject() {} template explicit RefCountedObject(P0&& p0) : T(std::forward(p0)) {} template RefCountedObject(P0&& p0, P1&& p1, Args&&... args) : T(std::forward(p0), std::forward(p1), std::forward(args)...) {} virtual void AddRef() const { ref_count_.IncRef(); } virtual RefCountReleaseStatus Release() const { const auto status = ref_count_.DecRef(); if (status == RefCountReleaseStatus::kDroppedLastRef) { delete this; } return status; } // Return whether the reference count is one. If the reference count is used // in the conventional way, a reference count of 1 implies that the current // thread owns the reference and no other thread shares it. This call // performs the test for a reference count of one, and performs the memory // barrier needed for the owning thread to act on the object, knowing that it // has exclusive access to the object. virtual bool HasOneRef() const { return ref_count_.HasOneRef(); } protected: virtual ~RefCountedObject() {} mutable webrtc::webrtc_impl::RefCounter ref_count_{0}; RTC_DISALLOW_COPY_AND_ASSIGN(RefCountedObject); }; } // namespace rtc #endif // RTC_BASE_REF_COUNTED_OBJECT_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/ref_counter.h0000664000175000017500000000626014475643423022426 0ustar00arunarun/* * Copyright 2017 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_REF_COUNTER_H_ #define RTC_BASE_REF_COUNTER_H_ #include #include "rtc_base/ref_count.h" namespace webrtc { namespace webrtc_impl { class RefCounter { public: explicit RefCounter(int ref_count) : ref_count_(ref_count) {} RefCounter() = delete; void IncRef() { // Relaxed memory order: The current thread is allowed to act on the // resource protected by the reference counter both before and after the // atomic op, so this function doesn't prevent memory access reordering. ref_count_.fetch_add(1, std::memory_order_relaxed); } // Returns kDroppedLastRef if this call dropped the last reference; the caller // should therefore free the resource protected by the reference counter. // Otherwise, returns kOtherRefsRemained (note that in case of multithreading, // some other caller may have dropped the last reference by the time this call // returns; all we know is that we didn't do it). rtc::RefCountReleaseStatus DecRef() { // Use release-acquire barrier to ensure all actions on the protected // resource are finished before the resource can be freed. // When ref_count_after_subtract > 0, this function require // std::memory_order_release part of the barrier. // When ref_count_after_subtract == 0, this function require // std::memory_order_acquire part of the barrier. // In addition std::memory_order_release is used for synchronization with // the HasOneRef function to make sure all actions on the protected resource // are finished before the resource is assumed to have exclusive access. int ref_count_after_subtract = ref_count_.fetch_sub(1, std::memory_order_acq_rel) - 1; return ref_count_after_subtract == 0 ? rtc::RefCountReleaseStatus::kDroppedLastRef : rtc::RefCountReleaseStatus::kOtherRefsRemained; } // Return whether the reference count is one. If the reference count is used // in the conventional way, a reference count of 1 implies that the current // thread owns the reference and no other thread shares it. This call performs // the test for a reference count of one, and performs the memory barrier // needed for the owning thread to act on the resource protected by the // reference counter, knowing that it has exclusive access. bool HasOneRef() const { // To ensure resource protected by the reference counter has exclusive // access, all changes to the resource before it was released by other // threads must be visible by current thread. That is provided by release // (in DecRef) and acquire (in this function) ordering. return ref_count_.load(std::memory_order_acquire) == 1; } private: std::atomic ref_count_; }; } // namespace webrtc_impl } // namespace webrtc #endif // RTC_BASE_REF_COUNTER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/sanitizer.h0000664000175000017500000001044014475643423022116 0ustar00arunarun/* * Copyright 2016 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_SANITIZER_H_ #define RTC_BASE_SANITIZER_H_ #include // For size_t. #ifdef __cplusplus #include "absl/meta/type_traits.h" #endif #if defined(__has_feature) #if __has_feature(address_sanitizer) #define RTC_HAS_ASAN 1 #endif #if __has_feature(memory_sanitizer) #define RTC_HAS_MSAN 1 #endif #endif #ifndef RTC_HAS_ASAN #define RTC_HAS_ASAN 0 #endif #ifndef RTC_HAS_MSAN #define RTC_HAS_MSAN 0 #endif #if RTC_HAS_ASAN #include #endif #if RTC_HAS_MSAN #include #endif #ifdef __has_attribute #if __has_attribute(no_sanitize) #define RTC_NO_SANITIZE(what) __attribute__((no_sanitize(what))) #endif #endif #ifndef RTC_NO_SANITIZE #define RTC_NO_SANITIZE(what) #endif // Ask ASan to mark the memory range [ptr, ptr + element_size * num_elements) // as being unaddressable, so that reads and writes are not allowed. ASan may // narrow the range to the nearest alignment boundaries. static inline void rtc_AsanPoison(const volatile void* ptr, size_t element_size, size_t num_elements) { #if RTC_HAS_ASAN ASAN_POISON_MEMORY_REGION(ptr, element_size * num_elements); #endif } // Ask ASan to mark the memory range [ptr, ptr + element_size * num_elements) // as being addressable, so that reads and writes are allowed. ASan may widen // the range to the nearest alignment boundaries. static inline void rtc_AsanUnpoison(const volatile void* ptr, size_t element_size, size_t num_elements) { #if RTC_HAS_ASAN ASAN_UNPOISON_MEMORY_REGION(ptr, element_size * num_elements); #endif } // Ask MSan to mark the memory range [ptr, ptr + element_size * num_elements) // as being uninitialized. static inline void rtc_MsanMarkUninitialized(const volatile void* ptr, size_t element_size, size_t num_elements) { #if RTC_HAS_MSAN __msan_poison(ptr, element_size * num_elements); #endif } // Force an MSan check (if any bits in the memory range [ptr, ptr + // element_size * num_elements) are uninitialized the call will crash with an // MSan report). static inline void rtc_MsanCheckInitialized(const volatile void* ptr, size_t element_size, size_t num_elements) { #if RTC_HAS_MSAN __msan_check_mem_is_initialized(ptr, element_size * num_elements); #endif } #ifdef __cplusplus namespace rtc { namespace sanitizer_impl { template constexpr bool IsTriviallyCopyable() { return static_cast(absl::is_trivially_copy_constructible::value && (absl::is_trivially_copy_assignable::value || !std::is_copy_assignable::value) && absl::is_trivially_destructible::value); } } // namespace sanitizer_impl template inline void AsanPoison(const T& mem) { rtc_AsanPoison(mem.data(), sizeof(mem.data()[0]), mem.size()); } template inline void AsanUnpoison(const T& mem) { rtc_AsanUnpoison(mem.data(), sizeof(mem.data()[0]), mem.size()); } template inline void MsanMarkUninitialized(const T& mem) { rtc_MsanMarkUninitialized(mem.data(), sizeof(mem.data()[0]), mem.size()); } template inline T MsanUninitialized(T t) { #if RTC_HAS_MSAN // TODO(bugs.webrtc.org/8762): Switch to std::is_trivially_copyable when it // becomes available in downstream projects. static_assert(sanitizer_impl::IsTriviallyCopyable(), ""); #endif rtc_MsanMarkUninitialized(&t, sizeof(T), 1); return t; } template inline void MsanCheckInitialized(const T& mem) { rtc_MsanCheckInitialized(mem.data(), sizeof(mem.data()[0]), mem.size()); } } // namespace rtc #endif // __cplusplus #endif // RTC_BASE_SANITIZER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/string_encode.cc0000664000175000017500000002602214475643423023072 0ustar00arunarun/* * Copyright 2004 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/string_encode.h" #include #include "rtc_base/arraysize.h" #include "rtc_base/checks.h" namespace rtc { ///////////////////////////////////////////////////////////////////////////// // String Encoding Utilities ///////////////////////////////////////////////////////////////////////////// namespace { const char HEX[] = "0123456789abcdef"; // Convert an unsigned value from 0 to 15 to the hex character equivalent... char hex_encode(unsigned char val) { RTC_DCHECK_LT(val, 16); return (val < 16) ? HEX[val] : '!'; } // ...and vice-versa. bool hex_decode(char ch, unsigned char* val) { if ((ch >= '0') && (ch <= '9')) { *val = ch - '0'; } else if ((ch >= 'A') && (ch <= 'F')) { *val = (ch - 'A') + 10; } else if ((ch >= 'a') && (ch <= 'f')) { *val = (ch - 'a') + 10; } else { return false; } return true; } size_t hex_encode_output_length(size_t srclen, char delimiter) { return delimiter && srclen > 0 ? (srclen * 3 - 1) : (srclen * 2); } // hex_encode shows the hex representation of binary data in ascii, with // |delimiter| between bytes, or none if |delimiter| == 0. void hex_encode_with_delimiter(char* buffer, const char* csource, size_t srclen, char delimiter) { RTC_DCHECK(buffer); // Init and check bounds. const unsigned char* bsource = reinterpret_cast(csource); size_t srcpos = 0, bufpos = 0; while (srcpos < srclen) { unsigned char ch = bsource[srcpos++]; buffer[bufpos] = hex_encode((ch >> 4) & 0xF); buffer[bufpos + 1] = hex_encode((ch)&0xF); bufpos += 2; // Don't write a delimiter after the last byte. if (delimiter && (srcpos < srclen)) { buffer[bufpos] = delimiter; ++bufpos; } } } } // namespace std::string hex_encode(const std::string& str) { return hex_encode(str.c_str(), str.size()); } std::string hex_encode(const char* source, size_t srclen) { return hex_encode_with_delimiter(source, srclen, 0); } std::string hex_encode_with_delimiter(const char* source, size_t srclen, char delimiter) { std::string s(hex_encode_output_length(srclen, delimiter), 0); hex_encode_with_delimiter(&s[0], source, srclen, delimiter); return s; } size_t hex_decode(char* cbuffer, size_t buflen, const char* source, size_t srclen) { return hex_decode_with_delimiter(cbuffer, buflen, source, srclen, 0); } size_t hex_decode_with_delimiter(char* cbuffer, size_t buflen, const char* source, size_t srclen, char delimiter) { RTC_DCHECK(cbuffer); // TODO(kwiberg): estimate output size if (buflen == 0) return 0; // Init and bounds check. unsigned char* bbuffer = reinterpret_cast(cbuffer); size_t srcpos = 0, bufpos = 0; size_t needed = (delimiter) ? (srclen + 1) / 3 : srclen / 2; if (buflen < needed) return 0; while (srcpos < srclen) { if ((srclen - srcpos) < 2) { // This means we have an odd number of bytes. return 0; } unsigned char h1, h2; if (!hex_decode(source[srcpos], &h1) || !hex_decode(source[srcpos + 1], &h2)) return 0; bbuffer[bufpos++] = (h1 << 4) | h2; srcpos += 2; // Remove the delimiter if needed. if (delimiter && (srclen - srcpos) > 1) { if (source[srcpos] != delimiter) return 0; ++srcpos; } } return bufpos; } size_t hex_decode(char* buffer, size_t buflen, const std::string& source) { return hex_decode_with_delimiter(buffer, buflen, source, 0); } size_t hex_decode_with_delimiter(char* buffer, size_t buflen, const std::string& source, char delimiter) { return hex_decode_with_delimiter(buffer, buflen, source.c_str(), source.length(), delimiter); } size_t tokenize(const std::string& source, char delimiter, std::vector* fields) { fields->clear(); size_t last = 0; for (size_t i = 0; i < source.length(); ++i) { if (source[i] == delimiter) { if (i != last) { fields->push_back(source.substr(last, i - last)); } last = i + 1; } } if (last != source.length()) { fields->push_back(source.substr(last, source.length() - last)); } return fields->size(); } size_t tokenize_with_empty_tokens(const std::string& source, char delimiter, std::vector* fields) { fields->clear(); size_t last = 0; for (size_t i = 0; i < source.length(); ++i) { if (source[i] == delimiter) { fields->push_back(source.substr(last, i - last)); last = i + 1; } } fields->push_back(source.substr(last, source.length() - last)); return fields->size(); } size_t tokenize_append(const std::string& source, char delimiter, std::vector* fields) { if (!fields) return 0; std::vector new_fields; tokenize(source, delimiter, &new_fields); fields->insert(fields->end(), new_fields.begin(), new_fields.end()); return fields->size(); } size_t tokenize(const std::string& source, char delimiter, char start_mark, char end_mark, std::vector* fields) { if (!fields) return 0; fields->clear(); std::string remain_source = source; while (!remain_source.empty()) { size_t start_pos = remain_source.find(start_mark); if (std::string::npos == start_pos) break; std::string pre_mark; if (start_pos > 0) { pre_mark = remain_source.substr(0, start_pos - 1); } ++start_pos; size_t end_pos = remain_source.find(end_mark, start_pos); if (std::string::npos == end_pos) break; // We have found the matching marks. First tokenize the pre-mask. Then add // the marked part as a single field. Finally, loop back for the post-mark. tokenize_append(pre_mark, delimiter, fields); fields->push_back(remain_source.substr(start_pos, end_pos - start_pos)); remain_source = remain_source.substr(end_pos + 1); } return tokenize_append(remain_source, delimiter, fields); } bool tokenize_first(const std::string& source, const char delimiter, std::string* token, std::string* rest) { // Find the first delimiter size_t left_pos = source.find(delimiter); if (left_pos == std::string::npos) { return false; } // Look for additional occurrances of delimiter. size_t right_pos = left_pos + 1; while (source[right_pos] == delimiter) { right_pos++; } *token = source.substr(0, left_pos); *rest = source.substr(right_pos); return true; } std::string join(const std::vector& source, char delimiter) { if (source.size() == 0) { return std::string(); } // Find length of the string to be returned to pre-allocate memory. size_t source_string_length = 0; for (size_t i = 0; i < source.size(); ++i) { source_string_length += source[i].length(); } // Build the joined string. std::string joined_string; joined_string.reserve(source_string_length + source.size() - 1); for (size_t i = 0; i < source.size(); ++i) { if (i != 0) { joined_string += delimiter; } joined_string += source[i]; } return joined_string; } size_t split(const std::string& source, char delimiter, std::vector* fields) { RTC_DCHECK(fields); fields->clear(); size_t last = 0; for (size_t i = 0; i < source.length(); ++i) { if (source[i] == delimiter) { fields->push_back(source.substr(last, i - last)); last = i + 1; } } fields->push_back(source.substr(last, source.length() - last)); return fields->size(); } std::string ToString(const bool b) { return b ? "true" : "false"; } std::string ToString(const char* const s) { return std::string(s); } std::string ToString(const std::string s) { return s; } std::string ToString(const short s) { char buf[32]; const int len = std::snprintf(&buf[0], arraysize(buf), "%hd", s); RTC_DCHECK_LE(len, arraysize(buf)); return std::string(&buf[0], len); } std::string ToString(const unsigned short s) { char buf[32]; const int len = std::snprintf(&buf[0], arraysize(buf), "%hu", s); RTC_DCHECK_LE(len, arraysize(buf)); return std::string(&buf[0], len); } std::string ToString(const int s) { char buf[32]; const int len = std::snprintf(&buf[0], arraysize(buf), "%d", s); RTC_DCHECK_LE(len, arraysize(buf)); return std::string(&buf[0], len); } std::string ToString(const unsigned int s) { char buf[32]; const int len = std::snprintf(&buf[0], arraysize(buf), "%u", s); RTC_DCHECK_LE(len, arraysize(buf)); return std::string(&buf[0], len); } std::string ToString(const long int s) { char buf[32]; const int len = std::snprintf(&buf[0], arraysize(buf), "%ld", s); RTC_DCHECK_LE(len, arraysize(buf)); return std::string(&buf[0], len); } std::string ToString(const unsigned long int s) { char buf[32]; const int len = std::snprintf(&buf[0], arraysize(buf), "%lu", s); RTC_DCHECK_LE(len, arraysize(buf)); return std::string(&buf[0], len); } std::string ToString(const long long int s) { char buf[32]; const int len = std::snprintf(&buf[0], arraysize(buf), "%lld", s); RTC_DCHECK_LE(len, arraysize(buf)); return std::string(&buf[0], len); } std::string ToString(const unsigned long long int s) { char buf[32]; const int len = std::snprintf(&buf[0], arraysize(buf), "%llu", s); RTC_DCHECK_LE(len, arraysize(buf)); return std::string(&buf[0], len); } std::string ToString(const double d) { char buf[32]; const int len = std::snprintf(&buf[0], arraysize(buf), "%g", d); RTC_DCHECK_LE(len, arraysize(buf)); return std::string(&buf[0], len); } std::string ToString(const long double d) { char buf[32]; const int len = std::snprintf(&buf[0], arraysize(buf), "%Lg", d); RTC_DCHECK_LE(len, arraysize(buf)); return std::string(&buf[0], len); } std::string ToString(const void* const p) { char buf[32]; const int len = std::snprintf(&buf[0], arraysize(buf), "%p", p); RTC_DCHECK_LE(len, arraysize(buf)); return std::string(&buf[0], len); } bool FromString(const std::string& s, bool* b) { if (s == "false") { *b = false; return true; } if (s == "true") { *b = true; return true; } return false; } } // namespace rtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/string_encode.h0000664000175000017500000001300414475643423022730 0ustar00arunarun/* * Copyright 2004 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_STRING_ENCODE_H_ #define RTC_BASE_STRING_ENCODE_H_ #include #include #include #include #include "absl/types/optional.h" #include "rtc_base/checks.h" #include "rtc_base/string_to_number.h" namespace rtc { ////////////////////////////////////////////////////////////////////// // String Encoding Utilities ////////////////////////////////////////////////////////////////////// std::string hex_encode(const std::string& str); std::string hex_encode(const char* source, size_t srclen); std::string hex_encode_with_delimiter(const char* source, size_t srclen, char delimiter); // hex_decode converts ascii hex to binary. size_t hex_decode(char* buffer, size_t buflen, const char* source, size_t srclen); // hex_decode, assuming that there is a delimiter between every byte // pair. // |delimiter| == 0 means no delimiter // If the buffer is too short or the data is invalid, we return 0. size_t hex_decode_with_delimiter(char* buffer, size_t buflen, const char* source, size_t srclen, char delimiter); // Helper functions for hex_decode. size_t hex_decode(char* buffer, size_t buflen, const std::string& source); size_t hex_decode_with_delimiter(char* buffer, size_t buflen, const std::string& source, char delimiter); // Joins the source vector of strings into a single string, with each // field in source being separated by delimiter. No trailing delimiter is added. std::string join(const std::vector& source, char delimiter); // Splits the source string into multiple fields separated by delimiter, // with duplicates of delimiter creating empty fields. size_t split(const std::string& source, char delimiter, std::vector* fields); // Splits the source string into multiple fields separated by delimiter, // with duplicates of delimiter ignored. Trailing delimiter ignored. size_t tokenize(const std::string& source, char delimiter, std::vector* fields); // Tokenize, including the empty tokens. size_t tokenize_with_empty_tokens(const std::string& source, char delimiter, std::vector* fields); // Tokenize and append the tokens to fields. Return the new size of fields. size_t tokenize_append(const std::string& source, char delimiter, std::vector* fields); // Splits the source string into multiple fields separated by delimiter, with // duplicates of delimiter ignored. Trailing delimiter ignored. A substring in // between the start_mark and the end_mark is treated as a single field. Return // the size of fields. For example, if source is "filename // \"/Library/Application Support/media content.txt\"", delimiter is ' ', and // the start_mark and end_mark are '"', this method returns two fields: // "filename" and "/Library/Application Support/media content.txt". size_t tokenize(const std::string& source, char delimiter, char start_mark, char end_mark, std::vector* fields); // Extract the first token from source as separated by delimiter, with // duplicates of delimiter ignored. Return false if the delimiter could not be // found, otherwise return true. bool tokenize_first(const std::string& source, const char delimiter, std::string* token, std::string* rest); // Convert arbitrary values to/from a string. // TODO(jonasolsson): Remove these when absl::StrCat becomes available. std::string ToString(bool b); std::string ToString(const char* s); std::string ToString(std::string t); std::string ToString(short s); std::string ToString(unsigned short s); std::string ToString(int s); std::string ToString(unsigned int s); std::string ToString(long int s); std::string ToString(unsigned long int s); std::string ToString(long long int s); std::string ToString(unsigned long long int s); std::string ToString(double t); std::string ToString(long double t); std::string ToString(const void* p); template ::value && !std::is_same::value, int>::type = 0> static bool FromString(const std::string& s, T* t) { RTC_DCHECK(t); absl::optional result = StringToNumber(s); if (result) *t = *result; return result.has_value(); } bool FromString(const std::string& s, bool* b); template static inline T FromString(const std::string& str) { T val; FromString(str, &val); return val; } ////////////////////////////////////////////////////////////////////// } // namespace rtc #endif // RTC_BASE_STRING_ENCODE_H__ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/string_to_number.cc0000664000175000017500000000476614475643423023642 0ustar00arunarun/* * Copyright 2017 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/string_to_number.h" #include #include #include #include "rtc_base/checks.h" namespace rtc { namespace string_to_number_internal { absl::optional ParseSigned(const char* str, int base) { RTC_DCHECK(str); if (isdigit(str[0]) || str[0] == '-') { char* end = nullptr; errno = 0; const signed_type value = std::strtoll(str, &end, base); if (end && *end == '\0' && errno == 0) { return value; } } return absl::nullopt; } absl::optional ParseUnsigned(const char* str, int base) { RTC_DCHECK(str); if (isdigit(str[0]) || str[0] == '-') { // Explicitly discard negative values. std::strtoull parsing causes unsigned // wraparound. We cannot just reject values that start with -, though, since // -0 is perfectly fine, as is -0000000000000000000000000000000. const bool is_negative = str[0] == '-'; char* end = nullptr; errno = 0; const unsigned_type value = std::strtoull(str, &end, base); if (end && *end == '\0' && errno == 0 && (value == 0 || !is_negative)) { return value; } } return absl::nullopt; } template T StrToT(const char* str, char** str_end); template <> inline float StrToT(const char* str, char** str_end) { return std::strtof(str, str_end); } template <> inline double StrToT(const char* str, char** str_end) { return std::strtod(str, str_end); } template <> inline long double StrToT(const char* str, char** str_end) { return std::strtold(str, str_end); } template absl::optional ParseFloatingPoint(const char* str) { RTC_DCHECK(str); if (*str == '\0') return absl::nullopt; char* end = nullptr; errno = 0; const T value = StrToT(str, &end); if (end && *end == '\0' && errno == 0) { return value; } return absl::nullopt; } template absl::optional ParseFloatingPoint(const char* str); template absl::optional ParseFloatingPoint(const char* str); template absl::optional ParseFloatingPoint(const char* str); } // namespace string_to_number_internal } // namespace rtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/string_to_number.h0000664000175000017500000001112614475643423023470 0ustar00arunarun/* * Copyright 2017 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_STRING_TO_NUMBER_H_ #define RTC_BASE_STRING_TO_NUMBER_H_ #include #include #include #include "absl/types/optional.h" namespace rtc { // This file declares a family of functions to parse integers from strings. // The standard C library functions either fail to indicate errors (atoi, etc.) // or are a hassle to work with (strtol, sscanf, etc.). The standard C++ library // functions (std::stoi, etc.) indicate errors by throwing exceptions, which // are disabled in WebRTC. // // Integers are parsed using one of the following functions: // absl::optional StringToNumber(const char* str, int base = 10); // absl::optional StringToNumber(const std::string& str, // int base = 10); // // These functions parse a value from the beginning of a string into one of the // fundamental integer types, or returns an empty Optional if parsing // failed. Values outside of the range supported by the type will be // rejected. The strings must begin with a digit or a minus sign. No leading // space nor trailing contents are allowed. // By setting base to 0, one of octal, decimal or hexadecimal will be // detected from the string's prefix (0, nothing or 0x, respectively). // If non-zero, base can be set to a value between 2 and 36 inclusively. // // If desired, this interface could be extended with support for floating-point // types. namespace string_to_number_internal { // These must be (unsigned) long long, to match the signature of strto(u)ll. using unsigned_type = unsigned long long; // NOLINT(runtime/int) using signed_type = long long; // NOLINT(runtime/int) absl::optional ParseSigned(const char* str, int base); absl::optional ParseUnsigned(const char* str, int base); template absl::optional ParseFloatingPoint(const char* str); } // namespace string_to_number_internal template typename std::enable_if::value && std::is_signed::value, absl::optional>::type StringToNumber(const char* str, int base = 10) { using string_to_number_internal::signed_type; static_assert( std::numeric_limits::max() <= std::numeric_limits::max() && std::numeric_limits::lowest() >= std::numeric_limits::lowest(), "StringToNumber only supports signed integers as large as long long int"); absl::optional value = string_to_number_internal::ParseSigned(str, base); if (value && *value >= std::numeric_limits::lowest() && *value <= std::numeric_limits::max()) { return static_cast(*value); } return absl::nullopt; } template typename std::enable_if::value && std::is_unsigned::value, absl::optional>::type StringToNumber(const char* str, int base = 10) { using string_to_number_internal::unsigned_type; static_assert(std::numeric_limits::max() <= std::numeric_limits::max(), "StringToNumber only supports unsigned integers as large as " "unsigned long long int"); absl::optional value = string_to_number_internal::ParseUnsigned(str, base); if (value && *value <= std::numeric_limits::max()) { return static_cast(*value); } return absl::nullopt; } template typename std::enable_if::value, absl::optional>::type StringToNumber(const char* str, int base = 10) { static_assert( std::numeric_limits::max() <= std::numeric_limits::max(), "StringToNumber only supports floating-point numbers as large " "as long double"); return string_to_number_internal::ParseFloatingPoint(str); } // The std::string overloads only exists if there is a matching const char* // version. template auto StringToNumber(const std::string& str, int base = 10) -> decltype(StringToNumber(str.c_str(), base)) { return StringToNumber(str.c_str(), base); } } // namespace rtc #endif // RTC_BASE_STRING_TO_NUMBER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/string_utils.cc0000664000175000017500000000252314475643423022775 0ustar00arunarun/* * Copyright 2004 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/string_utils.h" namespace rtc { size_t strcpyn(char* buffer, size_t buflen, const char* source, size_t srclen /* = SIZE_UNKNOWN */) { if (buflen <= 0) return 0; if (srclen == SIZE_UNKNOWN) { srclen = strlen(source); } if (srclen >= buflen) { srclen = buflen - 1; } memcpy(buffer, source, srclen); buffer[srclen] = 0; return srclen; } static const char kWhitespace[] = " \n\r\t"; std::string string_trim(const std::string& s) { std::string::size_type first = s.find_first_not_of(kWhitespace); std::string::size_type last = s.find_last_not_of(kWhitespace); if (first == std::string::npos || last == std::string::npos) { return std::string(""); } return s.substr(first, last - first + 1); } std::string ToHex(const int i) { char buffer[50]; snprintf(buffer, sizeof(buffer), "%x", i); return std::string(buffer); } } // namespace rtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/string_utils.h0000664000175000017500000000510514475643423022636 0ustar00arunarun/* * Copyright 2004 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_STRING_UTILS_H_ #define RTC_BASE_STRING_UTILS_H_ #include #include #include #include #if defined(WEBRTC_WIN) #include #include #include #endif // WEBRTC_WIN #if defined(WEBRTC_POSIX) #include #include #endif // WEBRTC_POSIX #include namespace rtc { const size_t SIZE_UNKNOWN = static_cast(-1); // Safe version of strncpy that always nul-terminate. size_t strcpyn(char* buffer, size_t buflen, const char* source, size_t srclen = SIZE_UNKNOWN); /////////////////////////////////////////////////////////////////////////////// // UTF helpers (Windows only) /////////////////////////////////////////////////////////////////////////////// #if defined(WEBRTC_WIN) inline std::wstring ToUtf16(const char* utf8, size_t len) { if (len == 0) return std::wstring(); int len16 = ::MultiByteToWideChar(CP_UTF8, 0, utf8, static_cast(len), nullptr, 0); std::wstring ws(len16, 0); ::MultiByteToWideChar(CP_UTF8, 0, utf8, static_cast(len), &*ws.begin(), len16); return ws; } inline std::wstring ToUtf16(const std::string& str) { return ToUtf16(str.data(), str.length()); } inline std::string ToUtf8(const wchar_t* wide, size_t len) { if (len == 0) return std::string(); int len8 = ::WideCharToMultiByte(CP_UTF8, 0, wide, static_cast(len), nullptr, 0, nullptr, nullptr); std::string ns(len8, 0); ::WideCharToMultiByte(CP_UTF8, 0, wide, static_cast(len), &*ns.begin(), len8, nullptr, nullptr); return ns; } inline std::string ToUtf8(const wchar_t* wide) { return ToUtf8(wide, wcslen(wide)); } inline std::string ToUtf8(const std::wstring& wstr) { return ToUtf8(wstr.data(), wstr.length()); } #endif // WEBRTC_WIN // Remove leading and trailing whitespaces. std::string string_trim(const std::string& s); // TODO(jonasolsson): replace with absl::Hex when that becomes available. std::string ToHex(const int i); } // namespace rtc #endif // RTC_BASE_STRING_UTILS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/strings/0000775000175000017500000000000014475643423021427 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/strings/string_builder.cc0000664000175000017500000001025214475643423024752 0ustar00arunarun/* * Copyright 2018 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/strings/string_builder.h" #include #include #include #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_minmax.h" namespace rtc { SimpleStringBuilder::SimpleStringBuilder(rtc::ArrayView buffer) : buffer_(buffer) { buffer_[0] = '\0'; RTC_DCHECK(IsConsistent()); } SimpleStringBuilder& SimpleStringBuilder::operator<<(const char* str) { return Append(str, strlen(str)); } SimpleStringBuilder& SimpleStringBuilder::operator<<(char ch) { return Append(&ch, 1); } SimpleStringBuilder& SimpleStringBuilder::operator<<(const std::string& str) { return Append(str.c_str(), str.length()); } // Numeric conversion routines. // // We use std::[v]snprintf instead of std::to_string because: // * std::to_string relies on the current locale for formatting purposes, // and therefore concurrent calls to std::to_string from multiple threads // may result in partial serialization of calls // * snprintf allows us to print the number directly into our buffer. // * avoid allocating a std::string (potential heap alloc). // TODO(tommi): Switch to std::to_chars in C++17. SimpleStringBuilder& SimpleStringBuilder::operator<<(int i) { return AppendFormat("%d", i); } SimpleStringBuilder& SimpleStringBuilder::operator<<(unsigned i) { return AppendFormat("%u", i); } SimpleStringBuilder& SimpleStringBuilder::operator<<(long i) { // NOLINT return AppendFormat("%ld", i); } SimpleStringBuilder& SimpleStringBuilder::operator<<(long long i) { // NOLINT return AppendFormat("%lld", i); } SimpleStringBuilder& SimpleStringBuilder::operator<<( unsigned long i) { // NOLINT return AppendFormat("%lu", i); } SimpleStringBuilder& SimpleStringBuilder::operator<<( unsigned long long i) { // NOLINT return AppendFormat("%llu", i); } SimpleStringBuilder& SimpleStringBuilder::operator<<(float f) { return AppendFormat("%g", f); } SimpleStringBuilder& SimpleStringBuilder::operator<<(double f) { return AppendFormat("%g", f); } SimpleStringBuilder& SimpleStringBuilder::operator<<(long double f) { return AppendFormat("%Lg", f); } SimpleStringBuilder& SimpleStringBuilder::AppendFormat(const char* fmt, ...) { va_list args; va_start(args, fmt); const int len = std::vsnprintf(&buffer_[size_], buffer_.size() - size_, fmt, args); if (len >= 0) { const size_t chars_added = rtc::SafeMin(len, buffer_.size() - 1 - size_); size_ += chars_added; RTC_DCHECK_EQ(len, chars_added) << "Buffer size was insufficient"; } else { // This should never happen, but we're paranoid, so re-write the // terminator in case vsnprintf() overwrote it. RTC_NOTREACHED(); buffer_[size_] = '\0'; } va_end(args); RTC_DCHECK(IsConsistent()); return *this; } SimpleStringBuilder& SimpleStringBuilder::Append(const char* str, size_t length) { RTC_DCHECK_LT(size_ + length, buffer_.size()) << "Buffer size was insufficient"; const size_t chars_added = rtc::SafeMin(length, buffer_.size() - size_ - 1); memcpy(&buffer_[size_], str, chars_added); size_ += chars_added; buffer_[size_] = '\0'; RTC_DCHECK(IsConsistent()); return *this; } StringBuilder& StringBuilder::AppendFormat(const char* fmt, ...) { va_list args, copy; va_start(args, fmt); va_copy(copy, args); const int predicted_length = std::vsnprintf(nullptr, 0, fmt, copy); va_end(copy); RTC_DCHECK_GE(predicted_length, 0); if (predicted_length > 0) { const size_t size = str_.size(); str_.resize(size + predicted_length); // Pass "+ 1" to vsnprintf to include space for the '\0'. const int actual_length = std::vsnprintf(&str_[size], predicted_length + 1, fmt, args); RTC_DCHECK_GE(actual_length, 0); } va_end(args); return *this; } } // namespace rtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/strings/string_builder.h0000664000175000017500000001250214475643423024614 0ustar00arunarun/* * Copyright 2018 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_STRINGS_STRING_BUILDER_H_ #define RTC_BASE_STRINGS_STRING_BUILDER_H_ #include #include #include #include "absl/strings/string_view.h" #include "api/array_view.h" #include "rtc_base/string_encode.h" namespace rtc { // This is a minimalistic string builder class meant to cover the most cases of // when you might otherwise be tempted to use a stringstream (discouraged for // anything except logging). It uses a fixed-size buffer provided by the caller // and concatenates strings and numbers into it, allowing the results to be // read via |str()|. class SimpleStringBuilder { public: explicit SimpleStringBuilder(rtc::ArrayView buffer); SimpleStringBuilder(const SimpleStringBuilder&) = delete; SimpleStringBuilder& operator=(const SimpleStringBuilder&) = delete; SimpleStringBuilder& operator<<(const char* str); SimpleStringBuilder& operator<<(char ch); SimpleStringBuilder& operator<<(const std::string& str); SimpleStringBuilder& operator<<(int i); SimpleStringBuilder& operator<<(unsigned i); SimpleStringBuilder& operator<<(long i); // NOLINT SimpleStringBuilder& operator<<(long long i); // NOLINT SimpleStringBuilder& operator<<(unsigned long i); // NOLINT SimpleStringBuilder& operator<<(unsigned long long i); // NOLINT SimpleStringBuilder& operator<<(float f); SimpleStringBuilder& operator<<(double f); SimpleStringBuilder& operator<<(long double f); // Returns a pointer to the built string. The name |str()| is borrowed for // compatibility reasons as we replace usage of stringstream throughout the // code base. const char* str() const { return buffer_.data(); } // Returns the length of the string. The name |size()| is picked for STL // compatibility reasons. size_t size() const { return size_; } // Allows appending a printf style formatted string. #if defined(__GNUC__) __attribute__((__format__(__printf__, 2, 3))) #endif SimpleStringBuilder& AppendFormat(const char* fmt, ...); // An alternate way from operator<<() to append a string. This variant is // slightly more efficient when the length of the string to append, is known. SimpleStringBuilder& Append(const char* str, size_t length); private: bool IsConsistent() const { return size_ <= buffer_.size() - 1 && buffer_[size_] == '\0'; } // An always-zero-terminated fixed-size buffer that we write to. The fixed // size allows the buffer to be stack allocated, which helps performance. // Having a fixed size is furthermore useful to avoid unnecessary resizing // while building it. const rtc::ArrayView buffer_; // Represents the number of characters written to the buffer. // This does not include the terminating '\0'. size_t size_ = 0; }; // A string builder that supports dynamic resizing while building a string. // The class is based around an instance of std::string and allows moving // ownership out of the class once the string has been built. // Note that this class uses the heap for allocations, so SimpleStringBuilder // might be more efficient for some use cases. class StringBuilder { public: StringBuilder() {} explicit StringBuilder(absl::string_view s) : str_(s) {} // TODO(tommi): Support construction from StringBuilder? StringBuilder(const StringBuilder&) = delete; StringBuilder& operator=(const StringBuilder&) = delete; StringBuilder& operator<<(const absl::string_view str) { str_.append(str.data(), str.length()); return *this; } StringBuilder& operator<<(char c) = delete; StringBuilder& operator<<(int i) { str_ += rtc::ToString(i); return *this; } StringBuilder& operator<<(unsigned i) { str_ += rtc::ToString(i); return *this; } StringBuilder& operator<<(long i) { // NOLINT str_ += rtc::ToString(i); return *this; } StringBuilder& operator<<(long long i) { // NOLINT str_ += rtc::ToString(i); return *this; } StringBuilder& operator<<(unsigned long i) { // NOLINT str_ += rtc::ToString(i); return *this; } StringBuilder& operator<<(unsigned long long i) { // NOLINT str_ += rtc::ToString(i); return *this; } StringBuilder& operator<<(float f) { str_ += rtc::ToString(f); return *this; } StringBuilder& operator<<(double f) { str_ += rtc::ToString(f); return *this; } StringBuilder& operator<<(long double f) { str_ += rtc::ToString(f); return *this; } const std::string& str() const { return str_; } void Clear() { str_.clear(); } size_t size() const { return str_.size(); } std::string Release() { std::string ret = std::move(str_); str_.clear(); return ret; } // Allows appending a printf style formatted string. StringBuilder& AppendFormat(const char* fmt, ...) #if defined(__GNUC__) __attribute__((__format__(__printf__, 2, 3))) #endif ; private: std::string str_; }; } // namespace rtc #endif // RTC_BASE_STRINGS_STRING_BUILDER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/swap_queue.h0000664000175000017500000002220114475643423022262 0ustar00arunarun/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_SWAP_QUEUE_H_ #define RTC_BASE_SWAP_QUEUE_H_ #include #include #include #include #include "rtc_base/checks.h" #include "rtc_base/system/unused.h" namespace webrtc { namespace internal { // (Internal; please don't use outside this file.) template bool NoopSwapQueueItemVerifierFunction(const T&) { return true; } } // namespace internal // Functor to use when supplying a verifier function for the queue. template class SwapQueueItemVerifier { public: bool operator()(const T& t) const { return QueueItemVerifierFunction(t); } }; // This class is a fixed-size queue. A single producer calls Insert() to insert // an element of type T at the back of the queue, and a single consumer calls // Remove() to remove an element from the front of the queue. It's safe for the // producer and the consumer to access the queue concurrently, from different // threads. // // To avoid the construction, copying, and destruction of Ts that a naive // queue implementation would require, for each "full" T passed from // producer to consumer, SwapQueue passes an "empty" T in the other // direction (an "empty" T is one that contains nothing of value for the // consumer). This bidirectional movement is implemented with swap(). // // // Create queue: // Bottle proto(568); // Prepare an empty Bottle. Heap allocates space for // // 568 ml. // SwapQueue q(N, proto); // Init queue with N copies of proto. // // Each copy allocates on the heap. // // Producer pseudo-code: // Bottle b(568); // Prepare an empty Bottle. Heap allocates space for 568 ml. // loop { // b.Fill(amount); // Where amount <= 568 ml. // q.Insert(&b); // Swap our full Bottle for an empty one from q. // } // // // Consumer pseudo-code: // Bottle b(568); // Prepare an empty Bottle. Heap allocates space for 568 ml. // loop { // q.Remove(&b); // Swap our empty Bottle for the next-in-line full Bottle. // Drink(&b); // } // // For a well-behaved Bottle class, there are no allocations in the // producer, since it just fills an empty Bottle that's already large // enough; no deallocations in the consumer, since it returns each empty // Bottle to the queue after having drunk it; and no copies along the // way, since the queue uses swap() everywhere to move full Bottles in // one direction and empty ones in the other. template > class SwapQueue { public: // Creates a queue of size size and fills it with default constructed Ts. explicit SwapQueue(size_t size) : queue_(size) { RTC_DCHECK(VerifyQueueSlots()); } // Same as above and accepts an item verification functor. SwapQueue(size_t size, const QueueItemVerifier& queue_item_verifier) : queue_item_verifier_(queue_item_verifier), queue_(size) { RTC_DCHECK(VerifyQueueSlots()); } // Creates a queue of size size and fills it with copies of prototype. SwapQueue(size_t size, const T& prototype) : queue_(size, prototype) { RTC_DCHECK(VerifyQueueSlots()); } // Same as above and accepts an item verification functor. SwapQueue(size_t size, const T& prototype, const QueueItemVerifier& queue_item_verifier) : queue_item_verifier_(queue_item_verifier), queue_(size, prototype) { RTC_DCHECK(VerifyQueueSlots()); } // Resets the queue to have zero content while maintaining the queue size. // Just like Remove(), this can only be called (safely) from the // consumer. void Clear() { // Drop all non-empty elements by resetting num_elements_ and incrementing // next_read_index_ by the previous value of num_elements_. Relaxed memory // ordering is sufficient since the dropped elements are not accessed. next_read_index_ += std::atomic_exchange_explicit( &num_elements_, size_t{0}, std::memory_order_relaxed); if (next_read_index_ >= queue_.size()) { next_read_index_ -= queue_.size(); } RTC_DCHECK_LT(next_read_index_, queue_.size()); } // Inserts a "full" T at the back of the queue by swapping *input with an // "empty" T from the queue. // Returns true if the item was inserted or false if not (the queue was full). // When specified, the T given in *input must pass the ItemVerifier() test. // The contents of *input after the call are then also guaranteed to pass the // ItemVerifier() test. bool Insert(T* input) RTC_WARN_UNUSED_RESULT { RTC_DCHECK(input); RTC_DCHECK(queue_item_verifier_(*input)); // Load the value of num_elements_. Acquire memory ordering prevents reads // and writes to queue_[next_write_index_] to be reordered to before the // load. (That element might be accessed by a concurrent call to Remove() // until the load finishes.) if (std::atomic_load_explicit(&num_elements_, std::memory_order_acquire) == queue_.size()) { return false; } using std::swap; swap(*input, queue_[next_write_index_]); // Increment the value of num_elements_ to account for the inserted element. // Release memory ordering prevents the reads and writes to // queue_[next_write_index_] to be reordered to after the increment. (Once // the increment has finished, Remove() might start accessing that element.) const size_t old_num_elements = std::atomic_fetch_add_explicit( &num_elements_, size_t{1}, std::memory_order_release); ++next_write_index_; if (next_write_index_ == queue_.size()) { next_write_index_ = 0; } RTC_DCHECK_LT(next_write_index_, queue_.size()); RTC_DCHECK_LT(old_num_elements, queue_.size()); return true; } // Removes the frontmost "full" T from the queue by swapping it with // the "empty" T in *output. // Returns true if an item could be removed or false if not (the queue was // empty). When specified, The T given in *output must pass the ItemVerifier() // test and the contents of *output after the call are then also guaranteed to // pass the ItemVerifier() test. bool Remove(T* output) RTC_WARN_UNUSED_RESULT { RTC_DCHECK(output); RTC_DCHECK(queue_item_verifier_(*output)); // Load the value of num_elements_. Acquire memory ordering prevents reads // and writes to queue_[next_read_index_] to be reordered to before the // load. (That element might be accessed by a concurrent call to Insert() // until the load finishes.) if (std::atomic_load_explicit(&num_elements_, std::memory_order_acquire) == 0) { return false; } using std::swap; swap(*output, queue_[next_read_index_]); // Decrement the value of num_elements_ to account for the removed element. // Release memory ordering prevents the reads and writes to // queue_[next_write_index_] to be reordered to after the decrement. (Once // the decrement has finished, Insert() might start accessing that element.) std::atomic_fetch_sub_explicit(&num_elements_, size_t{1}, std::memory_order_release); ++next_read_index_; if (next_read_index_ == queue_.size()) { next_read_index_ = 0; } RTC_DCHECK_LT(next_read_index_, queue_.size()); return true; } // Returns the current number of elements in the queue. Since elements may be // concurrently added to the queue, the caller must treat this as a lower // bound, not an exact count. // May only be called by the consumer. size_t SizeAtLeast() const { // Acquire memory ordering ensures that we wait for the producer to finish // inserting any element in progress. return std::atomic_load_explicit(&num_elements_, std::memory_order_acquire); } private: // Verify that the queue slots complies with the ItemVerifier test. This // function is not thread-safe and can only be used in the constructors. bool VerifyQueueSlots() { for (const auto& v : queue_) { RTC_DCHECK(queue_item_verifier_(v)); } return true; } // TODO(peah): Change this to use std::function() once we can use C++11 std // lib. QueueItemVerifier queue_item_verifier_; // Only accessed by the single producer. size_t next_write_index_ = 0; // Only accessed by the single consumer. size_t next_read_index_ = 0; // Accessed by both the producer and the consumer and used for synchronization // between them. std::atomic num_elements_{0}; // The elements of the queue are acced by both the producer and the consumer, // mediated by num_elements_. queue_.size() is constant. std::vector queue_; SwapQueue(const SwapQueue&) = delete; SwapQueue& operator=(const SwapQueue&) = delete; }; } // namespace webrtc #endif // RTC_BASE_SWAP_QUEUE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/synchronization/0000775000175000017500000000000014475643423023177 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/synchronization/BUILD.gn0000664000175000017500000000562314475643423024372 0ustar00arunarun# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../../webrtc.gni") if (is_android) { import("//build/config/android/config.gni") import("//build/config/android/rules.gni") } rtc_library("yield") { sources = [ "yield.cc", "yield.h", ] deps = [] } rtc_library("mutex") { sources = [ "mutex.cc", "mutex.h", "mutex_critical_section.h", "mutex_pthread.h", ] if (rtc_use_absl_mutex) { sources += [ "mutex_abseil.h" ] } deps = [ ":yield", "..:checks", "..:macromagic", "..:platform_thread_types", "../system:unused", ] absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers" ] if (rtc_use_absl_mutex) { absl_deps += [ "//third_party/abseil-cpp/absl/synchronization" ] } } rtc_library("rw_lock_wrapper") { public = [ "rw_lock_wrapper.h" ] sources = [ "rw_lock_wrapper.cc" ] deps = [ "..:macromagic" ] if (is_win) { sources += [ "rw_lock_win.cc", "rw_lock_win.h", ] deps += [ "..:logging" ] } else { sources += [ "rw_lock_posix.cc", "rw_lock_posix.h", ] } } rtc_library("sequence_checker") { sources = [ "sequence_checker.cc", "sequence_checker.h", ] deps = [ ":mutex", "..:checks", "..:criticalsection", "..:macromagic", "..:platform_thread_types", "..:stringutils", "../../api/task_queue", "../system:rtc_export", ] } rtc_library("yield_policy") { sources = [ "yield_policy.cc", "yield_policy.h", ] deps = [ "..:checks" ] absl_deps = [ "//third_party/abseil-cpp/absl/base:config", "//third_party/abseil-cpp/absl/base:core_headers", ] } if (rtc_include_tests) { rtc_library("synchronization_unittests") { testonly = true sources = [ "mutex_unittest.cc", "yield_policy_unittest.cc", ] deps = [ ":mutex", ":yield", ":yield_policy", "..:checks", "..:macromagic", "..:rtc_base", "..:rtc_event", "../../test:test_support", "//third_party/google_benchmark", ] } rtc_library("mutex_benchmark") { testonly = true sources = [ "mutex_benchmark.cc" ] deps = [ ":mutex", "../system:unused", "//third_party/google_benchmark", ] } rtc_library("sequence_checker_unittests") { testonly = true sources = [ "sequence_checker_unittest.cc" ] deps = [ ":sequence_checker", "..:checks", "..:rtc_base_approved", "..:task_queue_for_test", "../../api:function_view", "../../test:test_main", "../../test:test_support", ] } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/synchronization/mutex.cc0000664000175000017500000000202014475643423024642 0ustar00arunarun/* * Copyright 2020 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/synchronization/mutex.h" #include "rtc_base/checks.h" #include "rtc_base/synchronization/yield.h" namespace webrtc { #if !defined(WEBRTC_ABSL_MUTEX) void GlobalMutex::Lock() { while (mutex_locked_.exchange(1)) { YieldCurrentThread(); } } void GlobalMutex::Unlock() { int old = mutex_locked_.exchange(0); RTC_DCHECK_EQ(old, 1) << "Unlock called without calling Lock first"; } GlobalMutexLock::GlobalMutexLock(GlobalMutex* mutex) : mutex_(mutex) { mutex_->Lock(); } GlobalMutexLock::~GlobalMutexLock() { mutex_->Unlock(); } #endif // #if !defined(WEBRTC_ABSL_MUTEX) } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/synchronization/mutex.h0000664000175000017500000000573614475643423024525 0ustar00arunarun/* * Copyright 2020 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_SYNCHRONIZATION_MUTEX_H_ #define RTC_BASE_SYNCHRONIZATION_MUTEX_H_ #include #include "absl/base/const_init.h" #include "rtc_base/checks.h" #include "rtc_base/system/unused.h" #include "rtc_base/thread_annotations.h" #if defined(WEBRTC_ABSL_MUTEX) #include "rtc_base/synchronization/mutex_abseil.h" // nogncheck #elif defined(WEBRTC_WIN) #include "rtc_base/synchronization/mutex_critical_section.h" #elif defined(WEBRTC_POSIX) #include "rtc_base/synchronization/mutex_pthread.h" #else #error Unsupported platform. #endif namespace webrtc { // The Mutex guarantees exclusive access and aims to follow Abseil semantics // (i.e. non-reentrant etc). class RTC_LOCKABLE Mutex final { public: Mutex() = default; Mutex(const Mutex&) = delete; Mutex& operator=(const Mutex&) = delete; void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { impl_.Lock(); } RTC_WARN_UNUSED_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { return impl_.TryLock(); } void Unlock() RTC_UNLOCK_FUNCTION() { impl_.Unlock(); } private: MutexImpl impl_; }; // MutexLock, for serializing execution through a scope. class RTC_SCOPED_LOCKABLE MutexLock final { public: MutexLock(const MutexLock&) = delete; MutexLock& operator=(const MutexLock&) = delete; explicit MutexLock(Mutex* mutex) RTC_EXCLUSIVE_LOCK_FUNCTION(mutex) : mutex_(mutex) { mutex->Lock(); } ~MutexLock() RTC_UNLOCK_FUNCTION() { mutex_->Unlock(); } private: Mutex* mutex_; }; // A mutex used to protect global variables. Do NOT use for other purposes. #if defined(WEBRTC_ABSL_MUTEX) using GlobalMutex = absl::Mutex; using GlobalMutexLock = absl::MutexLock; #else class RTC_LOCKABLE GlobalMutex final { public: GlobalMutex(const GlobalMutex&) = delete; GlobalMutex& operator=(const GlobalMutex&) = delete; constexpr explicit GlobalMutex(absl::ConstInitType /*unused*/) : mutex_locked_(0) {} void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION(); void Unlock() RTC_UNLOCK_FUNCTION(); private: std::atomic mutex_locked_; // 0 means lock not taken, 1 means taken. }; // GlobalMutexLock, for serializing execution through a scope. class RTC_SCOPED_LOCKABLE GlobalMutexLock final { public: GlobalMutexLock(const GlobalMutexLock&) = delete; GlobalMutexLock& operator=(const GlobalMutexLock&) = delete; explicit GlobalMutexLock(GlobalMutex* mutex) RTC_EXCLUSIVE_LOCK_FUNCTION(mutex_); ~GlobalMutexLock() RTC_UNLOCK_FUNCTION(); private: GlobalMutex* mutex_; }; #endif // if defined(WEBRTC_ABSL_MUTEX) } // namespace webrtc #endif // RTC_BASE_SYNCHRONIZATION_MUTEX_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/synchronization/mutex_critical_section.h0000664000175000017500000000332214475643423030110 0ustar00arunarun/* * Copyright 2020 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_SYNCHRONIZATION_MUTEX_CRITICAL_SECTION_H_ #define RTC_BASE_SYNCHRONIZATION_MUTEX_CRITICAL_SECTION_H_ #if defined(WEBRTC_WIN) // clang-format off // clang formating would change include order. // Include winsock2.h before including to maintain consistency with // win32.h. To include win32.h directly, it must be broken out into its own // build target. #include #include #include // must come after windows headers. // clang-format on #include "rtc_base/thread_annotations.h" namespace webrtc { class RTC_LOCKABLE MutexImpl final { public: MutexImpl() { InitializeCriticalSection(&critical_section_); } MutexImpl(const MutexImpl&) = delete; MutexImpl& operator=(const MutexImpl&) = delete; ~MutexImpl() { DeleteCriticalSection(&critical_section_); } void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { EnterCriticalSection(&critical_section_); } RTC_WARN_UNUSED_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { return TryEnterCriticalSection(&critical_section_) != FALSE; } void Unlock() RTC_UNLOCK_FUNCTION() { LeaveCriticalSection(&critical_section_); } private: CRITICAL_SECTION critical_section_; }; } // namespace webrtc #endif // #if defined(WEBRTC_WIN) #endif // RTC_BASE_SYNCHRONIZATION_MUTEX_CRITICAL_SECTION_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/synchronization/mutex_pthread.h0000664000175000017500000000317614475643423026230 0ustar00arunarun/* * Copyright 2020 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_SYNCHRONIZATION_MUTEX_PTHREAD_H_ #define RTC_BASE_SYNCHRONIZATION_MUTEX_PTHREAD_H_ #if defined(WEBRTC_POSIX) #include #if defined(WEBRTC_MAC) #include #endif #include "rtc_base/thread_annotations.h" namespace webrtc { class RTC_LOCKABLE MutexImpl final { public: MutexImpl() { pthread_mutexattr_t mutex_attribute; pthread_mutexattr_init(&mutex_attribute); #if defined(WEBRTC_MAC) pthread_mutexattr_setpolicy_np(&mutex_attribute, _PTHREAD_MUTEX_POLICY_FIRSTFIT); #endif pthread_mutex_init(&mutex_, &mutex_attribute); pthread_mutexattr_destroy(&mutex_attribute); } MutexImpl(const MutexImpl&) = delete; MutexImpl& operator=(const MutexImpl&) = delete; ~MutexImpl() { pthread_mutex_destroy(&mutex_); } void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { pthread_mutex_lock(&mutex_); } RTC_WARN_UNUSED_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { return pthread_mutex_trylock(&mutex_) == 0; } void Unlock() RTC_UNLOCK_FUNCTION() { pthread_mutex_unlock(&mutex_); } private: pthread_mutex_t mutex_; }; } // namespace webrtc #endif // #if defined(WEBRTC_POSIX) #endif // RTC_BASE_SYNCHRONIZATION_MUTEX_PTHREAD_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/synchronization/rw_lock_posix.cc0000664000175000017500000000225214475643423026371 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/synchronization/rw_lock_posix.h" #include namespace webrtc { RWLockPosix::RWLockPosix() : lock_() {} RWLockPosix::~RWLockPosix() { pthread_rwlock_destroy(&lock_); } RWLockPosix* RWLockPosix::Create() { RWLockPosix* ret_val = new RWLockPosix(); if (!ret_val->Init()) { delete ret_val; return NULL; } return ret_val; } bool RWLockPosix::Init() { return pthread_rwlock_init(&lock_, 0) == 0; } void RWLockPosix::AcquireLockExclusive() { pthread_rwlock_wrlock(&lock_); } void RWLockPosix::ReleaseLockExclusive() { pthread_rwlock_unlock(&lock_); } void RWLockPosix::AcquireLockShared() { pthread_rwlock_rdlock(&lock_); } void RWLockPosix::ReleaseLockShared() { pthread_rwlock_unlock(&lock_); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/synchronization/rw_lock_posix.h0000664000175000017500000000200614475643423026230 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_SYNCHRONIZATION_RW_LOCK_POSIX_H_ #define RTC_BASE_SYNCHRONIZATION_RW_LOCK_POSIX_H_ #include #include "rtc_base/synchronization/rw_lock_wrapper.h" namespace webrtc { class RWLockPosix : public RWLockWrapper { public: static RWLockPosix* Create(); ~RWLockPosix() override; void AcquireLockExclusive() override; void ReleaseLockExclusive() override; void AcquireLockShared() override; void ReleaseLockShared() override; private: RWLockPosix(); bool Init(); pthread_rwlock_t lock_; }; } // namespace webrtc #endif // RTC_BASE_SYNCHRONIZATION_RW_LOCK_POSIX_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/synchronization/rw_lock_win.cc0000664000175000017500000000170214475643423026023 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/synchronization/rw_lock_win.h" #include "rtc_base/logging.h" namespace webrtc { RWLockWin::RWLockWin() { InitializeSRWLock(&lock_); } RWLockWin* RWLockWin::Create() { return new RWLockWin(); } void RWLockWin::AcquireLockExclusive() { AcquireSRWLockExclusive(&lock_); } void RWLockWin::ReleaseLockExclusive() { ReleaseSRWLockExclusive(&lock_); } void RWLockWin::AcquireLockShared() { AcquireSRWLockShared(&lock_); } void RWLockWin::ReleaseLockShared() { ReleaseSRWLockShared(&lock_); } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/synchronization/rw_lock_win.h0000664000175000017500000000170714475643423025672 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_SYNCHRONIZATION_RW_LOCK_WIN_H_ #define RTC_BASE_SYNCHRONIZATION_RW_LOCK_WIN_H_ #include #include "rtc_base/synchronization/rw_lock_wrapper.h" namespace webrtc { class RWLockWin : public RWLockWrapper { public: static RWLockWin* Create(); void AcquireLockExclusive() override; void ReleaseLockExclusive() override; void AcquireLockShared() override; void ReleaseLockShared() override; private: RWLockWin(); SRWLOCK lock_; }; } // namespace webrtc #endif // RTC_BASE_SYNCHRONIZATION_RW_LOCK_WIN_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/synchronization/rw_lock_wrapper.cc0000664000175000017500000000142314475643423026706 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/synchronization/rw_lock_wrapper.h" #if defined(_WIN32) #include "rtc_base/synchronization/rw_lock_win.h" #else #include "rtc_base/synchronization/rw_lock_posix.h" #endif namespace webrtc { RWLockWrapper* RWLockWrapper::CreateRWLock() { #ifdef _WIN32 return RWLockWin::Create(); #else return RWLockPosix::Create(); #endif } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/synchronization/rw_lock_wrapper.h0000664000175000017500000000377714475643423026566 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_SYNCHRONIZATION_RW_LOCK_WRAPPER_H_ #define RTC_BASE_SYNCHRONIZATION_RW_LOCK_WRAPPER_H_ #include "rtc_base/thread_annotations.h" // Note, Windows pre-Vista version of RW locks are not supported natively. For // these OSs regular critical sections have been used to approximate RW lock // functionality and will therefore have worse performance. namespace webrtc { class RTC_LOCKABLE RWLockWrapper { public: static RWLockWrapper* CreateRWLock(); virtual ~RWLockWrapper() {} virtual void AcquireLockExclusive() RTC_EXCLUSIVE_LOCK_FUNCTION() = 0; virtual void ReleaseLockExclusive() RTC_UNLOCK_FUNCTION() = 0; virtual void AcquireLockShared() RTC_SHARED_LOCK_FUNCTION() = 0; virtual void ReleaseLockShared() RTC_UNLOCK_FUNCTION() = 0; }; // RAII extensions of the RW lock. Prevents Acquire/Release missmatches and // provides more compact locking syntax. class RTC_SCOPED_LOCKABLE ReadLockScoped { public: explicit ReadLockScoped(RWLockWrapper& rw_lock) RTC_SHARED_LOCK_FUNCTION(rw_lock) : rw_lock_(rw_lock) { rw_lock_.AcquireLockShared(); } ~ReadLockScoped() RTC_UNLOCK_FUNCTION() { rw_lock_.ReleaseLockShared(); } private: RWLockWrapper& rw_lock_; }; class RTC_SCOPED_LOCKABLE WriteLockScoped { public: explicit WriteLockScoped(RWLockWrapper& rw_lock) RTC_EXCLUSIVE_LOCK_FUNCTION(rw_lock) : rw_lock_(rw_lock) { rw_lock_.AcquireLockExclusive(); } ~WriteLockScoped() RTC_UNLOCK_FUNCTION() { rw_lock_.ReleaseLockExclusive(); } private: RWLockWrapper& rw_lock_; }; } // namespace webrtc #endif // RTC_BASE_SYNCHRONIZATION_RW_LOCK_WRAPPER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/synchronization/sequence_checker.cc0000664000175000017500000000722214475643423027005 0ustar00arunarun/* * Copyright 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/synchronization/sequence_checker.h" #if defined(WEBRTC_MAC) #include #endif #include "rtc_base/strings/string_builder.h" namespace webrtc { namespace { // On Mac, returns the label of the current dispatch queue; elsewhere, return // null. const void* GetSystemQueueRef() { #if defined(WEBRTC_MAC) return dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL); #else return nullptr; #endif } } // namespace std::string ExpectationToString(const webrtc::SequenceChecker* checker) { #if RTC_DCHECK_IS_ON return checker->ExpectationToString(); #endif return std::string(); } SequenceCheckerImpl::SequenceCheckerImpl() : attached_(true), valid_thread_(rtc::CurrentThreadRef()), valid_queue_(TaskQueueBase::Current()), valid_system_queue_(GetSystemQueueRef()) {} SequenceCheckerImpl::~SequenceCheckerImpl() = default; bool SequenceCheckerImpl::IsCurrent() const { const TaskQueueBase* const current_queue = TaskQueueBase::Current(); const rtc::PlatformThreadRef current_thread = rtc::CurrentThreadRef(); const void* const current_system_queue = GetSystemQueueRef(); MutexLock scoped_lock(&lock_); if (!attached_) { // Previously detached. attached_ = true; valid_thread_ = current_thread; valid_queue_ = current_queue; valid_system_queue_ = current_system_queue; return true; } if (valid_queue_ || current_queue) { return valid_queue_ == current_queue; } if (valid_system_queue_ && valid_system_queue_ == current_system_queue) { return true; } return rtc::IsThreadRefEqual(valid_thread_, current_thread); } void SequenceCheckerImpl::Detach() { MutexLock scoped_lock(&lock_); attached_ = false; // We don't need to touch the other members here, they will be // reset on the next call to IsCurrent(). } #if RTC_DCHECK_IS_ON std::string SequenceCheckerImpl::ExpectationToString() const { const TaskQueueBase* const current_queue = TaskQueueBase::Current(); const rtc::PlatformThreadRef current_thread = rtc::CurrentThreadRef(); const void* const current_system_queue = GetSystemQueueRef(); MutexLock scoped_lock(&lock_); if (!attached_) return "Checker currently not attached."; // The format of the string is meant to compliment the one we have inside of // FatalLog() (checks.cc). Example: // // # Expected: TQ: 0x0 SysQ: 0x7fff69541330 Thread: 0x11dcf6dc0 // # Actual: TQ: 0x7fa8f0604190 SysQ: 0x7fa8f0604a30 Thread: 0x700006f1a000 // TaskQueue doesn't match rtc::StringBuilder message; message.AppendFormat( "# Expected: TQ: %p SysQ: %p Thread: %p\n" "# Actual: TQ: %p SysQ: %p Thread: %p\n", valid_queue_, valid_system_queue_, reinterpret_cast(valid_thread_), current_queue, current_system_queue, reinterpret_cast(current_thread)); if ((valid_queue_ || current_queue) && valid_queue_ != current_queue) { message << "TaskQueue doesn't match\n"; } else if (valid_system_queue_ && valid_system_queue_ != current_system_queue) { message << "System queue doesn't match\n"; } else if (!rtc::IsThreadRefEqual(valid_thread_, current_thread)) { message << "Threads don't match\n"; } return message.Release(); } #endif // RTC_DCHECK_IS_ON } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/synchronization/sequence_checker.h0000664000175000017500000001402514475643423026646 0ustar00arunarun/* * Copyright 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_ #define RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_ #include #include "api/task_queue/task_queue_base.h" #include "rtc_base/platform_thread_types.h" #include "rtc_base/synchronization/mutex.h" #include "rtc_base/system/rtc_export.h" #include "rtc_base/thread_annotations.h" namespace webrtc { // Real implementation of SequenceChecker, for use in debug mode, or // for temporary use in release mode (e.g. to RTC_CHECK on a threading issue // seen only in the wild). // // Note: You should almost always use the SequenceChecker class to get the // right version for your build configuration. class RTC_EXPORT SequenceCheckerImpl { public: SequenceCheckerImpl(); ~SequenceCheckerImpl(); bool IsCurrent() const; // Changes the task queue or thread that is checked for in IsCurrent. This can // be useful when an object may be created on one task queue / thread and then // used exclusively on another thread. void Detach(); // Returns a string that is formatted to match with the error string printed // by RTC_CHECK() when a condition is not met. // This is used in conjunction with the RTC_DCHECK_RUN_ON() macro. std::string ExpectationToString() const; private: mutable Mutex lock_; // These are mutable so that IsCurrent can set them. mutable bool attached_ RTC_GUARDED_BY(lock_); mutable rtc::PlatformThreadRef valid_thread_ RTC_GUARDED_BY(lock_); mutable const TaskQueueBase* valid_queue_ RTC_GUARDED_BY(lock_); mutable const void* valid_system_queue_ RTC_GUARDED_BY(lock_); }; // Do nothing implementation, for use in release mode. // // Note: You should almost always use the SequenceChecker class to get the // right version for your build configuration. class SequenceCheckerDoNothing { public: bool IsCurrent() const { return true; } void Detach() {} }; // SequenceChecker is a helper class used to help verify that some methods // of a class are called on the same task queue or thread. A // SequenceChecker is bound to a a task queue if the object is // created on a task queue, or a thread otherwise. // // // Example: // class MyClass { // public: // void Foo() { // RTC_DCHECK_RUN_ON(sequence_checker_); // ... (do stuff) ... // } // // private: // SequenceChecker sequence_checker_; // } // // In Release mode, IsCurrent will always return true. #if RTC_DCHECK_IS_ON class RTC_LOCKABLE SequenceChecker : public SequenceCheckerImpl {}; #else class RTC_LOCKABLE SequenceChecker : public SequenceCheckerDoNothing {}; #endif // RTC_ENABLE_THREAD_CHECKER namespace webrtc_seq_check_impl { // Helper class used by RTC_DCHECK_RUN_ON (see example usage below). class RTC_SCOPED_LOCKABLE SequenceCheckerScope { public: template explicit SequenceCheckerScope(const ThreadLikeObject* thread_like_object) RTC_EXCLUSIVE_LOCK_FUNCTION(thread_like_object) {} SequenceCheckerScope(const SequenceCheckerScope&) = delete; SequenceCheckerScope& operator=(const SequenceCheckerScope&) = delete; ~SequenceCheckerScope() RTC_UNLOCK_FUNCTION() {} template static bool IsCurrent(const ThreadLikeObject* thread_like_object) { return thread_like_object->IsCurrent(); } }; } // namespace webrtc_seq_check_impl } // namespace webrtc // RTC_RUN_ON/RTC_GUARDED_BY/RTC_DCHECK_RUN_ON macros allows to annotate // variables are accessed from same thread/task queue. // Using tools designed to check mutexes, it checks at compile time everywhere // variable is access, there is a run-time dcheck thread/task queue is correct. // // class ThreadExample { // public: // void NeedVar1() { // RTC_DCHECK_RUN_ON(network_thread_); // transport_->Send(); // } // // private: // rtc::Thread* network_thread_; // int transport_ RTC_GUARDED_BY(network_thread_); // }; // // class SequenceCheckerExample { // public: // int CalledFromPacer() RTC_RUN_ON(pacer_sequence_checker_) { // return var2_; // } // // void CallMeFromPacer() { // RTC_DCHECK_RUN_ON(&pacer_sequence_checker_) // << "Should be called from pacer"; // CalledFromPacer(); // } // // private: // int pacer_var_ RTC_GUARDED_BY(pacer_sequence_checker_); // SequenceChecker pacer_sequence_checker_; // }; // // class TaskQueueExample { // public: // class Encoder { // public: // rtc::TaskQueue* Queue() { return encoder_queue_; } // void Encode() { // RTC_DCHECK_RUN_ON(encoder_queue_); // DoSomething(var_); // } // // private: // rtc::TaskQueue* const encoder_queue_; // Frame var_ RTC_GUARDED_BY(encoder_queue_); // }; // // void Encode() { // // Will fail at runtime when DCHECK is enabled: // // encoder_->Encode(); // // Will work: // rtc::scoped_refptr encoder = encoder_; // encoder_->Queue()->PostTask([encoder] { encoder->Encode(); }); // } // // private: // rtc::scoped_refptr encoder_; // } // Document if a function expected to be called from same thread/task queue. #define RTC_RUN_ON(x) \ RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(x)) namespace webrtc { std::string ExpectationToString(const webrtc::SequenceChecker* checker); // Catch-all implementation for types other than explicitly supported above. template std::string ExpectationToString(const ThreadLikeObject*) { return std::string(); } } // namespace webrtc #define RTC_DCHECK_RUN_ON(x) \ webrtc::webrtc_seq_check_impl::SequenceCheckerScope seq_check_scope(x); \ RTC_DCHECK((x)->IsCurrent()) << webrtc::ExpectationToString(x) #endif // RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/synchronization/yield.cc0000664000175000017500000000172014475643423024614 0ustar00arunarun/* * Copyright 2020 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/synchronization/yield.h" #if defined(WEBRTC_WIN) #include #else #include #include #endif namespace webrtc { void YieldCurrentThread() { // TODO(bugs.webrtc.org/11634): use dedicated OS functionality instead of // sleep for yielding. #if defined(WEBRTC_WIN) ::Sleep(0); #elif defined(WEBRTC_MAC) && defined(RTC_USE_NATIVE_MUTEX_ON_MAC) && \ !RTC_USE_NATIVE_MUTEX_ON_MAC sched_yield(); #else static const struct timespec ts_null = {0}; nanosleep(&ts_null, nullptr); #endif } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/synchronization/yield.h0000664000175000017500000000120714475643423024456 0ustar00arunarun/* * Copyright 2020 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_SYNCHRONIZATION_YIELD_H_ #define RTC_BASE_SYNCHRONIZATION_YIELD_H_ namespace webrtc { // Request rescheduling of threads. void YieldCurrentThread(); } // namespace webrtc #endif // RTC_BASE_SYNCHRONIZATION_YIELD_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/synchronization/yield_policy.cc0000664000175000017500000000425214475643423026176 0ustar00arunarun/* * Copyright 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/synchronization/yield_policy.h" #include "absl/base/attributes.h" #include "absl/base/config.h" #include "rtc_base/checks.h" #if !defined(ABSL_HAVE_THREAD_LOCAL) && defined(WEBRTC_POSIX) #include #endif namespace rtc { namespace { #if defined(ABSL_HAVE_THREAD_LOCAL) ABSL_CONST_INIT thread_local YieldInterface* current_yield_policy = nullptr; YieldInterface* GetCurrentYieldPolicy() { return current_yield_policy; } void SetCurrentYieldPolicy(YieldInterface* ptr) { current_yield_policy = ptr; } #elif defined(WEBRTC_POSIX) // Emscripten does not support the C++11 thread_local keyword but does support // the pthread thread-local storage API. // https://github.com/emscripten-core/emscripten/issues/3502 ABSL_CONST_INIT pthread_key_t g_current_yield_policy_tls = 0; void InitializeTls() { RTC_CHECK_EQ(pthread_key_create(&g_current_yield_policy_tls, nullptr), 0); } pthread_key_t GetCurrentYieldPolicyTls() { static pthread_once_t init_once = PTHREAD_ONCE_INIT; RTC_CHECK_EQ(pthread_once(&init_once, &InitializeTls), 0); return g_current_yield_policy_tls; } YieldInterface* GetCurrentYieldPolicy() { return static_cast( pthread_getspecific(GetCurrentYieldPolicyTls())); } void SetCurrentYieldPolicy(YieldInterface* ptr) { pthread_setspecific(GetCurrentYieldPolicyTls(), ptr); } #else #error Unsupported platform #endif } // namespace ScopedYieldPolicy::ScopedYieldPolicy(YieldInterface* policy) : previous_(GetCurrentYieldPolicy()) { SetCurrentYieldPolicy(policy); } ScopedYieldPolicy::~ScopedYieldPolicy() { SetCurrentYieldPolicy(previous_); } void ScopedYieldPolicy::YieldExecution() { YieldInterface* current = GetCurrentYieldPolicy(); if (current) current->YieldExecution(); } } // namespace rtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/synchronization/yield_policy.h0000664000175000017500000000237614475643423026045 0ustar00arunarun/* * Copyright 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_SYNCHRONIZATION_YIELD_POLICY_H_ #define RTC_BASE_SYNCHRONIZATION_YIELD_POLICY_H_ namespace rtc { class YieldInterface { public: virtual ~YieldInterface() = default; virtual void YieldExecution() = 0; }; // Sets the current thread-local yield policy while it's in scope and reverts // to the previous policy when it leaves the scope. class ScopedYieldPolicy final { public: explicit ScopedYieldPolicy(YieldInterface* policy); ScopedYieldPolicy(const ScopedYieldPolicy&) = delete; ScopedYieldPolicy& operator=(const ScopedYieldPolicy&) = delete; ~ScopedYieldPolicy(); // Will yield as specified by the currently active thread-local yield policy // (which by default is a no-op). static void YieldExecution(); private: YieldInterface* const previous_; }; } // namespace rtc #endif // RTC_BASE_SYNCHRONIZATION_YIELD_POLICY_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/system/0000775000175000017500000000000014475643423021262 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/system/arch.h0000664000175000017500000000430014475643423022345 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // This file contains platform-specific typedefs and defines. // Much of it is derived from Chromium's build/build_config.h. #ifndef RTC_BASE_SYSTEM_ARCH_H_ #define RTC_BASE_SYSTEM_ARCH_H_ // Processor architecture detection. For more info on what's defined, see: // http://msdn.microsoft.com/en-us/library/b0084kay.aspx // http://www.agner.org/optimize/calling_conventions.pdf // or with gcc, run: "echo | gcc -E -dM -" #if defined(_M_X64) || defined(__x86_64__) #define WEBRTC_ARCH_X86_FAMILY #define WEBRTC_ARCH_X86_64 #define WEBRTC_ARCH_64_BITS #define WEBRTC_ARCH_LITTLE_ENDIAN #elif defined(_M_ARM64) || defined(__aarch64__) #define WEBRTC_ARCH_ARM_FAMILY #define WEBRTC_ARCH_64_BITS #define WEBRTC_ARCH_LITTLE_ENDIAN #elif defined(__riscv) || defined(__riscv__) #define WEBRTC_ARCH_LITTLE_ENDIAN #if __riscv_xlen == 64 #define WEBRTC_ARCH_64_BITS #else #define WEBRTC_ARCH_32_BITS #endif #elif defined(_M_IX86) || defined(__i386__) #define WEBRTC_ARCH_X86_FAMILY #define WEBRTC_ARCH_X86 #define WEBRTC_ARCH_32_BITS #define WEBRTC_ARCH_LITTLE_ENDIAN #elif defined(__ARMEL__) #define WEBRTC_ARCH_ARM_FAMILY #define WEBRTC_ARCH_32_BITS #define WEBRTC_ARCH_LITTLE_ENDIAN #elif defined(__MIPSEL__) #define WEBRTC_ARCH_MIPS_FAMILY #if defined(__LP64__) #define WEBRTC_ARCH_64_BITS #else #define WEBRTC_ARCH_32_BITS #endif #define WEBRTC_ARCH_LITTLE_ENDIAN #elif defined(__pnacl__) #define WEBRTC_ARCH_32_BITS #define WEBRTC_ARCH_LITTLE_ENDIAN #elif defined(__EMSCRIPTEN__) #define WEBRTC_ARCH_32_BITS #define WEBRTC_ARCH_LITTLE_ENDIAN #else #error Please add support for your architecture in rtc_base/system/arch.h #endif #if !(defined(WEBRTC_ARCH_LITTLE_ENDIAN) ^ defined(WEBRTC_ARCH_BIG_ENDIAN)) #error Define either WEBRTC_ARCH_LITTLE_ENDIAN or WEBRTC_ARCH_BIG_ENDIAN #endif #endif // RTC_BASE_SYSTEM_ARCH_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/system/asm_defines.h0000664000175000017500000000335114475643423023712 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_SYSTEM_ASM_DEFINES_H_ #define RTC_BASE_SYSTEM_ASM_DEFINES_H_ // clang-format off // clang formatting breaks everything here, e.g. concatenating directives, // due to absence of context via asm keyword. #if defined(__linux__) && defined(__ELF__) .section .note.GNU-stack,"",%progbits #endif // Define the macros used in ARM assembly code, so that for Mac or iOS builds // we add leading underscores for the function names. #ifdef __APPLE__ .macro GLOBAL_FUNCTION name .global _\name .private_extern _\name .endm .macro DEFINE_FUNCTION name _\name: .endm .macro CALL_FUNCTION name bl _\name .endm .macro GLOBAL_LABEL name .global _\name .private_extern _\name .endm #else .macro GLOBAL_FUNCTION name .global \name .hidden \name .endm .macro DEFINE_FUNCTION name #if defined(__linux__) && defined(__ELF__) .type \name,%function #endif \name: .endm .macro CALL_FUNCTION name bl \name .endm .macro GLOBAL_LABEL name .global \name .hidden \name .endm #endif // With Apple's clang compiler, for instructions ldrb, strh, etc., // the condition code is after the width specifier. Here we define // only the ones that are actually used in the assembly files. #if (defined __llvm__) && (defined __APPLE__) .macro streqh reg1, reg2, num strheq \reg1, \reg2, \num .endm #endif .text // clang-format on #endif // RTC_BASE_SYSTEM_ASM_DEFINES_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/system/file_wrapper.cc0000664000175000017500000000625214475643423024255 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/system/file_wrapper.h" #include "rtc_base/numerics/safe_conversions.h" #include #ifdef _WIN32 #include #else #include #endif #include namespace webrtc { namespace { FILE* FileOpen(const char* file_name_utf8, bool read_only, int* error) { #if defined(_WIN32) int len = MultiByteToWideChar(CP_UTF8, 0, file_name_utf8, -1, nullptr, 0); std::wstring wstr(len, 0); MultiByteToWideChar(CP_UTF8, 0, file_name_utf8, -1, &wstr[0], len); FILE* file = _wfopen(wstr.c_str(), read_only ? L"rb" : L"wb"); #else FILE* file = fopen(file_name_utf8, read_only ? "rb" : "wb"); #endif if (!file && error) { *error = errno; } return file; } const char* GetCstrCheckNoEmbeddedNul(const std::string& s) { const char* p = s.c_str(); RTC_CHECK_EQ(strlen(p), s.size()) << "Invalid filename, containing NUL character"; return p; } } // namespace // static FileWrapper FileWrapper::OpenReadOnly(const char* file_name_utf8) { return FileWrapper(FileOpen(file_name_utf8, true, nullptr)); } // static FileWrapper FileWrapper::OpenReadOnly(const std::string& file_name_utf8) { return OpenReadOnly(GetCstrCheckNoEmbeddedNul(file_name_utf8)); } // static FileWrapper FileWrapper::OpenWriteOnly(const char* file_name_utf8, int* error /*=nullptr*/) { return FileWrapper(FileOpen(file_name_utf8, false, error)); } // static FileWrapper FileWrapper::OpenWriteOnly(const std::string& file_name_utf8, int* error /*=nullptr*/) { return OpenWriteOnly(GetCstrCheckNoEmbeddedNul(file_name_utf8), error); } FileWrapper::FileWrapper(FileWrapper&& other) { operator=(std::move(other)); } FileWrapper& FileWrapper::operator=(FileWrapper&& other) { Close(); file_ = other.file_; other.file_ = nullptr; return *this; } bool FileWrapper::SeekRelative(int64_t offset) { RTC_DCHECK(file_); return fseek(file_, rtc::checked_cast(offset), SEEK_CUR) == 0; } bool FileWrapper::SeekTo(int64_t position) { RTC_DCHECK(file_); return fseek(file_, rtc::checked_cast(position), SEEK_SET) == 0; } bool FileWrapper::Flush() { RTC_DCHECK(file_); return fflush(file_) == 0; } size_t FileWrapper::Read(void* buf, size_t length) { RTC_DCHECK(file_); return fread(buf, 1, length, file_); } bool FileWrapper::ReadEof() const { RTC_DCHECK(file_); return feof(file_); } bool FileWrapper::Write(const void* buf, size_t length) { RTC_DCHECK(file_); return fwrite(buf, 1, length, file_) == length; } bool FileWrapper::Close() { if (file_ == nullptr) return true; bool success = fclose(file_) == 0; file_ = nullptr; return success; } FILE* FileWrapper::Release() { FILE* file = file_; file_ = nullptr; return file; } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/system/file_wrapper.h0000664000175000017500000001037014475643423024113 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_SYSTEM_FILE_WRAPPER_H_ #define RTC_BASE_SYSTEM_FILE_WRAPPER_H_ #include #include #include // Implementation that can read (exclusive) or write from/to a file. namespace webrtc { // This class is a thin wrapper around FILE*. It's main features are that it // owns the FILE*, calling fclose on destruction, and that on windows, file // names passed to the open methods are always treated as utf-8, regardless of // system code page. // Most of the methods return only a success/fail indication. When needed, an // optional argument |int* error| should be added to all methods, in the same // way as for the OpenWriteOnly methods. class FileWrapper final { public: // Opens a file, in read or write mode. Use the is_open() method on the // returned object to check if the open operation was successful. On failure, // and if |error| is non-null, the system errno value is stored at |*error|. // The file is closed by the destructor. static FileWrapper OpenReadOnly(const char* file_name_utf8); static FileWrapper OpenReadOnly(const std::string& file_name_utf8); static FileWrapper OpenWriteOnly(const char* file_name_utf8, int* error = nullptr); static FileWrapper OpenWriteOnly(const std::string& file_name_utf8, int* error = nullptr); FileWrapper() = default; // Takes over ownership of |file|, closing it on destruction. Calling with // null |file| is allowed, and results in a FileWrapper with is_open() false. explicit FileWrapper(FILE* file) : file_(file) {} ~FileWrapper() { Close(); } // Copying is not supported. FileWrapper(const FileWrapper&) = delete; FileWrapper& operator=(const FileWrapper&) = delete; // Support for move semantics. FileWrapper(FileWrapper&&); FileWrapper& operator=(FileWrapper&&); // Returns true if a file has been opened. If the file is not open, no methods // but is_open and Close may be called. bool is_open() const { return file_ != nullptr; } // Closes the file, and implies Flush. Returns true on success, false if // writing buffered data fails. On failure, the file is nevertheless closed. // Calling Close on an already closed file does nothing and returns success. bool Close(); // Releases and returns the wrapped file without closing it. This call passes // the ownership of the file to the caller, and the wrapper is no longer // responsible for closing it. Similarly the previously wrapped file is no // longer available for the wrapper to use in any aspect. FILE* Release(); // Write any buffered data to the underlying file. Returns true on success, // false on write error. Note: Flushing when closing, is not required. bool Flush(); // Seeks to the beginning of file. Returns true on success, false on failure, // e.g., if the underlying file isn't seekable. bool Rewind() { return SeekTo(0); } // TODO(nisse): The seek functions are used only by the WavReader. If that // code is demoted to test code, seek functions can be deleted from this // utility. // Seek relative to current file position. bool SeekRelative(int64_t offset); // Seek to given position. bool SeekTo(int64_t position); // Returns number of bytes read. Short count indicates EOF or error. size_t Read(void* buf, size_t length); // If the most recent Read() returned a short count, this methods returns true // if the short count was due to EOF, and false it it was due to some i/o // error. bool ReadEof() const; // Returns true if all data was successfully written (or buffered), or false // if there was an error. Writing buffered data can fail later, and is // reported with return value from Flush or Close. bool Write(const void* buf, size_t length); private: FILE* file_ = nullptr; }; } // namespace webrtc #endif // RTC_BASE_SYSTEM_FILE_WRAPPER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/system/ignore_warnings.h0000664000175000017500000000222014475643423024622 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_SYSTEM_IGNORE_WARNINGS_H_ #define RTC_BASE_SYSTEM_IGNORE_WARNINGS_H_ #ifdef __clang__ #define RTC_PUSH_IGNORING_WFRAME_LARGER_THAN() \ _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Wframe-larger-than=\"") #define RTC_POP_IGNORING_WFRAME_LARGER_THAN() _Pragma("clang diagnostic pop") #elif __GNUC__ #define RTC_PUSH_IGNORING_WFRAME_LARGER_THAN() \ _Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic ignored \"-Wframe-larger-than=\"") #define RTC_POP_IGNORING_WFRAME_LARGER_THAN() _Pragma("GCC diagnostic pop") #else #define RTC_PUSH_IGNORING_WFRAME_LARGER_THAN() #define RTC_POP_IGNORING_WFRAME_LARGER_THAN() #endif #endif // RTC_BASE_SYSTEM_IGNORE_WARNINGS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/system/inline.h0000664000175000017500000000147314475643423022716 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_SYSTEM_INLINE_H_ #define RTC_BASE_SYSTEM_INLINE_H_ #if defined(_MSC_VER) #define RTC_FORCE_INLINE __forceinline #define RTC_NO_INLINE __declspec(noinline) #elif defined(__GNUC__) #define RTC_FORCE_INLINE __attribute__((__always_inline__)) #define RTC_NO_INLINE __attribute__((__noinline__)) #else #define RTC_FORCE_INLINE #define RTC_NO_INLINE #endif #endif // RTC_BASE_SYSTEM_INLINE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/system/rtc_export.h0000664000175000017500000000222714475643423023627 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_SYSTEM_RTC_EXPORT_H_ #define RTC_BASE_SYSTEM_RTC_EXPORT_H_ // RTC_EXPORT is used to mark symbols as exported or imported when WebRTC is // built or used as a shared library. // When WebRTC is built as a static library the RTC_EXPORT macro expands to // nothing. #ifdef WEBRTC_ENABLE_SYMBOL_EXPORT #ifdef WEBRTC_WIN #ifdef WEBRTC_LIBRARY_IMPL #define RTC_EXPORT __declspec(dllexport) #else #define RTC_EXPORT __declspec(dllimport) #endif #else // WEBRTC_WIN #if __has_attribute(visibility) && defined(WEBRTC_LIBRARY_IMPL) #define RTC_EXPORT __attribute__((visibility("default"))) #endif #endif // WEBRTC_WIN #endif // WEBRTC_ENABLE_SYMBOL_EXPORT #ifndef RTC_EXPORT #define RTC_EXPORT #endif #endif // RTC_BASE_SYSTEM_RTC_EXPORT_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/system/unused.h0000664000175000017500000000262714475643423022745 0ustar00arunarun/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_SYSTEM_UNUSED_H_ #define RTC_BASE_SYSTEM_UNUSED_H_ // Annotate a function indicating the caller must examine the return value. // Use like: // int foo() RTC_WARN_UNUSED_RESULT; // To explicitly ignore a result, cast to void. // TODO(kwiberg): Remove when we can use [[nodiscard]] from C++17. #if defined(__clang__) #define RTC_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) #elif defined(__GNUC__) // gcc has a __warn_unused_result__ attribute, but you can't quiet it by // casting to void, so we don't use it. #define RTC_WARN_UNUSED_RESULT #else #define RTC_WARN_UNUSED_RESULT #endif // Prevent the compiler from warning about an unused variable. For example: // int result = DoSomething(); // assert(result == 17); // RTC_UNUSED(result); // Note: In most cases it is better to remove the unused variable rather than // suppressing the compiler warning. #ifndef RTC_UNUSED #define RTC_UNUSED(x) static_cast(x) #endif // RTC_UNUSED #endif // RTC_BASE_SYSTEM_UNUSED_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/system/warn_current_thread_is_deadlocked.h0000664000175000017500000000174514475643423030334 0ustar00arunarun/* * Copyright 2019 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_SYSTEM_WARN_CURRENT_THREAD_IS_DEADLOCKED_H_ #define RTC_BASE_SYSTEM_WARN_CURRENT_THREAD_IS_DEADLOCKED_H_ namespace webrtc { #if defined(WEBRTC_ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD) /* webrtc-audio-processing: * We don't support the Android SDK integration for this, so stub out void WarnThatTheCurrentThreadIsProbablyDeadlocked(); */ inline void WarnThatTheCurrentThreadIsProbablyDeadlocked() {} #else inline void WarnThatTheCurrentThreadIsProbablyDeadlocked() {} #endif } // namespace webrtc #endif // RTC_BASE_SYSTEM_WARN_CURRENT_THREAD_IS_DEADLOCKED_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/thread_annotations.h0000664000175000017500000001041614475643423023775 0ustar00arunarun// // Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. // // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file in the root of the source // tree. An additional intellectual property rights grant can be found // in the file PATENTS. All contributing project authors may // be found in the AUTHORS file in the root of the source tree. // // Borrowed from // https://code.google.com/p/gperftools/source/browse/src/base/thread_annotations.h // but adapted for clang attributes instead of the gcc. // // This header file contains the macro definitions for thread safety // annotations that allow the developers to document the locking policies // of their multi-threaded code. The annotations can also help program // analysis tools to identify potential thread safety issues. #ifndef RTC_BASE_THREAD_ANNOTATIONS_H_ #define RTC_BASE_THREAD_ANNOTATIONS_H_ #if defined(__clang__) && (!defined(SWIG)) #define RTC_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) #else #define RTC_THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op #endif // Document if a shared variable/field needs to be protected by a lock. // GUARDED_BY allows the user to specify a particular lock that should be // held when accessing the annotated variable. #define RTC_GUARDED_BY(x) RTC_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) // Document if the memory location pointed to by a pointer should be guarded // by a lock when dereferencing the pointer. Note that a pointer variable to a // shared memory location could itself be a shared variable. For example, if a // shared global pointer q, which is guarded by mu1, points to a shared memory // location that is guarded by mu2, q should be annotated as follows: // int *q GUARDED_BY(mu1) PT_GUARDED_BY(mu2); #define RTC_PT_GUARDED_BY(x) RTC_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) // Document the acquisition order between locks that can be held // simultaneously by a thread. For any two locks that need to be annotated // to establish an acquisition order, only one of them needs the annotation. // (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER // and ACQUIRED_BEFORE.) #define RTC_ACQUIRED_AFTER(x) \ RTC_THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(x)) #define RTC_ACQUIRED_BEFORE(x) \ RTC_THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(x)) // The following three annotations document the lock requirements for // functions/methods. // Document if a function expects certain locks to be held before it is called #define RTC_EXCLUSIVE_LOCKS_REQUIRED(...) \ RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__)) #define RTC_SHARED_LOCKS_REQUIRED(...) \ RTC_THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__)) // Document the locks acquired in the body of the function. These locks // cannot be held when calling this function (as google3's Mutex locks are // non-reentrant). #define RTC_LOCKS_EXCLUDED(...) \ RTC_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) // Document the lock the annotated function returns without acquiring it. #define RTC_LOCK_RETURNED(x) RTC_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) // Document if a class/type is a lockable type (such as the Mutex class). #define RTC_LOCKABLE RTC_THREAD_ANNOTATION_ATTRIBUTE__(lockable) // Document if a class is a scoped lockable type (such as the MutexLock class). #define RTC_SCOPED_LOCKABLE RTC_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) // The following annotations specify lock and unlock primitives. #define RTC_EXCLUSIVE_LOCK_FUNCTION(...) \ RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__)) #define RTC_SHARED_LOCK_FUNCTION(...) \ RTC_THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__)) #define RTC_EXCLUSIVE_TRYLOCK_FUNCTION(...) \ RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__)) #define RTC_SHARED_TRYLOCK_FUNCTION(...) \ RTC_THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__)) #define RTC_UNLOCK_FUNCTION(...) \ RTC_THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__)) // An escape hatch for thread safety analysis to ignore the annotated function. #define RTC_NO_THREAD_SAFETY_ANALYSIS \ RTC_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) #endif // RTC_BASE_THREAD_ANNOTATIONS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/thread_checker.h0000664000175000017500000000171314475643423023044 0ustar00arunarun/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Borrowed from Chromium's src/base/threading/thread_checker.h. #ifndef RTC_BASE_THREAD_CHECKER_H_ #define RTC_BASE_THREAD_CHECKER_H_ #include "rtc_base/deprecation.h" #include "rtc_base/synchronization/sequence_checker.h" namespace rtc { // TODO(srte): Replace usages of this with SequenceChecker. class ThreadChecker : public webrtc::SequenceChecker { public: RTC_DEPRECATED bool CalledOnValidThread() const { return IsCurrent(); } RTC_DEPRECATED void DetachFromThread() { Detach(); } }; } // namespace rtc #endif // RTC_BASE_THREAD_CHECKER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/time_utils.cc0000664000175000017500000002305614475643423022431 0ustar00arunarun/* * Copyright 2004 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include #if defined(WEBRTC_POSIX) #include #if defined(WEBRTC_MAC) #include #endif #endif #if defined(WEBRTC_WIN) // clang-format off // clang formatting would put last, // which leads to compilation failure. #include #include #include // clang-format on #endif #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/time_utils.h" namespace rtc { ClockInterface* g_clock = nullptr; ClockInterface* SetClockForTesting(ClockInterface* clock) { ClockInterface* prev = g_clock; g_clock = clock; return prev; } ClockInterface* GetClockForTesting() { return g_clock; } #if defined(WINUWP) namespace { class TimeHelper final { public: TimeHelper(const TimeHelper&) = delete; // Resets the clock based upon an NTP server. This routine must be called // prior to the main system start-up to ensure all clocks are based upon // an NTP server time if NTP synchronization is required. No critical // section is used thus this method must be called prior to any clock // routines being used. static void SyncWithNtp(int64_t ntp_server_time_ms) { auto& singleton = Singleton(); TIME_ZONE_INFORMATION time_zone; GetTimeZoneInformation(&time_zone); int64_t time_zone_bias_ns = rtc::dchecked_cast(time_zone.Bias) * 60 * 1000 * 1000 * 1000; singleton.app_start_time_ns_ = (ntp_server_time_ms - kNTPTimeToUnixTimeEpochOffset) * 1000000 - time_zone_bias_ns; singleton.UpdateReferenceTime(); } // Returns the number of nanoseconds that have passed since unix epoch. static int64_t TicksNs() { auto& singleton = Singleton(); int64_t result = 0; LARGE_INTEGER qpcnt; QueryPerformanceCounter(&qpcnt); result = rtc::dchecked_cast( (rtc::dchecked_cast(qpcnt.QuadPart) * 100000 / rtc::dchecked_cast(singleton.os_ticks_per_second_)) * 10000); result = singleton.app_start_time_ns_ + result - singleton.time_since_os_start_ns_; return result; } private: TimeHelper() { TIME_ZONE_INFORMATION time_zone; GetTimeZoneInformation(&time_zone); int64_t time_zone_bias_ns = rtc::dchecked_cast(time_zone.Bias) * 60 * 1000 * 1000 * 1000; FILETIME ft; // This will give us system file in UTC format. GetSystemTimeAsFileTime(&ft); LARGE_INTEGER li; li.HighPart = ft.dwHighDateTime; li.LowPart = ft.dwLowDateTime; app_start_time_ns_ = (li.QuadPart - kFileTimeToUnixTimeEpochOffset) * 100 - time_zone_bias_ns; UpdateReferenceTime(); } static TimeHelper& Singleton() { static TimeHelper singleton; return singleton; } void UpdateReferenceTime() { LARGE_INTEGER qpfreq; QueryPerformanceFrequency(&qpfreq); os_ticks_per_second_ = rtc::dchecked_cast(qpfreq.QuadPart); LARGE_INTEGER qpcnt; QueryPerformanceCounter(&qpcnt); time_since_os_start_ns_ = rtc::dchecked_cast( (rtc::dchecked_cast(qpcnt.QuadPart) * 100000 / rtc::dchecked_cast(os_ticks_per_second_)) * 10000); } private: static constexpr uint64_t kFileTimeToUnixTimeEpochOffset = 116444736000000000ULL; static constexpr uint64_t kNTPTimeToUnixTimeEpochOffset = 2208988800000L; // The number of nanoseconds since unix system epoch int64_t app_start_time_ns_; // The number of nanoseconds since the OS started int64_t time_since_os_start_ns_; // The OS calculated ticks per second int64_t os_ticks_per_second_; }; } // namespace void SyncWithNtp(int64_t time_from_ntp_server_ms) { TimeHelper::SyncWithNtp(time_from_ntp_server_ms); } #endif // defined(WINUWP) int64_t SystemTimeNanos() { int64_t ticks; #if defined(WEBRTC_MAC) static mach_timebase_info_data_t timebase; if (timebase.denom == 0) { // Get the timebase if this is the first time we run. // Recommended by Apple's QA1398. if (mach_timebase_info(&timebase) != KERN_SUCCESS) { RTC_NOTREACHED(); } } // Use timebase to convert absolute time tick units into nanoseconds. const auto mul = [](uint64_t a, uint32_t b) -> int64_t { RTC_DCHECK_NE(b, 0); RTC_DCHECK_LE(a, std::numeric_limits::max() / b) << "The multiplication " << a << " * " << b << " overflows"; return rtc::dchecked_cast(a * b); }; ticks = mul(mach_absolute_time(), timebase.numer) / timebase.denom; #elif defined(WEBRTC_POSIX) struct timespec ts; // TODO(deadbeef): Do we need to handle the case when CLOCK_MONOTONIC is not // supported? clock_gettime(CLOCK_MONOTONIC, &ts); ticks = kNumNanosecsPerSec * static_cast(ts.tv_sec) + static_cast(ts.tv_nsec); #elif defined(WINUWP) ticks = TimeHelper::TicksNs(); #elif defined(WEBRTC_WIN) static volatile LONG last_timegettime = 0; static volatile int64_t num_wrap_timegettime = 0; volatile LONG* last_timegettime_ptr = &last_timegettime; DWORD now = timeGetTime(); // Atomically update the last gotten time DWORD old = InterlockedExchange(last_timegettime_ptr, now); if (now < old) { // If now is earlier than old, there may have been a race between threads. // 0x0fffffff ~3.1 days, the code will not take that long to execute // so it must have been a wrap around. if (old > 0xf0000000 && now < 0x0fffffff) { num_wrap_timegettime++; } } ticks = now + (num_wrap_timegettime << 32); // TODO(deadbeef): Calculate with nanosecond precision. Otherwise, we're // just wasting a multiply and divide when doing Time() on Windows. ticks = ticks * kNumNanosecsPerMillisec; #else #error Unsupported platform. #endif return ticks; } int64_t SystemTimeMillis() { return static_cast(SystemTimeNanos() / kNumNanosecsPerMillisec); } int64_t TimeNanos() { if (g_clock) { return g_clock->TimeNanos(); } return SystemTimeNanos(); } uint32_t Time32() { return static_cast(TimeNanos() / kNumNanosecsPerMillisec); } int64_t TimeMillis() { return TimeNanos() / kNumNanosecsPerMillisec; } int64_t TimeMicros() { return TimeNanos() / kNumNanosecsPerMicrosec; } int64_t TimeAfter(int64_t elapsed) { RTC_DCHECK_GE(elapsed, 0); return TimeMillis() + elapsed; } int32_t TimeDiff32(uint32_t later, uint32_t earlier) { return later - earlier; } int64_t TimeDiff(int64_t later, int64_t earlier) { return later - earlier; } TimestampWrapAroundHandler::TimestampWrapAroundHandler() : last_ts_(0), num_wrap_(-1) {} int64_t TimestampWrapAroundHandler::Unwrap(uint32_t ts) { if (num_wrap_ == -1) { last_ts_ = ts; num_wrap_ = 0; return ts; } if (ts < last_ts_) { if (last_ts_ >= 0xf0000000 && ts < 0x0fffffff) ++num_wrap_; } else if ((ts - last_ts_) > 0xf0000000) { // Backwards wrap. Unwrap with last wrap count and don't update last_ts_. return ts + (num_wrap_ - 1) * (int64_t{1} << 32); } last_ts_ = ts; return ts + (num_wrap_ << 32); } int64_t TmToSeconds(const tm& tm) { static short int mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; static short int cumul_mdays[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; int year = tm.tm_year + 1900; int month = tm.tm_mon; int day = tm.tm_mday - 1; // Make 0-based like the rest. int hour = tm.tm_hour; int min = tm.tm_min; int sec = tm.tm_sec; bool expiry_in_leap_year = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); if (year < 1970) return -1; if (month < 0 || month > 11) return -1; if (day < 0 || day >= mdays[month] + (expiry_in_leap_year && month == 2 - 1)) return -1; if (hour < 0 || hour > 23) return -1; if (min < 0 || min > 59) return -1; if (sec < 0 || sec > 59) return -1; day += cumul_mdays[month]; // Add number of leap days between 1970 and the expiration year, inclusive. day += ((year / 4 - 1970 / 4) - (year / 100 - 1970 / 100) + (year / 400 - 1970 / 400)); // We will have added one day too much above if expiration is during a leap // year, and expiration is in January or February. if (expiry_in_leap_year && month <= 2 - 1) // |month| is zero based. day -= 1; // Combine all variables into seconds from 1970-01-01 00:00 (except |month| // which was accumulated into |day| above). return (((static_cast(year - 1970) * 365 + day) * 24 + hour) * 60 + min) * 60 + sec; } int64_t TimeUTCMicros() { if (g_clock) { return g_clock->TimeNanos() / kNumNanosecsPerMicrosec; } #if defined(WEBRTC_POSIX) struct timeval time; gettimeofday(&time, nullptr); // Convert from second (1.0) and microsecond (1e-6). return (static_cast(time.tv_sec) * rtc::kNumMicrosecsPerSec + time.tv_usec); #elif defined(WEBRTC_WIN) struct _timeb time; _ftime(&time); // Convert from second (1.0) and milliseconds (1e-3). return (static_cast(time.time) * rtc::kNumMicrosecsPerSec + static_cast(time.millitm) * rtc::kNumMicrosecsPerMillisec); #endif } int64_t TimeUTCMillis() { return TimeUTCMicros() / kNumMicrosecsPerMillisec; } } // namespace rtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/time_utils.h0000664000175000017500000001107514475643423022271 0ustar00arunarun/* * Copyright 2005 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_TIME_UTILS_H_ #define RTC_BASE_TIME_UTILS_H_ #include #include #include "rtc_base/checks.h" #include "rtc_base/system/rtc_export.h" namespace rtc { static const int64_t kNumMillisecsPerSec = INT64_C(1000); static const int64_t kNumMicrosecsPerSec = INT64_C(1000000); static const int64_t kNumNanosecsPerSec = INT64_C(1000000000); static const int64_t kNumMicrosecsPerMillisec = kNumMicrosecsPerSec / kNumMillisecsPerSec; static const int64_t kNumNanosecsPerMillisec = kNumNanosecsPerSec / kNumMillisecsPerSec; static const int64_t kNumNanosecsPerMicrosec = kNumNanosecsPerSec / kNumMicrosecsPerSec; // TODO(honghaiz): Define a type for the time value specifically. class ClockInterface { public: virtual ~ClockInterface() {} virtual int64_t TimeNanos() const = 0; }; // Sets the global source of time. This is useful mainly for unit tests. // // Returns the previously set ClockInterface, or nullptr if none is set. // // Does not transfer ownership of the clock. SetClockForTesting(nullptr) // should be called before the ClockInterface is deleted. // // This method is not thread-safe; it should only be used when no other thread // is running (for example, at the start/end of a unit test, or start/end of // main()). // // TODO(deadbeef): Instead of having functions that access this global // ClockInterface, we may want to pass the ClockInterface into everything // that uses it, eliminating the need for a global variable and this function. RTC_EXPORT ClockInterface* SetClockForTesting(ClockInterface* clock); // Returns previously set clock, or nullptr if no custom clock is being used. RTC_EXPORT ClockInterface* GetClockForTesting(); #if defined(WINUWP) // Synchronizes the current clock based upon an NTP server's epoch in // milliseconds. void SyncWithNtp(int64_t time_from_ntp_server_ms); #endif // defined(WINUWP) // Returns the actual system time, even if a clock is set for testing. // Useful for timeouts while using a test clock, or for logging. int64_t SystemTimeNanos(); int64_t SystemTimeMillis(); // Returns the current time in milliseconds in 32 bits. uint32_t Time32(); // Returns the current time in milliseconds in 64 bits. RTC_EXPORT int64_t TimeMillis(); // Deprecated. Do not use this in any new code. inline int64_t Time() { return TimeMillis(); } // Returns the current time in microseconds. RTC_EXPORT int64_t TimeMicros(); // Returns the current time in nanoseconds. RTC_EXPORT int64_t TimeNanos(); // Returns a future timestamp, 'elapsed' milliseconds from now. int64_t TimeAfter(int64_t elapsed); // Number of milliseconds that would elapse between 'earlier' and 'later' // timestamps. The value is negative if 'later' occurs before 'earlier'. int64_t TimeDiff(int64_t later, int64_t earlier); int32_t TimeDiff32(uint32_t later, uint32_t earlier); // The number of milliseconds that have elapsed since 'earlier'. inline int64_t TimeSince(int64_t earlier) { return TimeMillis() - earlier; } // The number of milliseconds that will elapse between now and 'later'. inline int64_t TimeUntil(int64_t later) { return later - TimeMillis(); } class TimestampWrapAroundHandler { public: TimestampWrapAroundHandler(); int64_t Unwrap(uint32_t ts); private: uint32_t last_ts_; int64_t num_wrap_; }; // Convert from tm, which is relative to 1900-01-01 00:00 to number of // seconds from 1970-01-01 00:00 ("epoch"). Don't return time_t since that // is still 32 bits on many systems. int64_t TmToSeconds(const tm& tm); // Return the number of microseconds since January 1, 1970, UTC. // Useful mainly when producing logs to be correlated with other // devices, and when the devices in question all have properly // synchronized clocks. // // Note that this function obeys the system's idea about what the time // is. It is not guaranteed to be monotonic; it will jump in case the // system time is changed, e.g., by some other process calling // settimeofday. Always use rtc::TimeMicros(), not this function, for // measuring time intervals and timeouts. int64_t TimeUTCMicros(); // Return the number of milliseconds since January 1, 1970, UTC. // See above. int64_t TimeUTCMillis(); } // namespace rtc #endif // RTC_BASE_TIME_UTILS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/trace_event.h0000664000175000017500000013714714475643423022423 0ustar00arunarun// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file under third_party_mods/chromium or at: // http://src.chromium.org/svn/trunk/src/LICENSE #ifndef RTC_BASE_TRACE_EVENT_H_ #define RTC_BASE_TRACE_EVENT_H_ #include #include "rtc_base/event_tracer.h" #if defined(TRACE_EVENT0) #error "Another copy of trace_event.h has already been included." #endif #if defined(RTC_DISABLE_TRACE_EVENTS) #define RTC_TRACE_EVENTS_ENABLED 0 #else #define RTC_TRACE_EVENTS_ENABLED 1 #endif // Type values for identifying types in the TraceValue union. #define TRACE_VALUE_TYPE_BOOL (static_cast(1)) #define TRACE_VALUE_TYPE_UINT (static_cast(2)) #define TRACE_VALUE_TYPE_INT (static_cast(3)) #define TRACE_VALUE_TYPE_DOUBLE (static_cast(4)) #define TRACE_VALUE_TYPE_POINTER (static_cast(5)) #define TRACE_VALUE_TYPE_STRING (static_cast(6)) #define TRACE_VALUE_TYPE_COPY_STRING (static_cast(7)) #if RTC_TRACE_EVENTS_ENABLED // Extracted from Chromium's src/base/debug/trace_event.h. // This header is designed to give you trace_event macros without specifying // how the events actually get collected and stored. If you need to expose trace // event to some other universe, you can copy-and-paste this file, // implement the TRACE_EVENT_API macros, and do any other necessary fixup for // the target platform. The end result is that multiple libraries can funnel // events through to a shared trace event collector. // Trace events are for tracking application performance and resource usage. // Macros are provided to track: // Begin and end of function calls // Counters // // Events are issued against categories. Whereas RTC_LOG's // categories are statically defined, TRACE categories are created // implicitly with a string. For example: // TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent") // // Events can be INSTANT, or can be pairs of BEGIN and END in the same scope: // TRACE_EVENT_BEGIN0("MY_SUBSYSTEM", "SomethingCostly") // doSomethingCostly() // TRACE_EVENT_END0("MY_SUBSYSTEM", "SomethingCostly") // Note: our tools can't always determine the correct BEGIN/END pairs unless // these are used in the same scope. Use ASYNC_BEGIN/ASYNC_END macros if you // need them to be in separate scopes. // // A common use case is to trace entire function scopes. This // issues a trace BEGIN and END automatically: // void doSomethingCostly() { // TRACE_EVENT0("MY_SUBSYSTEM", "doSomethingCostly"); // ... // } // // Additional parameters can be associated with an event: // void doSomethingCostly2(int howMuch) { // TRACE_EVENT1("MY_SUBSYSTEM", "doSomethingCostly", // "howMuch", howMuch); // ... // } // // The trace system will automatically add to this information the // current process id, thread id, and a timestamp in microseconds. // // To trace an asynchronous procedure such as an IPC send/receive, use // ASYNC_BEGIN and ASYNC_END: // [single threaded sender code] // static int send_count = 0; // ++send_count; // TRACE_EVENT_ASYNC_BEGIN0("ipc", "message", send_count); // Send(new MyMessage(send_count)); // [receive code] // void OnMyMessage(send_count) { // TRACE_EVENT_ASYNC_END0("ipc", "message", send_count); // } // The third parameter is a unique ID to match ASYNC_BEGIN/ASYNC_END pairs. // ASYNC_BEGIN and ASYNC_END can occur on any thread of any traced process. // Pointers can be used for the ID parameter, and they will be mangled // internally so that the same pointer on two different processes will not // match. For example: // class MyTracedClass { // public: // MyTracedClass() { // TRACE_EVENT_ASYNC_BEGIN0("category", "MyTracedClass", this); // } // ~MyTracedClass() { // TRACE_EVENT_ASYNC_END0("category", "MyTracedClass", this); // } // } // // Trace event also supports counters, which is a way to track a quantity // as it varies over time. Counters are created with the following macro: // TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter", g_myCounterValue); // // Counters are process-specific. The macro itself can be issued from any // thread, however. // // Sometimes, you want to track two counters at once. You can do this with two // counter macros: // TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter0", g_myCounterValue[0]); // TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter1", g_myCounterValue[1]); // Or you can do it with a combined macro: // TRACE_COUNTER2("MY_SUBSYSTEM", "myCounter", // "bytesPinned", g_myCounterValue[0], // "bytesAllocated", g_myCounterValue[1]); // This indicates to the tracing UI that these counters should be displayed // in a single graph, as a summed area chart. // // Since counters are in a global namespace, you may want to disembiguate with a // unique ID, by using the TRACE_COUNTER_ID* variations. // // By default, trace collection is compiled in, but turned off at runtime. // Collecting trace data is the responsibility of the embedding // application. In Chrome's case, navigating to about:tracing will turn on // tracing and display data collected across all active processes. // // // Memory scoping note: // Tracing copies the pointers, not the string content, of the strings passed // in for category, name, and arg_names. Thus, the following code will // cause problems: // char* str = strdup("impprtantName"); // TRACE_EVENT_INSTANT0("SUBSYSTEM", str); // BAD! // free(str); // Trace system now has dangling pointer // // To avoid this issue with the |name| and |arg_name| parameters, use the // TRACE_EVENT_COPY_XXX overloads of the macros at additional runtime overhead. // Notes: The category must always be in a long-lived char* (i.e. static const). // The |arg_values|, when used, are always deep copied with the _COPY // macros. // // When are string argument values copied: // const char* arg_values are only referenced by default: // TRACE_EVENT1("category", "name", // "arg1", "literal string is only referenced"); // Use TRACE_STR_COPY to force copying of a const char*: // TRACE_EVENT1("category", "name", // "arg1", TRACE_STR_COPY("string will be copied")); // std::string arg_values are always copied: // TRACE_EVENT1("category", "name", // "arg1", std::string("string will be copied")); // // // Thread Safety: // Thread safety is provided by methods defined in event_tracer.h. See the file // for details. // By default, const char* argument values are assumed to have long-lived scope // and will not be copied. Use this macro to force a const char* to be copied. #define TRACE_STR_COPY(str) \ webrtc::trace_event_internal::TraceStringWithCopy(str) // This will mark the trace event as disabled by default. The user will need // to explicitly enable the event. #define TRACE_DISABLED_BY_DEFAULT(name) "disabled-by-default-" name // By default, uint64 ID argument values are not mangled with the Process ID in // TRACE_EVENT_ASYNC macros. Use this macro to force Process ID mangling. #define TRACE_ID_MANGLE(id) \ webrtc::trace_event_internal::TraceID::ForceMangle(id) // Records a pair of begin and end events called "name" for the current // scope, with 0, 1 or 2 associated arguments. If the category is not // enabled, then this does nothing. // - category and name strings must have application lifetime (statics or // literals). They may not include " chars. #define TRACE_EVENT0(category, name) \ INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name) #define TRACE_EVENT1(category, name, arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val) #define TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \ INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val, \ arg2_name, arg2_val) // Records a single event called "name" immediately, with 0, 1 or 2 // associated arguments. If the category is not enabled, then this // does nothing. // - category and name strings must have application lifetime (statics or // literals). They may not include " chars. #define TRACE_EVENT_INSTANT0(category, name) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ category, name, TRACE_EVENT_FLAG_NONE) #define TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) #define TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \ arg2_name, arg2_val) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ arg2_name, arg2_val) #define TRACE_EVENT_COPY_INSTANT0(category, name) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ category, name, TRACE_EVENT_FLAG_COPY) #define TRACE_EVENT_COPY_INSTANT1(category, name, arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) #define TRACE_EVENT_COPY_INSTANT2(category, name, arg1_name, arg1_val, \ arg2_name, arg2_val) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ arg2_name, arg2_val) // Records a single BEGIN event called "name" immediately, with 0, 1 or 2 // associated arguments. If the category is not enabled, then this // does nothing. // - category and name strings must have application lifetime (statics or // literals). They may not include " chars. #define TRACE_EVENT_BEGIN0(category, name) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ category, name, TRACE_EVENT_FLAG_NONE) #define TRACE_EVENT_BEGIN1(category, name, arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) #define TRACE_EVENT_BEGIN2(category, name, arg1_name, arg1_val, \ arg2_name, arg2_val) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ arg2_name, arg2_val) #define TRACE_EVENT_COPY_BEGIN0(category, name) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ category, name, TRACE_EVENT_FLAG_COPY) #define TRACE_EVENT_COPY_BEGIN1(category, name, arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) #define TRACE_EVENT_COPY_BEGIN2(category, name, arg1_name, arg1_val, \ arg2_name, arg2_val) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ arg2_name, arg2_val) // Records a single END event for "name" immediately. If the category // is not enabled, then this does nothing. // - category and name strings must have application lifetime (statics or // literals). They may not include " chars. #define TRACE_EVENT_END0(category, name) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ category, name, TRACE_EVENT_FLAG_NONE) #define TRACE_EVENT_END1(category, name, arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) #define TRACE_EVENT_END2(category, name, arg1_name, arg1_val, \ arg2_name, arg2_val) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ arg2_name, arg2_val) #define TRACE_EVENT_COPY_END0(category, name) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ category, name, TRACE_EVENT_FLAG_COPY) #define TRACE_EVENT_COPY_END1(category, name, arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) #define TRACE_EVENT_COPY_END2(category, name, arg1_name, arg1_val, \ arg2_name, arg2_val) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ arg2_name, arg2_val) // Records the value of a counter called "name" immediately. Value // must be representable as a 32 bit integer. // - category and name strings must have application lifetime (statics or // literals). They may not include " chars. #define TRACE_COUNTER1(category, name, value) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ category, name, TRACE_EVENT_FLAG_NONE, \ "value", static_cast(value)) #define TRACE_COPY_COUNTER1(category, name, value) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ category, name, TRACE_EVENT_FLAG_COPY, \ "value", static_cast(value)) // Records the values of a multi-parted counter called "name" immediately. // The UI will treat value1 and value2 as parts of a whole, displaying their // values as a stacked-bar chart. // - category and name strings must have application lifetime (statics or // literals). They may not include " chars. #define TRACE_COUNTER2(category, name, value1_name, value1_val, \ value2_name, value2_val) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ category, name, TRACE_EVENT_FLAG_NONE, \ value1_name, static_cast(value1_val), \ value2_name, static_cast(value2_val)) #define TRACE_COPY_COUNTER2(category, name, value1_name, value1_val, \ value2_name, value2_val) \ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ category, name, TRACE_EVENT_FLAG_COPY, \ value1_name, static_cast(value1_val), \ value2_name, static_cast(value2_val)) // Records the value of a counter called "name" immediately. Value // must be representable as a 32 bit integer. // - category and name strings must have application lifetime (statics or // literals). They may not include " chars. // - |id| is used to disambiguate counters with the same name. It must either // be a pointer or an integer value up to 64 bits. If it's a pointer, the bits // will be xored with a hash of the process ID so that the same pointer on // two different processes will not collide. #define TRACE_COUNTER_ID1(category, name, id, value) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ category, name, id, TRACE_EVENT_FLAG_NONE, \ "value", static_cast(value)) #define TRACE_COPY_COUNTER_ID1(category, name, id, value) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ category, name, id, TRACE_EVENT_FLAG_COPY, \ "value", static_cast(value)) // Records the values of a multi-parted counter called "name" immediately. // The UI will treat value1 and value2 as parts of a whole, displaying their // values as a stacked-bar chart. // - category and name strings must have application lifetime (statics or // literals). They may not include " chars. // - |id| is used to disambiguate counters with the same name. It must either // be a pointer or an integer value up to 64 bits. If it's a pointer, the bits // will be xored with a hash of the process ID so that the same pointer on // two different processes will not collide. #define TRACE_COUNTER_ID2(category, name, id, value1_name, value1_val, \ value2_name, value2_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ category, name, id, TRACE_EVENT_FLAG_NONE, \ value1_name, static_cast(value1_val), \ value2_name, static_cast(value2_val)) #define TRACE_COPY_COUNTER_ID2(category, name, id, value1_name, value1_val, \ value2_name, value2_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ category, name, id, TRACE_EVENT_FLAG_COPY, \ value1_name, static_cast(value1_val), \ value2_name, static_cast(value2_val)) // Records a single ASYNC_BEGIN event called "name" immediately, with 0, 1 or 2 // associated arguments. If the category is not enabled, then this // does nothing. // - category and name strings must have application lifetime (statics or // literals). They may not include " chars. // - |id| is used to match the ASYNC_BEGIN event with the ASYNC_END event. ASYNC // events are considered to match if their category, name and id values all // match. |id| must either be a pointer or an integer value up to 64 bits. If // it's a pointer, the bits will be xored with a hash of the process ID so // that the same pointer on two different processes will not collide. // An asynchronous operation can consist of multiple phases. The first phase is // defined by the ASYNC_BEGIN calls. Additional phases can be defined using the // ASYNC_STEP macros. When the operation completes, call ASYNC_END. // An ASYNC trace typically occur on a single thread (if not, they will only be // drawn on the thread defined in the ASYNC_BEGIN event), but all events in that // operation must use the same |name| and |id|. Each event can have its own // args. #define TRACE_EVENT_ASYNC_BEGIN0(category, name, id) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ category, name, id, TRACE_EVENT_FLAG_NONE) #define TRACE_EVENT_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) #define TRACE_EVENT_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \ arg2_name, arg2_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ category, name, id, TRACE_EVENT_FLAG_NONE, \ arg1_name, arg1_val, arg2_name, arg2_val) #define TRACE_EVENT_COPY_ASYNC_BEGIN0(category, name, id) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ category, name, id, TRACE_EVENT_FLAG_COPY) #define TRACE_EVENT_COPY_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ category, name, id, TRACE_EVENT_FLAG_COPY, \ arg1_name, arg1_val) #define TRACE_EVENT_COPY_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \ arg2_name, arg2_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ category, name, id, TRACE_EVENT_FLAG_COPY, \ arg1_name, arg1_val, arg2_name, arg2_val) // Records a single ASYNC_STEP event for |step| immediately. If the category // is not enabled, then this does nothing. The |name| and |id| must match the // ASYNC_BEGIN event above. The |step| param identifies this step within the // async event. This should be called at the beginning of the next phase of an // asynchronous operation. #define TRACE_EVENT_ASYNC_STEP0(category, name, id, step) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ category, name, id, TRACE_EVENT_FLAG_NONE, "step", step) #define TRACE_EVENT_ASYNC_STEP1(category, name, id, step, \ arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ category, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \ arg1_name, arg1_val) #define TRACE_EVENT_COPY_ASYNC_STEP0(category, name, id, step) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ category, name, id, TRACE_EVENT_FLAG_COPY, "step", step) #define TRACE_EVENT_COPY_ASYNC_STEP1(category, name, id, step, \ arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ category, name, id, TRACE_EVENT_FLAG_COPY, "step", step, \ arg1_name, arg1_val) // Records a single ASYNC_END event for "name" immediately. If the category // is not enabled, then this does nothing. #define TRACE_EVENT_ASYNC_END0(category, name, id) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ category, name, id, TRACE_EVENT_FLAG_NONE) #define TRACE_EVENT_ASYNC_END1(category, name, id, arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) #define TRACE_EVENT_ASYNC_END2(category, name, id, arg1_name, arg1_val, \ arg2_name, arg2_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ category, name, id, TRACE_EVENT_FLAG_NONE, \ arg1_name, arg1_val, arg2_name, arg2_val) #define TRACE_EVENT_COPY_ASYNC_END0(category, name, id) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ category, name, id, TRACE_EVENT_FLAG_COPY) #define TRACE_EVENT_COPY_ASYNC_END1(category, name, id, arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ category, name, id, TRACE_EVENT_FLAG_COPY, \ arg1_name, arg1_val) #define TRACE_EVENT_COPY_ASYNC_END2(category, name, id, arg1_name, arg1_val, \ arg2_name, arg2_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ category, name, id, TRACE_EVENT_FLAG_COPY, \ arg1_name, arg1_val, arg2_name, arg2_val) // Records a single FLOW_BEGIN event called "name" immediately, with 0, 1 or 2 // associated arguments. If the category is not enabled, then this // does nothing. // - category and name strings must have application lifetime (statics or // literals). They may not include " chars. // - |id| is used to match the FLOW_BEGIN event with the FLOW_END event. FLOW // events are considered to match if their category, name and id values all // match. |id| must either be a pointer or an integer value up to 64 bits. If // it's a pointer, the bits will be xored with a hash of the process ID so // that the same pointer on two different processes will not collide. // FLOW events are different from ASYNC events in how they are drawn by the // tracing UI. A FLOW defines asynchronous data flow, such as posting a task // (FLOW_BEGIN) and later executing that task (FLOW_END). Expect FLOWs to be // drawn as lines or arrows from FLOW_BEGIN scopes to FLOW_END scopes. Similar // to ASYNC, a FLOW can consist of multiple phases. The first phase is defined // by the FLOW_BEGIN calls. Additional phases can be defined using the FLOW_STEP // macros. When the operation completes, call FLOW_END. An async operation can // span threads and processes, but all events in that operation must use the // same |name| and |id|. Each event can have its own args. #define TRACE_EVENT_FLOW_BEGIN0(category, name, id) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ category, name, id, TRACE_EVENT_FLAG_NONE) #define TRACE_EVENT_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) #define TRACE_EVENT_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \ arg2_name, arg2_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ category, name, id, TRACE_EVENT_FLAG_NONE, \ arg1_name, arg1_val, arg2_name, arg2_val) #define TRACE_EVENT_COPY_FLOW_BEGIN0(category, name, id) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ category, name, id, TRACE_EVENT_FLAG_COPY) #define TRACE_EVENT_COPY_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ category, name, id, TRACE_EVENT_FLAG_COPY, \ arg1_name, arg1_val) #define TRACE_EVENT_COPY_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \ arg2_name, arg2_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ category, name, id, TRACE_EVENT_FLAG_COPY, \ arg1_name, arg1_val, arg2_name, arg2_val) // Records a single FLOW_STEP event for |step| immediately. If the category // is not enabled, then this does nothing. The |name| and |id| must match the // FLOW_BEGIN event above. The |step| param identifies this step within the // async event. This should be called at the beginning of the next phase of an // asynchronous operation. #define TRACE_EVENT_FLOW_STEP0(category, name, id, step) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \ category, name, id, TRACE_EVENT_FLAG_NONE, "step", step) #define TRACE_EVENT_FLOW_STEP1(category, name, id, step, \ arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \ category, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \ arg1_name, arg1_val) #define TRACE_EVENT_COPY_FLOW_STEP0(category, name, id, step) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \ category, name, id, TRACE_EVENT_FLAG_COPY, "step", step) #define TRACE_EVENT_COPY_FLOW_STEP1(category, name, id, step, \ arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \ category, name, id, TRACE_EVENT_FLAG_COPY, "step", step, \ arg1_name, arg1_val) // Records a single FLOW_END event for "name" immediately. If the category // is not enabled, then this does nothing. #define TRACE_EVENT_FLOW_END0(category, name, id) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \ category, name, id, TRACE_EVENT_FLAG_NONE) #define TRACE_EVENT_FLOW_END1(category, name, id, arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \ category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) #define TRACE_EVENT_FLOW_END2(category, name, id, arg1_name, arg1_val, \ arg2_name, arg2_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \ category, name, id, TRACE_EVENT_FLAG_NONE, \ arg1_name, arg1_val, arg2_name, arg2_val) #define TRACE_EVENT_COPY_FLOW_END0(category, name, id) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \ category, name, id, TRACE_EVENT_FLAG_COPY) #define TRACE_EVENT_COPY_FLOW_END1(category, name, id, arg1_name, arg1_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \ category, name, id, TRACE_EVENT_FLAG_COPY, \ arg1_name, arg1_val) #define TRACE_EVENT_COPY_FLOW_END2(category, name, id, arg1_name, arg1_val, \ arg2_name, arg2_val) \ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \ category, name, id, TRACE_EVENT_FLAG_COPY, \ arg1_name, arg1_val, arg2_name, arg2_val) //////////////////////////////////////////////////////////////////////////////// // Implementation specific tracing API definitions. // Get a pointer to the enabled state of the given trace category. Only // long-lived literal strings should be given as the category name. The returned // pointer can be held permanently in a local static for example. If the // unsigned char is non-zero, tracing is enabled. If tracing is enabled, // TRACE_EVENT_API_ADD_TRACE_EVENT can be called. It's OK if tracing is disabled // between the load of the tracing state and the call to // TRACE_EVENT_API_ADD_TRACE_EVENT, because this flag only provides an early out // for best performance when tracing is disabled. // const unsigned char* // TRACE_EVENT_API_GET_CATEGORY_ENABLED(const char* category_name) #define TRACE_EVENT_API_GET_CATEGORY_ENABLED \ webrtc::EventTracer::GetCategoryEnabled // Add a trace event to the platform tracing system. // void TRACE_EVENT_API_ADD_TRACE_EVENT( // char phase, // const unsigned char* category_enabled, // const char* name, // unsigned long long id, // int num_args, // const char** arg_names, // const unsigned char* arg_types, // const unsigned long long* arg_values, // unsigned char flags) #define TRACE_EVENT_API_ADD_TRACE_EVENT webrtc::EventTracer::AddTraceEvent //////////////////////////////////////////////////////////////////////////////// // Implementation detail: trace event macros create temporary variables // to keep instrumentation overhead low. These macros give each temporary // variable a unique name based on the line number to prevent name collissions. #define INTERNAL_TRACE_EVENT_UID3(a,b) \ trace_event_unique_##a##b #define INTERNAL_TRACE_EVENT_UID2(a,b) \ INTERNAL_TRACE_EVENT_UID3(a,b) #define INTERNAL_TRACE_EVENT_UID(name_prefix) \ INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__) #if WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS #define INTERNAL_TRACE_EVENT_INFO_TYPE const unsigned char* #else #define INTERNAL_TRACE_EVENT_INFO_TYPE static const unsigned char* #endif // WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS // Implementation detail: internal macro to create static category. #define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category) \ INTERNAL_TRACE_EVENT_INFO_TYPE INTERNAL_TRACE_EVENT_UID(catstatic) = \ TRACE_EVENT_API_GET_CATEGORY_ENABLED(category); // Implementation detail: internal macro to create static category and add // event if the category is enabled. #define INTERNAL_TRACE_EVENT_ADD(phase, category, name, flags, ...) \ do { \ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \ if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \ webrtc::trace_event_internal::AddTraceEvent( \ phase, INTERNAL_TRACE_EVENT_UID(catstatic), name, \ webrtc::trace_event_internal::kNoEventId, flags, ##__VA_ARGS__); \ } \ } while (0) // Implementation detail: internal macro to create static category and add begin // event if the category is enabled. Also adds the end event when the scope // ends. #define INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, ...) \ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \ webrtc::trace_event_internal::TraceEndOnScopeClose \ INTERNAL_TRACE_EVENT_UID(profileScope); \ if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \ webrtc::trace_event_internal::AddTraceEvent( \ TRACE_EVENT_PHASE_BEGIN, \ INTERNAL_TRACE_EVENT_UID(catstatic), \ name, webrtc::trace_event_internal::kNoEventId, \ TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__); \ INTERNAL_TRACE_EVENT_UID(profileScope).Initialize( \ INTERNAL_TRACE_EVENT_UID(catstatic), name); \ } // Implementation detail: internal macro to create static category and add // event if the category is enabled. #define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category, name, id, flags, \ ...) \ do { \ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \ if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \ unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \ webrtc::trace_event_internal::TraceID trace_event_trace_id( \ id, &trace_event_flags); \ webrtc::trace_event_internal::AddTraceEvent( \ phase, INTERNAL_TRACE_EVENT_UID(catstatic), \ name, trace_event_trace_id.data(), trace_event_flags, \ ##__VA_ARGS__); \ } \ } while (0) // Notes regarding the following definitions: // New values can be added and propagated to third party libraries, but existing // definitions must never be changed, because third party libraries may use old // definitions. // Phase indicates the nature of an event entry. E.g. part of a begin/end pair. #define TRACE_EVENT_PHASE_BEGIN ('B') #define TRACE_EVENT_PHASE_END ('E') #define TRACE_EVENT_PHASE_INSTANT ('I') #define TRACE_EVENT_PHASE_ASYNC_BEGIN ('S') #define TRACE_EVENT_PHASE_ASYNC_STEP ('T') #define TRACE_EVENT_PHASE_ASYNC_END ('F') #define TRACE_EVENT_PHASE_FLOW_BEGIN ('s') #define TRACE_EVENT_PHASE_FLOW_STEP ('t') #define TRACE_EVENT_PHASE_FLOW_END ('f') #define TRACE_EVENT_PHASE_METADATA ('M') #define TRACE_EVENT_PHASE_COUNTER ('C') // Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT. #define TRACE_EVENT_FLAG_NONE (static_cast(0)) #define TRACE_EVENT_FLAG_COPY (static_cast(1 << 0)) #define TRACE_EVENT_FLAG_HAS_ID (static_cast(1 << 1)) #define TRACE_EVENT_FLAG_MANGLE_ID (static_cast(1 << 2)) namespace webrtc { namespace trace_event_internal { // Specify these values when the corresponding argument of AddTraceEvent is not // used. const int kZeroNumArgs = 0; const unsigned long long kNoEventId = 0; // TraceID encapsulates an ID that can either be an integer or pointer. Pointers // are mangled with the Process ID so that they are unlikely to collide when the // same pointer is used on different processes. class TraceID { public: class ForceMangle { public: explicit ForceMangle(unsigned long long id) : data_(id) {} explicit ForceMangle(unsigned long id) : data_(id) {} explicit ForceMangle(unsigned int id) : data_(id) {} explicit ForceMangle(unsigned short id) : data_(id) {} explicit ForceMangle(unsigned char id) : data_(id) {} explicit ForceMangle(long long id) : data_(static_cast(id)) {} explicit ForceMangle(long id) : data_(static_cast(id)) {} explicit ForceMangle(int id) : data_(static_cast(id)) {} explicit ForceMangle(short id) : data_(static_cast(id)) {} explicit ForceMangle(signed char id) : data_(static_cast(id)) {} unsigned long long data() const { return data_; } private: unsigned long long data_; }; explicit TraceID(const void* id, unsigned char* flags) : data_(static_cast( reinterpret_cast(id))) { *flags |= TRACE_EVENT_FLAG_MANGLE_ID; } explicit TraceID(ForceMangle id, unsigned char* flags) : data_(id.data()) { *flags |= TRACE_EVENT_FLAG_MANGLE_ID; } explicit TraceID(unsigned long long id, unsigned char* flags) : data_(id) { (void)flags; } explicit TraceID(unsigned long id, unsigned char* flags) : data_(id) { (void)flags; } explicit TraceID(unsigned int id, unsigned char* flags) : data_(id) { (void)flags; } explicit TraceID(unsigned short id, unsigned char* flags) : data_(id) { (void)flags; } explicit TraceID(unsigned char id, unsigned char* flags) : data_(id) { (void)flags; } explicit TraceID(long long id, unsigned char* flags) : data_(static_cast(id)) { (void)flags; } explicit TraceID(long id, unsigned char* flags) : data_(static_cast(id)) { (void)flags; } explicit TraceID(int id, unsigned char* flags) : data_(static_cast(id)) { (void)flags; } explicit TraceID(short id, unsigned char* flags) : data_(static_cast(id)) { (void)flags; } explicit TraceID(signed char id, unsigned char* flags) : data_(static_cast(id)) { (void)flags; } unsigned long long data() const { return data_; } private: unsigned long long data_; }; // Simple union to store various types as unsigned long long. union TraceValueUnion { bool as_bool; unsigned long long as_uint; long long as_int; double as_double; const void* as_pointer; const char* as_string; }; // Simple container for const char* that should be copied instead of retained. class TraceStringWithCopy { public: explicit TraceStringWithCopy(const char* str) : str_(str) {} operator const char* () const { return str_; } private: const char* str_; }; // Define SetTraceValue for each allowed type. It stores the type and // value in the return arguments. This allows this API to avoid declaring any // structures so that it is portable to third_party libraries. #define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, \ union_member, \ value_type_id) \ static inline void SetTraceValue(actual_type arg, \ unsigned char* type, \ unsigned long long* value) { \ TraceValueUnion type_value; \ type_value.union_member = arg; \ *type = value_type_id; \ *value = type_value.as_uint; \ } // Simpler form for int types that can be safely casted. #define INTERNAL_DECLARE_SET_TRACE_VALUE_INT(actual_type, \ value_type_id) \ static inline void SetTraceValue(actual_type arg, \ unsigned char* type, \ unsigned long long* value) { \ *type = value_type_id; \ *value = static_cast(arg); \ } INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long long, TRACE_VALUE_TYPE_UINT) INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long, TRACE_VALUE_TYPE_UINT) INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned int, TRACE_VALUE_TYPE_UINT) INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned short, TRACE_VALUE_TYPE_UINT) INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned char, TRACE_VALUE_TYPE_UINT) INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long long, TRACE_VALUE_TYPE_INT) INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long, TRACE_VALUE_TYPE_INT) INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int, TRACE_VALUE_TYPE_INT) INTERNAL_DECLARE_SET_TRACE_VALUE_INT(short, TRACE_VALUE_TYPE_INT) INTERNAL_DECLARE_SET_TRACE_VALUE_INT(signed char, TRACE_VALUE_TYPE_INT) INTERNAL_DECLARE_SET_TRACE_VALUE(bool, as_bool, TRACE_VALUE_TYPE_BOOL) INTERNAL_DECLARE_SET_TRACE_VALUE(double, as_double, TRACE_VALUE_TYPE_DOUBLE) INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, as_pointer, TRACE_VALUE_TYPE_POINTER) INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, as_string, TRACE_VALUE_TYPE_STRING) INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy&, as_string, TRACE_VALUE_TYPE_COPY_STRING) #undef INTERNAL_DECLARE_SET_TRACE_VALUE #undef INTERNAL_DECLARE_SET_TRACE_VALUE_INT // std::string version of SetTraceValue so that trace arguments can be strings. static inline void SetTraceValue(const std::string& arg, unsigned char* type, unsigned long long* value) { TraceValueUnion type_value; type_value.as_string = arg.c_str(); *type = TRACE_VALUE_TYPE_COPY_STRING; *value = type_value.as_uint; } // These AddTraceEvent template functions are defined here instead of in the // macro, because the arg_values could be temporary objects, such as // std::string. In order to store pointers to the internal c_str and pass // through to the tracing API, the arg_values must live throughout // these procedures. static inline void AddTraceEvent(char phase, const unsigned char* category_enabled, const char* name, unsigned long long id, unsigned char flags) { TRACE_EVENT_API_ADD_TRACE_EVENT(phase, category_enabled, name, id, kZeroNumArgs, nullptr, nullptr, nullptr, flags); } template static inline void AddTraceEvent(char phase, const unsigned char* category_enabled, const char* name, unsigned long long id, unsigned char flags, const char* arg1_name, const ARG1_TYPE& arg1_val) { const int num_args = 1; unsigned char arg_types[1]; unsigned long long arg_values[1]; SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]); TRACE_EVENT_API_ADD_TRACE_EVENT( phase, category_enabled, name, id, num_args, &arg1_name, arg_types, arg_values, flags); } template static inline void AddTraceEvent(char phase, const unsigned char* category_enabled, const char* name, unsigned long long id, unsigned char flags, const char* arg1_name, const ARG1_TYPE& arg1_val, const char* arg2_name, const ARG2_TYPE& arg2_val) { const int num_args = 2; const char* arg_names[2] = { arg1_name, arg2_name }; unsigned char arg_types[2]; unsigned long long arg_values[2]; SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]); SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]); TRACE_EVENT_API_ADD_TRACE_EVENT( phase, category_enabled, name, id, num_args, arg_names, arg_types, arg_values, flags); } // Used by TRACE_EVENTx macro. Do not use directly. class TraceEndOnScopeClose { public: // Note: members of data_ intentionally left uninitialized. See Initialize. TraceEndOnScopeClose() : p_data_(nullptr) {} ~TraceEndOnScopeClose() { if (p_data_) AddEventIfEnabled(); } void Initialize(const unsigned char* category_enabled, const char* name) { data_.category_enabled = category_enabled; data_.name = name; p_data_ = &data_; } private: // Add the end event if the category is still enabled. void AddEventIfEnabled() { // Only called when p_data_ is non-null. if (*p_data_->category_enabled) { TRACE_EVENT_API_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_END, p_data_->category_enabled, p_data_->name, kNoEventId, kZeroNumArgs, nullptr, nullptr, nullptr, TRACE_EVENT_FLAG_NONE); } } // This Data struct workaround is to avoid initializing all the members // in Data during construction of this object, since this object is always // constructed, even when tracing is disabled. If the members of Data were // members of this class instead, compiler warnings occur about potential // uninitialized accesses. struct Data { const unsigned char* category_enabled; const char* name; }; Data* p_data_; Data data_; }; } // namespace trace_event_internal } // namespace webrtc #else //////////////////////////////////////////////////////////////////////////////// // This section defines no-op alternatives to the tracing macros when // RTC_DISABLE_TRACE_EVENTS is defined. #define RTC_NOOP() do {} while (0) #define TRACE_STR_COPY(str) RTC_NOOP() #define TRACE_DISABLED_BY_DEFAULT(name) "disabled-by-default-" name #define TRACE_ID_MANGLE(id) 0 #define TRACE_EVENT0(category, name) RTC_NOOP() #define TRACE_EVENT1(category, name, arg1_name, arg1_val) RTC_NOOP() #define TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \ RTC_NOOP() #define TRACE_EVENT_INSTANT0(category, name) RTC_NOOP() #define TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) RTC_NOOP() #define TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \ arg2_name, arg2_val) RTC_NOOP() #define TRACE_EVENT_COPY_INSTANT0(category, name) RTC_NOOP() #define TRACE_EVENT_COPY_INSTANT1(category, name, arg1_name, arg1_val) \ RTC_NOOP() #define TRACE_EVENT_COPY_INSTANT2(category, name, arg1_name, arg1_val, \ arg2_name, arg2_val) RTC_NOOP() #define TRACE_EVENT_BEGIN0(category, name) RTC_NOOP() #define TRACE_EVENT_BEGIN1(category, name, arg1_name, arg1_val) RTC_NOOP() #define TRACE_EVENT_BEGIN2(category, name, arg1_name, arg1_val, \ arg2_name, arg2_val) RTC_NOOP() #define TRACE_EVENT_COPY_BEGIN0(category, name) RTC_NOOP() #define TRACE_EVENT_COPY_BEGIN1(category, name, arg1_name, arg1_val) RTC_NOOP() #define TRACE_EVENT_COPY_BEGIN2(category, name, arg1_name, arg1_val, \ arg2_name, arg2_val) RTC_NOOP() #define TRACE_EVENT_END0(category, name) RTC_NOOP() #define TRACE_EVENT_END1(category, name, arg1_name, arg1_val) RTC_NOOP() #define TRACE_EVENT_END2(category, name, arg1_name, arg1_val, \ arg2_name, arg2_val) RTC_NOOP() #define TRACE_EVENT_COPY_END0(category, name) RTC_NOOP() #define TRACE_EVENT_COPY_END1(category, name, arg1_name, arg1_val) RTC_NOOP() #define TRACE_EVENT_COPY_END2(category, name, arg1_name, arg1_val, \ arg2_name, arg2_val) RTC_NOOP() #define TRACE_COUNTER1(category, name, value) RTC_NOOP() #define TRACE_COPY_COUNTER1(category, name, value) RTC_NOOP() #define TRACE_COUNTER2(category, name, value1_name, value1_val, \ value2_name, value2_val) RTC_NOOP() #define TRACE_COPY_COUNTER2(category, name, value1_name, value1_val, \ value2_name, value2_val) RTC_NOOP() #define TRACE_COUNTER_ID1(category, name, id, value) RTC_NOOP() #define TRACE_COPY_COUNTER_ID1(category, name, id, value) RTC_NOOP() #define TRACE_COUNTER_ID2(category, name, id, value1_name, value1_val, \ value2_name, value2_val) RTC_NOOP() #define TRACE_COPY_COUNTER_ID2(category, name, id, value1_name, value1_val, \ value2_name, value2_val) RTC_NOOP() #define TRACE_EVENT_ASYNC_BEGIN0(category, name, id) RTC_NOOP() #define TRACE_EVENT_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \ RTC_NOOP() #define TRACE_EVENT_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \ arg2_name, arg2_val) RTC_NOOP() #define TRACE_EVENT_COPY_ASYNC_BEGIN0(category, name, id) RTC_NOOP() #define TRACE_EVENT_COPY_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \ RTC_NOOP() #define TRACE_EVENT_COPY_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \ arg2_name, arg2_val) RTC_NOOP() #define TRACE_EVENT_ASYNC_STEP0(category, name, id, step) RTC_NOOP() #define TRACE_EVENT_ASYNC_STEP1(category, name, id, step, \ arg1_name, arg1_val) RTC_NOOP() #define TRACE_EVENT_COPY_ASYNC_STEP0(category, name, id, step) RTC_NOOP() #define TRACE_EVENT_COPY_ASYNC_STEP1(category, name, id, step, \ arg1_name, arg1_val) RTC_NOOP() #define TRACE_EVENT_ASYNC_END0(category, name, id) RTC_NOOP() #define TRACE_EVENT_ASYNC_END1(category, name, id, arg1_name, arg1_val) \ RTC_NOOP() #define TRACE_EVENT_ASYNC_END2(category, name, id, arg1_name, arg1_val, \ arg2_name, arg2_val) RTC_NOOP() #define TRACE_EVENT_COPY_ASYNC_END0(category, name, id) RTC_NOOP() #define TRACE_EVENT_COPY_ASYNC_END1(category, name, id, arg1_name, arg1_val) \ RTC_NOOP() #define TRACE_EVENT_COPY_ASYNC_END2(category, name, id, arg1_name, arg1_val, \ arg2_name, arg2_val) RTC_NOOP() #define TRACE_EVENT_FLOW_BEGIN0(category, name, id) RTC_NOOP() #define TRACE_EVENT_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \ RTC_NOOP() #define TRACE_EVENT_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \ arg2_name, arg2_val) RTC_NOOP() #define TRACE_EVENT_COPY_FLOW_BEGIN0(category, name, id) RTC_NOOP() #define TRACE_EVENT_COPY_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \ RTC_NOOP() #define TRACE_EVENT_COPY_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \ arg2_name, arg2_val) RTC_NOOP() #define TRACE_EVENT_FLOW_STEP0(category, name, id, step) RTC_NOOP() #define TRACE_EVENT_FLOW_STEP1(category, name, id, step, \ arg1_name, arg1_val) RTC_NOOP() #define TRACE_EVENT_COPY_FLOW_STEP0(category, name, id, step) RTC_NOOP() #define TRACE_EVENT_COPY_FLOW_STEP1(category, name, id, step, \ arg1_name, arg1_val) RTC_NOOP() #define TRACE_EVENT_FLOW_END0(category, name, id) RTC_NOOP() #define TRACE_EVENT_FLOW_END1(category, name, id, arg1_name, arg1_val) \ RTC_NOOP() #define TRACE_EVENT_FLOW_END2(category, name, id, arg1_name, arg1_val, \ arg2_name, arg2_val) RTC_NOOP() #define TRACE_EVENT_COPY_FLOW_END0(category, name, id) RTC_NOOP() #define TRACE_EVENT_COPY_FLOW_END1(category, name, id, arg1_name, arg1_val) \ RTC_NOOP() #define TRACE_EVENT_COPY_FLOW_END2(category, name, id, arg1_name, arg1_val, \ arg2_name, arg2_val) RTC_NOOP() #define TRACE_EVENT_API_GET_CATEGORY_ENABLED "" #define TRACE_EVENT_API_ADD_TRACE_EVENT RTC_NOOP() #endif // RTC_TRACE_EVENTS_ENABLED #endif // RTC_BASE_TRACE_EVENT_H_././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/type_traits.h0000664000175000017500000001007614475643423022462 0ustar00arunarun/* * Copyright 2016 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_TYPE_TRAITS_H_ #define RTC_BASE_TYPE_TRAITS_H_ #include #include namespace rtc { // Determines if the given class has zero-argument .data() and .size() methods // whose return values are convertible to T* and size_t, respectively. template class HasDataAndSize { private: template < typename C, typename std::enable_if< std::is_convertible().data()), T*>::value && std::is_convertible().size()), std::size_t>::value>::type* = nullptr> static int Test(int); template static char Test(...); public: static constexpr bool value = std::is_same(0)), int>::value; }; namespace test_has_data_and_size { template struct Test1 { DR data(); SR size(); }; static_assert(HasDataAndSize, int>::value, ""); static_assert(HasDataAndSize, const int>::value, ""); static_assert(HasDataAndSize, const int>::value, ""); static_assert(!HasDataAndSize, int>::value, "implicit cast of const int* to int*"); static_assert(!HasDataAndSize, int>::value, "implicit cast of char* to int*"); struct Test2 { int* data; size_t size; }; static_assert(!HasDataAndSize::value, ".data and .size aren't functions"); struct Test3 { int* data(); }; static_assert(!HasDataAndSize::value, ".size() is missing"); class Test4 { int* data(); size_t size(); }; static_assert(!HasDataAndSize::value, ".data() and .size() are private"); } // namespace test_has_data_and_size namespace type_traits_impl { // Determines if the given type is an enum that converts implicitly to // an integral type. template struct IsIntEnum { private: // This overload is used if the type is an enum, and unary plus // compiles and turns it into an integral type. template ::value && std::is_integral())>::value>::type* = nullptr> static int Test(int); // Otherwise, this overload is used. template static char Test(...); public: static constexpr bool value = std::is_same::type>(0)), int>::value; }; } // namespace type_traits_impl // Determines if the given type is integral, or an enum that // converts implicitly to an integral type. template struct IsIntlike { private: using X = typename std::remove_reference::type; public: static constexpr bool value = std::is_integral::value || type_traits_impl::IsIntEnum::value; }; namespace test_enum_intlike { enum E1 { e1 }; enum { e2 }; enum class E3 { e3 }; struct S {}; static_assert(type_traits_impl::IsIntEnum::value, ""); static_assert(type_traits_impl::IsIntEnum::value, ""); static_assert(!type_traits_impl::IsIntEnum::value, ""); static_assert(!type_traits_impl::IsIntEnum::value, ""); static_assert(!type_traits_impl::IsIntEnum::value, ""); static_assert(!type_traits_impl::IsIntEnum::value, ""); static_assert(IsIntlike::value, ""); static_assert(IsIntlike::value, ""); static_assert(!IsIntlike::value, ""); static_assert(IsIntlike::value, ""); static_assert(!IsIntlike::value, ""); static_assert(!IsIntlike::value, ""); } // namespace test_enum_intlike } // namespace rtc #endif // RTC_BASE_TYPE_TRAITS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/units/0000775000175000017500000000000014475643423021100 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/units/BUILD.gn0000664000175000017500000000147114475643423022270 0ustar00arunarun# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import("../../webrtc.gni") rtc_source_set("unit_base") { visibility = [ "../../api/units:*", ":*", ] sources = [ "unit_base.h" ] deps = [ "../../rtc_base:checks", "../../rtc_base:safe_conversions", ] } if (rtc_include_tests) { rtc_library("units_unittests") { testonly = true sources = [ "unit_base_unittest.cc" ] deps = [ ":unit_base", "../../test:test_support", ] } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/units/unit_base.h0000664000175000017500000002513014475643423023223 0ustar00arunarun/* * Copyright 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_UNITS_UNIT_BASE_H_ #define RTC_BASE_UNITS_UNIT_BASE_H_ #include #include #include #include #include #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_conversions.h" namespace webrtc { namespace rtc_units_impl { // UnitBase is a base class for implementing custom value types with a specific // unit. It provides type safety and commonly useful operations. The underlying // storage is always an int64_t, it's up to the unit implementation to choose // what scale it represents. // // It's used like: // class MyUnit: public UnitBase {...}; // // Unit_T is the subclass representing the specific unit. template class UnitBase { public: UnitBase() = delete; static constexpr Unit_T Zero() { return Unit_T(0); } static constexpr Unit_T PlusInfinity() { return Unit_T(PlusInfinityVal()); } static constexpr Unit_T MinusInfinity() { return Unit_T(MinusInfinityVal()); } constexpr bool IsZero() const { return value_ == 0; } constexpr bool IsFinite() const { return !IsInfinite(); } constexpr bool IsInfinite() const { return value_ == PlusInfinityVal() || value_ == MinusInfinityVal(); } constexpr bool IsPlusInfinity() const { return value_ == PlusInfinityVal(); } constexpr bool IsMinusInfinity() const { return value_ == MinusInfinityVal(); } constexpr bool operator==(const Unit_T& other) const { return value_ == other.value_; } constexpr bool operator!=(const Unit_T& other) const { return value_ != other.value_; } constexpr bool operator<=(const Unit_T& other) const { return value_ <= other.value_; } constexpr bool operator>=(const Unit_T& other) const { return value_ >= other.value_; } constexpr bool operator>(const Unit_T& other) const { return value_ > other.value_; } constexpr bool operator<(const Unit_T& other) const { return value_ < other.value_; } constexpr Unit_T RoundTo(const Unit_T& resolution) const { RTC_DCHECK(IsFinite()); RTC_DCHECK(resolution.IsFinite()); RTC_DCHECK_GT(resolution.value_, 0); return Unit_T((value_ + resolution.value_ / 2) / resolution.value_) * resolution.value_; } constexpr Unit_T RoundUpTo(const Unit_T& resolution) const { RTC_DCHECK(IsFinite()); RTC_DCHECK(resolution.IsFinite()); RTC_DCHECK_GT(resolution.value_, 0); return Unit_T((value_ + resolution.value_ - 1) / resolution.value_) * resolution.value_; } constexpr Unit_T RoundDownTo(const Unit_T& resolution) const { RTC_DCHECK(IsFinite()); RTC_DCHECK(resolution.IsFinite()); RTC_DCHECK_GT(resolution.value_, 0); return Unit_T(value_ / resolution.value_) * resolution.value_; } protected: template < typename T, typename std::enable_if::value>::type* = nullptr> static constexpr Unit_T FromValue(T value) { if (Unit_T::one_sided) RTC_DCHECK_GE(value, 0); RTC_DCHECK_GT(value, MinusInfinityVal()); RTC_DCHECK_LT(value, PlusInfinityVal()); return Unit_T(rtc::dchecked_cast(value)); } template ::value>::type* = nullptr> static constexpr Unit_T FromValue(T value) { if (value == std::numeric_limits::infinity()) { return PlusInfinity(); } else if (value == -std::numeric_limits::infinity()) { return MinusInfinity(); } else { RTC_DCHECK(!std::isnan(value)); return FromValue(rtc::dchecked_cast(value)); } } template < typename T, typename std::enable_if::value>::type* = nullptr> static constexpr Unit_T FromFraction(int64_t denominator, T value) { if (Unit_T::one_sided) RTC_DCHECK_GE(value, 0); RTC_DCHECK_GT(value, MinusInfinityVal() / denominator); RTC_DCHECK_LT(value, PlusInfinityVal() / denominator); return Unit_T(rtc::dchecked_cast(value * denominator)); } template ::value>::type* = nullptr> static constexpr Unit_T FromFraction(int64_t denominator, T value) { return FromValue(value * denominator); } template constexpr typename std::enable_if::value, T>::type ToValue() const { RTC_DCHECK(IsFinite()); return rtc::dchecked_cast(value_); } template constexpr typename std::enable_if::value, T>::type ToValue() const { return IsPlusInfinity() ? std::numeric_limits::infinity() : IsMinusInfinity() ? -std::numeric_limits::infinity() : value_; } template constexpr T ToValueOr(T fallback_value) const { return IsFinite() ? value_ : fallback_value; } template constexpr typename std::enable_if::value, T>::type ToFraction() const { RTC_DCHECK(IsFinite()); if (Unit_T::one_sided) { return rtc::dchecked_cast( DivRoundPositiveToNearest(value_, Denominator)); } else { return rtc::dchecked_cast(DivRoundToNearest(value_, Denominator)); } } template constexpr typename std::enable_if::value, T>::type ToFraction() const { return ToValue() * (1 / static_cast(Denominator)); } template constexpr int64_t ToFractionOr(int64_t fallback_value) const { return IsFinite() ? Unit_T::one_sided ? DivRoundPositiveToNearest(value_, Denominator) : DivRoundToNearest(value_, Denominator) : fallback_value; } template constexpr typename std::enable_if::value, T>::type ToMultiple() const { RTC_DCHECK_GE(ToValue(), std::numeric_limits::min() / Factor); RTC_DCHECK_LE(ToValue(), std::numeric_limits::max() / Factor); return rtc::dchecked_cast(ToValue() * Factor); } template constexpr typename std::enable_if::value, T>::type ToMultiple() const { return ToValue() * Factor; } explicit constexpr UnitBase(int64_t value) : value_(value) {} private: template friend class RelativeUnit; static inline constexpr int64_t PlusInfinityVal() { return std::numeric_limits::max(); } static inline constexpr int64_t MinusInfinityVal() { return std::numeric_limits::min(); } constexpr Unit_T& AsSubClassRef() { return static_cast(*this); } constexpr const Unit_T& AsSubClassRef() const { return static_cast(*this); } // Assumes that n >= 0 and d > 0. static constexpr int64_t DivRoundPositiveToNearest(int64_t n, int64_t d) { return (n + d / 2) / d; } // Assumes that d > 0. static constexpr int64_t DivRoundToNearest(int64_t n, int64_t d) { return (n + (n >= 0 ? d / 2 : -d / 2)) / d; } int64_t value_; }; // Extends UnitBase to provide operations for relative units, that is, units // that have a meaningful relation between values such that a += b is a // sensible thing to do. For a,b <- same unit. template class RelativeUnit : public UnitBase { public: constexpr Unit_T Clamped(Unit_T min_value, Unit_T max_value) const { return std::max(min_value, std::min(UnitBase::AsSubClassRef(), max_value)); } constexpr void Clamp(Unit_T min_value, Unit_T max_value) { *this = Clamped(min_value, max_value); } constexpr Unit_T operator+(const Unit_T other) const { if (this->IsPlusInfinity() || other.IsPlusInfinity()) { RTC_DCHECK(!this->IsMinusInfinity()); RTC_DCHECK(!other.IsMinusInfinity()); return this->PlusInfinity(); } else if (this->IsMinusInfinity() || other.IsMinusInfinity()) { RTC_DCHECK(!this->IsPlusInfinity()); RTC_DCHECK(!other.IsPlusInfinity()); return this->MinusInfinity(); } return UnitBase::FromValue(this->ToValue() + other.ToValue()); } constexpr Unit_T operator-(const Unit_T other) const { if (this->IsPlusInfinity() || other.IsMinusInfinity()) { RTC_DCHECK(!this->IsMinusInfinity()); RTC_DCHECK(!other.IsPlusInfinity()); return this->PlusInfinity(); } else if (this->IsMinusInfinity() || other.IsPlusInfinity()) { RTC_DCHECK(!this->IsPlusInfinity()); RTC_DCHECK(!other.IsMinusInfinity()); return this->MinusInfinity(); } return UnitBase::FromValue(this->ToValue() - other.ToValue()); } constexpr Unit_T& operator+=(const Unit_T other) { *this = *this + other; return this->AsSubClassRef(); } constexpr Unit_T& operator-=(const Unit_T other) { *this = *this - other; return this->AsSubClassRef(); } constexpr double operator/(const Unit_T other) const { return UnitBase::template ToValue() / other.template ToValue(); } template constexpr typename std::enable_if::value, Unit_T>::type operator/(const T& scalar) const { return UnitBase::FromValue( std::round(UnitBase::template ToValue() / scalar)); } constexpr Unit_T operator*(double scalar) const { return UnitBase::FromValue(std::round(this->ToValue() * scalar)); } constexpr Unit_T operator*(int64_t scalar) const { return UnitBase::FromValue(this->ToValue() * scalar); } constexpr Unit_T operator*(int32_t scalar) const { return UnitBase::FromValue(this->ToValue() * scalar); } protected: using UnitBase::UnitBase; }; template inline constexpr Unit_T operator*(double scalar, RelativeUnit other) { return other * scalar; } template inline constexpr Unit_T operator*(int64_t scalar, RelativeUnit other) { return other * scalar; } template inline constexpr Unit_T operator*(int32_t scalar, RelativeUnit other) { return other * scalar; } } // namespace rtc_units_impl } // namespace webrtc #endif // RTC_BASE_UNITS_UNIT_BASE_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/win32.h0000664000175000017500000000505314475643423021054 0ustar00arunarun/* * Copyright 2004 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_WIN32_H_ #define RTC_BASE_WIN32_H_ #ifndef WEBRTC_WIN #error "Only #include this header in Windows builds" #endif // Make sure we don't get min/max macros #ifndef NOMINMAX #define NOMINMAX #endif // clang-format off // clang formating would change include order. #include // must come first #include // clang-format on typedef int socklen_t; #ifndef SECURITY_MANDATORY_LABEL_AUTHORITY // Add defines that we use if we are compiling against older sdks #define SECURITY_MANDATORY_MEDIUM_RID (0x00002000L) #define TokenIntegrityLevel static_cast(0x19) typedef struct _TOKEN_MANDATORY_LABEL { SID_AND_ATTRIBUTES Label; } TOKEN_MANDATORY_LABEL, *PTOKEN_MANDATORY_LABEL; #endif // SECURITY_MANDATORY_LABEL_AUTHORITY #undef SetPort #include namespace rtc { const char* win32_inet_ntop(int af, const void* src, char* dst, socklen_t size); int win32_inet_pton(int af, const char* src, void* dst); enum WindowsMajorVersions { kWindows2000 = 5, kWindowsVista = 6, kWindows10 = 10, }; #if !defined(WINUWP) bool GetOsVersion(int* major, int* minor, int* build); inline bool IsWindowsVistaOrLater() { int major; return (GetOsVersion(&major, nullptr, nullptr) && major >= kWindowsVista); } inline bool IsWindowsXpOrLater() { int major, minor; return (GetOsVersion(&major, &minor, nullptr) && (major >= kWindowsVista || (major == kWindows2000 && minor >= 1))); } inline bool IsWindows8OrLater() { int major, minor; return (GetOsVersion(&major, &minor, nullptr) && (major > kWindowsVista || (major == kWindowsVista && minor >= 2))); } inline bool IsWindows10OrLater() { int major; return (GetOsVersion(&major, nullptr, nullptr) && (major >= kWindows10)); } #else // When targetting WinUWP the OS must be Windows 10 (or greater) as lesser // Windows OS targets are not supported. inline bool IsWindowsVistaOrLater() { return true; } inline bool IsWindowsXpOrLater() { return true; } inline bool IsWindows8OrLater() { return true; } inline bool IsWindows10OrLater() { return true; } #endif // !defined(WINUWP) } // namespace rtc #endif // RTC_BASE_WIN32_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/zero_memory.cc0000664000175000017500000000217214475643423022616 0ustar00arunarun/* * Copyright 2017 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #if defined(WEBRTC_WIN) #include #else #include #endif #include "rtc_base/checks.h" #include "rtc_base/zero_memory.h" namespace rtc { // Code and comment taken from "OPENSSL_cleanse" of BoringSSL. void ExplicitZeroMemory(void* ptr, size_t len) { RTC_DCHECK(ptr || !len); #if defined(WEBRTC_WIN) SecureZeroMemory(ptr, len); #else memset(ptr, 0, len); #if !defined(__pnacl__) /* As best as we can tell, this is sufficient to break any optimisations that might try to eliminate "superfluous" memsets. If there's an easy way to detect memset_s, it would be better to use that. */ __asm__ __volatile__("" : : "r"(ptr) : "memory"); // NOLINT #endif #endif // !WEBRTC_WIN } } // namespace rtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/rtc_base/zero_memory.h0000664000175000017500000000203314475643423022454 0ustar00arunarun/* * Copyright 2017 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_ZERO_MEMORY_H_ #define RTC_BASE_ZERO_MEMORY_H_ #include #include #include "api/array_view.h" namespace rtc { // Fill memory with zeros in a way that the compiler doesn't optimize it away // even if the pointer is not used afterwards. void ExplicitZeroMemory(void* ptr, size_t len); template ::value && std::is_trivial::value>::type* = nullptr> void ExplicitZeroMemory(rtc::ArrayView a) { ExplicitZeroMemory(a.data(), a.size()); } } // namespace rtc #endif // RTC_BASE_ZERO_MEMORY_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/system_wrappers/0000775000175000017500000000000014475643423021423 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/system_wrappers/BUILD.gn0000664000175000017500000000702114475643423022610 0ustar00arunarun# Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. if (is_android) { import("//build/config/android/config.gni") import("//build/config/android/rules.gni") } import("../webrtc.gni") rtc_library("system_wrappers") { visibility = [ "*" ] sources = [ "include/clock.h", "include/cpu_features_wrapper.h", "include/cpu_info.h", "include/ntp_time.h", "include/rtp_to_ntp_estimator.h", "include/sleep.h", "source/clock.cc", "source/cpu_features.cc", "source/cpu_info.cc", "source/rtp_to_ntp_estimator.cc", "source/sleep.cc", ] defines = [] libs = [] deps = [ ":field_trial", "../api:array_view", "../api/units:timestamp", "../modules:module_api_public", "../rtc_base:checks", "../rtc_base/synchronization:mutex", "../rtc_base/synchronization:rw_lock_wrapper", "../rtc_base/system:arch", "../rtc_base/system:rtc_export", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] if (is_android) { if (build_with_mozilla) { include_dirs = [ "/config/external/nspr", "/nsprpub/lib/ds", "/nsprpub/pr/include", ] } else { sources += [ "source/cpu_features_android.cc" ] deps += [ "//third_party/android_sdk:cpu_features" ] } libs += [ "log" ] } if (is_linux || is_chromeos) { if (!build_with_chromium) { sources += [ "source/cpu_features_linux.cc" ] } libs += [ "rt" ] } if (is_win) { libs += [ "winmm.lib" ] # Windows needs ../rtc_base due to include of # webrtc/rtc_base/win32.h in source/clock.cc. deps += [ "../rtc_base:win32" ] } deps += [ "../rtc_base:rtc_base_approved", "../rtc_base:rtc_numerics", ] } rtc_library("field_trial") { visibility = [ "*" ] public = [ "include/field_trial.h" ] sources = [ "source/field_trial.cc" ] if (rtc_exclude_field_trial_default) { defines = [ "WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT" ] } deps = [ "../rtc_base:checks", "../rtc_base:logging", "../rtc_base:stringutils", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } rtc_library("metrics") { visibility = [ "*" ] public = [ "include/metrics.h" ] sources = [ "source/metrics.cc" ] if (rtc_exclude_metrics_default) { defines = [ "WEBRTC_EXCLUDE_METRICS_DEFAULT" ] } deps = [ "../rtc_base:checks", "../rtc_base:rtc_base_approved", "../rtc_base/synchronization:mutex", ] } if (rtc_include_tests) { rtc_test("system_wrappers_unittests") { testonly = true sources = [ "source/clock_unittest.cc", "source/field_trial_unittest.cc", "source/metrics_default_unittest.cc", "source/metrics_unittest.cc", "source/ntp_time_unittest.cc", "source/rtp_to_ntp_estimator_unittest.cc", ] deps = [ ":field_trial", ":metrics", ":system_wrappers", "../rtc_base:checks", "../rtc_base:rtc_base_approved", "../test:rtc_expect_death", "../test:test_main", "../test:test_support", "//testing/gtest", "//third_party/abseil-cpp/absl/strings", ] if (is_android) { deps += [ "//testing/android/native_test:native_test_support" ] shard_timeout = 900 } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/system_wrappers/include/0000775000175000017500000000000014475643423023046 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/system_wrappers/include/cpu_features_wrapper.h0000664000175000017500000000237614475643423027454 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef SYSTEM_WRAPPERS_INCLUDE_CPU_FEATURES_WRAPPER_H_ #define SYSTEM_WRAPPERS_INCLUDE_CPU_FEATURES_WRAPPER_H_ #include namespace webrtc { // List of features in x86. typedef enum { kSSE2, kSSE3, kAVX2 } CPUFeature; // List of features in ARM. enum { kCPUFeatureARMv7 = (1 << 0), kCPUFeatureVFPv3 = (1 << 1), kCPUFeatureNEON = (1 << 2), kCPUFeatureLDREXSTREX = (1 << 3) }; // Returns true if the CPU supports the feature. int GetCPUInfo(CPUFeature feature); // No CPU feature is available => straight C path. int GetCPUInfoNoASM(CPUFeature feature); // Return the features in an ARM device. // It detects the features in the hardware platform, and returns supported // values in the above enum definition as a bitmask. uint64_t GetCPUFeaturesARM(void); } // namespace webrtc #endif // SYSTEM_WRAPPERS_INCLUDE_CPU_FEATURES_WRAPPER_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/system_wrappers/include/field_trial.h0000664000175000017500000000757114475643423025507 0ustar00arunarun// // Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. // // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file in the root of the source // tree. An additional intellectual property rights grant can be found // in the file PATENTS. All contributing project authors may // be found in the AUTHORS file in the root of the source tree. // #ifndef SYSTEM_WRAPPERS_INCLUDE_FIELD_TRIAL_H_ #define SYSTEM_WRAPPERS_INCLUDE_FIELD_TRIAL_H_ #include // Field trials allow webrtc clients (such as Chrome) to turn on feature code // in binaries out in the field and gather information with that. // // By default WebRTC provides an implementation of field trials that can be // found in system_wrappers/source/field_trial.cc. If clients want to provide // a custom version, they will have to: // // 1. Compile WebRTC defining the preprocessor macro // WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT (if GN is used this can be achieved // by setting the GN arg rtc_exclude_field_trial_default to true). // 2. Provide an implementation of: // std::string webrtc::field_trial::FindFullName(const std::string& trial). // // They are designed to wire up directly to chrome field trials and to speed up // developers by reducing the need to wire APIs to control whether a feature is // on/off. E.g. to experiment with a new method that could lead to a different // trade-off between CPU/bandwidth: // // 1 - Develop the feature with default behaviour off: // // if (FieldTrial::FindFullName("WebRTCExperimentMethod2") == "Enabled") // method2(); // else // method1(); // // 2 - Once the changes are rolled to chrome, the new code path can be // controlled as normal chrome field trials. // // 3 - Evaluate the new feature and clean the code paths. // // Notes: // - NOT every feature is a candidate to be controlled by this mechanism as // it may require negotiation between involved parties (e.g. SDP). // // TODO(andresp): since chrome --force-fieldtrials does not marks the trial // as active it does not get propagated to the renderer process. For now one // needs to push a config with start_active:true or run a local finch // server. // // TODO(andresp): find out how to get bots to run tests with trials enabled. namespace webrtc { namespace field_trial { // Returns the group name chosen for the named trial, or the empty string // if the trial does not exists. // // Note: To keep things tidy append all the trial names with WebRTC. std::string FindFullName(const std::string& name); // Convenience method, returns true iff FindFullName(name) return a string that // starts with "Enabled". // TODO(tommi): Make sure all implementations support this. inline bool IsEnabled(const char* name) { return FindFullName(name).find("Enabled") == 0; } // Convenience method, returns true iff FindFullName(name) return a string that // starts with "Disabled". inline bool IsDisabled(const char* name) { return FindFullName(name).find("Disabled") == 0; } // Optionally initialize field trial from a string. // This method can be called at most once before any other call into webrtc. // E.g. before the peer connection factory is constructed. // Note: trials_string must never be destroyed. void InitFieldTrialsFromString(const char* trials_string); const char* GetFieldTrialString(); #ifndef WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT // Validates the given field trial string. bool FieldTrialsStringIsValid(const char* trials_string); // Merges two field trial strings. // // If a key (trial) exists twice with conflicting values (groups), the value // in 'second' takes precedence. // Shall only be called with valid FieldTrial strings. std::string MergeFieldTrialsStrings(const char* first, const char* second); #endif // WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT } // namespace field_trial } // namespace webrtc #endif // SYSTEM_WRAPPERS_INCLUDE_FIELD_TRIAL_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/system_wrappers/include/metrics.h0000664000175000017500000004466114475643423024700 0ustar00arunarun// // Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. // // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file in the root of the source // tree. An additional intellectual property rights grant can be found // in the file PATENTS. All contributing project authors may // be found in the AUTHORS file in the root of the source tree. // #ifndef SYSTEM_WRAPPERS_INCLUDE_METRICS_H_ #define SYSTEM_WRAPPERS_INCLUDE_METRICS_H_ #include #include #include #include #include "rtc_base/atomic_ops.h" #include "rtc_base/checks.h" #if defined(RTC_DISABLE_METRICS) #define RTC_METRICS_ENABLED 0 #else #define RTC_METRICS_ENABLED 1 #endif namespace webrtc { namespace metrics_impl { template void NoOp(const Ts&...) {} } } #if RTC_METRICS_ENABLED #define EXPECT_METRIC_EQ(val1, val2) EXPECT_EQ(val1, val2) #define EXPECT_METRIC_EQ_WAIT(val1, val2, timeout) \ EXPECT_EQ_WAIT(val1, val2, timeout) #define EXPECT_METRIC_GT(val1, val2) EXPECT_GT(val1, val2) #define EXPECT_METRIC_LE(val1, val2) EXPECT_LE(val1, val2) #define EXPECT_METRIC_TRUE(conditon) EXPECT_TRUE(conditon) #define EXPECT_METRIC_FALSE(conditon) EXPECT_FALSE(conditon) #define EXPECT_METRIC_THAT(value, matcher) EXPECT_THAT(value, matcher) #else #define EXPECT_METRIC_EQ(val1, val2) webrtc::metrics_impl::NoOp(val1, val2) #define EXPECT_METRIC_EQ_WAIT(val1, val2, timeout) webrtc::metrics_impl::NoOp(val1, val2, timeout) #define EXPECT_METRIC_GT(val1, val2) webrtc::metrics_impl::NoOp(val1, val2) #define EXPECT_METRIC_LE(val1, val2) webrtc::metrics_impl::NoOp(val1, val2) #define EXPECT_METRIC_TRUE(condition) webrtc::metrics_impl::NoOp(condition || true) #define EXPECT_METRIC_FALSE(condition) webrtc::metrics_impl::NoOp(condition && false) #define EXPECT_METRIC_THAT(value, matcher) webrtc::metrics_impl::NoOp(value, testing::_) #endif #if RTC_METRICS_ENABLED // Macros for allowing WebRTC clients (e.g. Chrome) to gather and aggregate // statistics. // // Histogram for counters. // RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count); // // Histogram for enumerators. // The boundary should be above the max enumerator sample. // RTC_HISTOGRAM_ENUMERATION(name, sample, boundary); // // // The macros use the methods HistogramFactoryGetCounts, // HistogramFactoryGetEnumeration and HistogramAdd. // // By default WebRTC provides implementations of the aforementioned methods // that can be found in system_wrappers/source/metrics.cc. If clients want to // provide a custom version, they will have to: // // 1. Compile WebRTC defining the preprocessor macro // WEBRTC_EXCLUDE_METRICS_DEFAULT (if GN is used this can be achieved // by setting the GN arg rtc_exclude_metrics_default to true). // 2. Provide implementations of: // Histogram* webrtc::metrics::HistogramFactoryGetCounts( // const std::string& name, int sample, int min, int max, // int bucket_count); // Histogram* webrtc::metrics::HistogramFactoryGetEnumeration( // const std::string& name, int sample, int boundary); // void webrtc::metrics::HistogramAdd( // Histogram* histogram_pointer, const std::string& name, int sample); // // Example usage: // // RTC_HISTOGRAM_COUNTS("WebRTC.Video.NacksSent", nacks_sent, 1, 100000, 100); // // enum Types { // kTypeX, // kTypeY, // kBoundary, // }; // // RTC_HISTOGRAM_ENUMERATION("WebRTC.Types", kTypeX, kBoundary); // // NOTE: It is recommended to do the Chromium review for modifications to // histograms.xml before new metrics are committed to WebRTC. // Macros for adding samples to a named histogram. // Histogram for counters (exponentially spaced buckets). #define RTC_HISTOGRAM_COUNTS_100(name, sample) \ RTC_HISTOGRAM_COUNTS(name, sample, 1, 100, 50) #define RTC_HISTOGRAM_COUNTS_200(name, sample) \ RTC_HISTOGRAM_COUNTS(name, sample, 1, 200, 50) #define RTC_HISTOGRAM_COUNTS_500(name, sample) \ RTC_HISTOGRAM_COUNTS(name, sample, 1, 500, 50) #define RTC_HISTOGRAM_COUNTS_1000(name, sample) \ RTC_HISTOGRAM_COUNTS(name, sample, 1, 1000, 50) #define RTC_HISTOGRAM_COUNTS_10000(name, sample) \ RTC_HISTOGRAM_COUNTS(name, sample, 1, 10000, 50) #define RTC_HISTOGRAM_COUNTS_100000(name, sample) \ RTC_HISTOGRAM_COUNTS(name, sample, 1, 100000, 50) #define RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count) \ RTC_HISTOGRAM_COMMON_BLOCK(name, sample, \ webrtc::metrics::HistogramFactoryGetCounts( \ name, min, max, bucket_count)) #define RTC_HISTOGRAM_COUNTS_LINEAR(name, sample, min, max, bucket_count) \ RTC_HISTOGRAM_COMMON_BLOCK(name, sample, \ webrtc::metrics::HistogramFactoryGetCountsLinear( \ name, min, max, bucket_count)) // Slow metrics: pointer to metric is acquired at each call and is not cached. // #define RTC_HISTOGRAM_COUNTS_SPARSE_100(name, sample) \ RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 100, 50) #define RTC_HISTOGRAM_COUNTS_SPARSE_200(name, sample) \ RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 200, 50) #define RTC_HISTOGRAM_COUNTS_SPARSE_500(name, sample) \ RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 500, 50) #define RTC_HISTOGRAM_COUNTS_SPARSE_1000(name, sample) \ RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 1000, 50) #define RTC_HISTOGRAM_COUNTS_SPARSE_10000(name, sample) \ RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 10000, 50) #define RTC_HISTOGRAM_COUNTS_SPARSE_100000(name, sample) \ RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 100000, 50) #define RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, min, max, bucket_count) \ RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample, \ webrtc::metrics::HistogramFactoryGetCounts( \ name, min, max, bucket_count)) // Histogram for percentage (evenly spaced buckets). #define RTC_HISTOGRAM_PERCENTAGE_SPARSE(name, sample) \ RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, 101) // Histogram for booleans. #define RTC_HISTOGRAM_BOOLEAN_SPARSE(name, sample) \ RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, 2) // Histogram for enumerators (evenly spaced buckets). // |boundary| should be above the max enumerator sample. // // TODO(qingsi): Refactor the default implementation given by RtcHistogram, // which is already sparse, and remove the boundary argument from the macro. #define RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, boundary) \ RTC_HISTOGRAM_COMMON_BLOCK_SLOW( \ name, sample, \ webrtc::metrics::SparseHistogramFactoryGetEnumeration(name, boundary)) // Histogram for percentage (evenly spaced buckets). #define RTC_HISTOGRAM_PERCENTAGE(name, sample) \ RTC_HISTOGRAM_ENUMERATION(name, sample, 101) // Histogram for booleans. #define RTC_HISTOGRAM_BOOLEAN(name, sample) \ RTC_HISTOGRAM_ENUMERATION(name, sample, 2) // Histogram for enumerators (evenly spaced buckets). // |boundary| should be above the max enumerator sample. #define RTC_HISTOGRAM_ENUMERATION(name, sample, boundary) \ RTC_HISTOGRAM_COMMON_BLOCK_SLOW( \ name, sample, \ webrtc::metrics::HistogramFactoryGetEnumeration(name, boundary)) // The name of the histogram should not vary. // TODO(asapersson): Consider changing string to const char*. #define RTC_HISTOGRAM_COMMON_BLOCK(constant_name, sample, \ factory_get_invocation) \ do { \ static webrtc::metrics::Histogram* atomic_histogram_pointer = nullptr; \ webrtc::metrics::Histogram* histogram_pointer = \ rtc::AtomicOps::AcquireLoadPtr(&atomic_histogram_pointer); \ if (!histogram_pointer) { \ histogram_pointer = factory_get_invocation; \ webrtc::metrics::Histogram* prev_pointer = \ rtc::AtomicOps::CompareAndSwapPtr( \ &atomic_histogram_pointer, \ static_cast(nullptr), \ histogram_pointer); \ RTC_DCHECK(prev_pointer == nullptr || \ prev_pointer == histogram_pointer); \ } \ if (histogram_pointer) { \ webrtc::metrics::HistogramAdd(histogram_pointer, sample); \ } \ } while (0) // The histogram is constructed/found for each call. // May be used for histograms with infrequent updates.` #define RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample, factory_get_invocation) \ do { \ webrtc::metrics::Histogram* histogram_pointer = factory_get_invocation; \ if (histogram_pointer) { \ webrtc::metrics::HistogramAdd(histogram_pointer, sample); \ } \ } while (0) // Helper macros. // Macros for calling a histogram with varying name (e.g. when using a metric // in different modes such as real-time vs screenshare). Fast, because pointer // is cached. |index| should be different for different names. Allowed |index| // values are 0, 1, and 2. #define RTC_HISTOGRAMS_COUNTS_100(index, name, sample) \ RTC_HISTOGRAMS_COMMON(index, name, sample, \ RTC_HISTOGRAM_COUNTS(name, sample, 1, 100, 50)) #define RTC_HISTOGRAMS_COUNTS_200(index, name, sample) \ RTC_HISTOGRAMS_COMMON(index, name, sample, \ RTC_HISTOGRAM_COUNTS(name, sample, 1, 200, 50)) #define RTC_HISTOGRAMS_COUNTS_500(index, name, sample) \ RTC_HISTOGRAMS_COMMON(index, name, sample, \ RTC_HISTOGRAM_COUNTS(name, sample, 1, 500, 50)) #define RTC_HISTOGRAMS_COUNTS_1000(index, name, sample) \ RTC_HISTOGRAMS_COMMON(index, name, sample, \ RTC_HISTOGRAM_COUNTS(name, sample, 1, 1000, 50)) #define RTC_HISTOGRAMS_COUNTS_10000(index, name, sample) \ RTC_HISTOGRAMS_COMMON(index, name, sample, \ RTC_HISTOGRAM_COUNTS(name, sample, 1, 10000, 50)) #define RTC_HISTOGRAMS_COUNTS_100000(index, name, sample) \ RTC_HISTOGRAMS_COMMON(index, name, sample, \ RTC_HISTOGRAM_COUNTS(name, sample, 1, 100000, 50)) #define RTC_HISTOGRAMS_ENUMERATION(index, name, sample, boundary) \ RTC_HISTOGRAMS_COMMON(index, name, sample, \ RTC_HISTOGRAM_ENUMERATION(name, sample, boundary)) #define RTC_HISTOGRAMS_PERCENTAGE(index, name, sample) \ RTC_HISTOGRAMS_COMMON(index, name, sample, \ RTC_HISTOGRAM_PERCENTAGE(name, sample)) #define RTC_HISTOGRAMS_COMMON(index, name, sample, macro_invocation) \ do { \ switch (index) { \ case 0: \ macro_invocation; \ break; \ case 1: \ macro_invocation; \ break; \ case 2: \ macro_invocation; \ break; \ default: \ RTC_NOTREACHED(); \ } \ } while (0) #else //////////////////////////////////////////////////////////////////////////////// // This section defines no-op alternatives to the metrics macros when // RTC_METRICS_ENABLED is defined. #define RTC_HISTOGRAM_COUNTS_100(name, sample) webrtc::metrics_impl::NoOp(name, sample) #define RTC_HISTOGRAM_COUNTS_200(name, sample) webrtc::metrics_impl::NoOp(name, sample) #define RTC_HISTOGRAM_COUNTS_500(name, sample) webrtc::metrics_impl::NoOp(name, sample) #define RTC_HISTOGRAM_COUNTS_1000(name, sample) webrtc::metrics_impl::NoOp(name, sample) #define RTC_HISTOGRAM_COUNTS_10000(name, sample) webrtc::metrics_impl::NoOp(name, sample) #define RTC_HISTOGRAM_COUNTS_100000(name, sample) webrtc::metrics_impl::NoOp(name, sample) #define RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count) \ webrtc::metrics_impl::NoOp(name, sample, min, max, bucket_count) #define RTC_HISTOGRAM_COUNTS_LINEAR(name, sample, min, max, bucket_count) \ webrtc::metrics_impl::NoOp(name, sample, min, max, bucket_count) #define RTC_HISTOGRAM_COUNTS_SPARSE_100(name, sample) webrtc::metrics_impl::NoOp(name, sample) #define RTC_HISTOGRAM_COUNTS_SPARSE_200(name, sample) webrtc::metrics_impl::NoOp(name, sample) #define RTC_HISTOGRAM_COUNTS_SPARSE_500(name, sample) webrtc::metrics_impl::NoOp(name, sample) #define RTC_HISTOGRAM_COUNTS_SPARSE_1000(name, sample) webrtc::metrics_impl::NoOp(name, sample) #define RTC_HISTOGRAM_COUNTS_SPARSE_10000(name, sample) webrtc::metrics_impl::NoOp(name, sample) #define RTC_HISTOGRAM_COUNTS_SPARSE_100000(name, sample) webrtc::metrics_impl::NoOp(name, sample) #define RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, min, max, bucket_count) \ webrtc::metrics_impl::NoOp(name, sample, min, max, bucket_count) #define RTC_HISTOGRAM_PERCENTAGE_SPARSE(name, sample) webrtc::metrics_impl::NoOp(name, sample) #define RTC_HISTOGRAM_BOOLEAN_SPARSE(name, sample) webrtc::metrics_impl::NoOp(name, sample) #define RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, boundary) \ webrtc::metrics_impl::NoOp(name, sample, boundary) #define RTC_HISTOGRAM_PERCENTAGE(name, sample) webrtc::metrics_impl::NoOp(name, sample) #define RTC_HISTOGRAM_BOOLEAN(name, sample) webrtc::metrics_impl::NoOp(name, sample) #define RTC_HISTOGRAM_ENUMERATION(name, sample, boundary) \ webrtc::metrics_impl::NoOp(name, sample, boundary) #define RTC_HISTOGRAM_COMMON_BLOCK(constant_name, sample, \ factory_get_invocation) \ webrtc::metrics_impl::NoOp(constant_name, sample, factory_get_invocation) #define RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample, factory_get_invocation) \ webrtc::metrics_impl::NoOp(name, sample, factory_get_invocation) #define RTC_HISTOGRAMS_COUNTS_100(index, name, sample) webrtc::metrics_impl::NoOp(index, name, sample) #define RTC_HISTOGRAMS_COUNTS_200(index, name, sample) webrtc::metrics_impl::NoOp(index, name, sample) #define RTC_HISTOGRAMS_COUNTS_500(index, name, sample) webrtc::metrics_impl::NoOp(index, name, sample) #define RTC_HISTOGRAMS_COUNTS_1000(index, name, sample) \ webrtc::metrics_impl::NoOp(index, name, sample) #define RTC_HISTOGRAMS_COUNTS_10000(index, name, sample) \ webrtc::metrics_impl::NoOp(index, name, sample) #define RTC_HISTOGRAMS_COUNTS_100000(index, name, sample) \ webrtc::metrics_impl::NoOp(index, name, sample) #define RTC_HISTOGRAMS_ENUMERATION(index, name, sample, boundary) \ webrtc::metrics_impl::NoOp(index, name, sample, boundary) #define RTC_HISTOGRAMS_PERCENTAGE(index, name, sample) webrtc::metrics_impl::NoOp(index, name, sample) #define RTC_HISTOGRAMS_COMMON(index, name, sample, macro_invocation) \ webrtc::metrics_impl::NoOp(index, name, sample, macro_invocation) #endif // RTC_METRICS_ENABLED namespace webrtc { namespace metrics { // Time that should have elapsed for stats that are gathered once per call. enum { kMinRunTimeInSeconds = 10 }; class Histogram; // Functions for getting pointer to histogram (constructs or finds the named // histogram). // Get histogram for counters. Histogram* HistogramFactoryGetCounts(const std::string& name, int min, int max, int bucket_count); // Get histogram for counters with linear bucket spacing. Histogram* HistogramFactoryGetCountsLinear(const std::string& name, int min, int max, int bucket_count); // Get histogram for enumerators. // |boundary| should be above the max enumerator sample. Histogram* HistogramFactoryGetEnumeration(const std::string& name, int boundary); // Get sparse histogram for enumerators. // |boundary| should be above the max enumerator sample. Histogram* SparseHistogramFactoryGetEnumeration(const std::string& name, int boundary); // Function for adding a |sample| to a histogram. void HistogramAdd(Histogram* histogram_pointer, int sample); struct SampleInfo { SampleInfo(const std::string& name, int min, int max, size_t bucket_count); ~SampleInfo(); const std::string name; const int min; const int max; const size_t bucket_count; std::map samples; // }; // Enables collection of samples. // This method should be called before any other call into webrtc. void Enable(); // Gets histograms and clears all samples. void GetAndReset( std::map>* histograms); // Functions below are mainly for testing. // Clears all samples. void Reset(); // Returns the number of times the |sample| has been added to the histogram. int NumEvents(const std::string& name, int sample); // Returns the total number of added samples to the histogram. int NumSamples(const std::string& name); // Returns the minimum sample value (or -1 if the histogram has no samples). int MinSample(const std::string& name); // Returns a map with keys the samples with at least one event and values the // number of events for that sample. std::map Samples(const std::string& name); } // namespace metrics } // namespace webrtc #endif // SYSTEM_WRAPPERS_INCLUDE_METRICS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/system_wrappers/include/sleep.h0000664000175000017500000000147214475643423024333 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // An OS-independent sleep function. #ifndef SYSTEM_WRAPPERS_INCLUDE_SLEEP_H_ #define SYSTEM_WRAPPERS_INCLUDE_SLEEP_H_ namespace webrtc { // This function sleeps for the specified number of milliseconds. // It may return early if the thread is woken by some other event, // such as the delivery of a signal on Unix. void SleepMs(int msecs); } // namespace webrtc #endif // SYSTEM_WRAPPERS_INCLUDE_SLEEP_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/system_wrappers/meson.build0000664000175000017500000000116414475643423023567 0ustar00arunarunsystem_wrappers_sources = [ 'source/cpu_features.cc', 'source/field_trial.cc', 'source/metrics.cc', 'source/sleep.cc', ] system_headers = [ 'include/cpu_features_wrapper.h', 'include/metrics.h', 'include/sleep.h', ] install_headers(system_headers, subdir: join_paths(include_subdir, 'system_wrappers', 'include') ) libsystem_wrappers = static_library('system_wrappers', system_wrappers_sources, dependencies: common_deps, include_directories: webrtc_inc, c_args : common_cflags, cpp_args : common_cxxflags ) system_wrappers_dep = declare_dependency( link_with: libsystem_wrappers ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/system_wrappers/source/0000775000175000017500000000000014475643423022723 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/system_wrappers/source/cpu_features.cc0000664000175000017500000000660414475643423025725 0ustar00arunarun/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Parts of this file derived from Chromium's base/cpu.cc. #include "rtc_base/system/arch.h" #include "system_wrappers/include/cpu_features_wrapper.h" #include "system_wrappers/include/field_trial.h" #if defined(WEBRTC_ARCH_X86_FAMILY) && defined(_MSC_VER) #include #endif namespace webrtc { // No CPU feature is available => straight C path. int GetCPUInfoNoASM(CPUFeature feature) { (void)feature; return 0; } #if defined(WEBRTC_ARCH_X86_FAMILY) #if defined(WEBRTC_ENABLE_AVX2) // xgetbv returns the value of an Intel Extended Control Register (XCR). // Currently only XCR0 is defined by Intel so |xcr| should always be zero. static uint64_t xgetbv(uint32_t xcr) { #if defined(_MSC_VER) return _xgetbv(xcr); #else uint32_t eax, edx; __asm__ volatile("xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr)); return (static_cast(edx) << 32) | eax; #endif // _MSC_VER } #endif // WEBRTC_ENABLE_AVX2 #ifndef _MSC_VER // Intrinsic for "cpuid". #if defined(__pic__) && defined(__i386__) static inline void __cpuid(int cpu_info[4], int info_type) { __asm__ volatile( "mov %%ebx, %%edi\n" "cpuid\n" "xchg %%edi, %%ebx\n" : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) : "a"(info_type)); } #else static inline void __cpuid(int cpu_info[4], int info_type) { __asm__ volatile("cpuid\n" : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) : "a"(info_type), "c"(0)); } #endif #endif // _MSC_VER #endif // WEBRTC_ARCH_X86_FAMILY #if defined(WEBRTC_ARCH_X86_FAMILY) // Actual feature detection for x86. int GetCPUInfo(CPUFeature feature) { int cpu_info[4]; __cpuid(cpu_info, 1); if (feature == kSSE2) { return 0 != (cpu_info[3] & 0x04000000); } if (feature == kSSE3) { return 0 != (cpu_info[2] & 0x00000001); } #if defined(WEBRTC_ENABLE_AVX2) if (feature == kAVX2 && !webrtc::field_trial::IsEnabled("WebRTC-Avx2SupportKillSwitch")) { int cpu_info7[4]; __cpuid(cpu_info7, 0); int num_ids = cpu_info7[0]; if (num_ids < 7) { return 0; } // Interpret CPU feature information. __cpuid(cpu_info7, 7); // AVX instructions can be used when // a) AVX are supported by the CPU, // b) XSAVE is supported by the CPU, // c) XSAVE is enabled by the kernel. // See http://software.intel.com/en-us/blogs/2011/04/14/is-avx-enabled // AVX2 support needs (avx_support && (cpu_info7[1] & 0x00000020) != 0;). return (cpu_info[2] & 0x10000000) != 0 && (cpu_info[2] & 0x04000000) != 0 /* XSAVE */ && (cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ && (xgetbv(0) & 0x00000006) == 6 /* XSAVE enabled by kernel */ && (cpu_info7[1] & 0x00000020) != 0; } #endif // WEBRTC_ENABLE_AVX2 return 0; } #else // Default to straight C for other platforms. int GetCPUInfo(CPUFeature feature) { (void)feature; return 0; } #endif } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/system_wrappers/source/field_trial.cc0000664000175000017500000001224314475643423025512 0ustar00arunarun// Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. // // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file in the root of the source // tree. An additional intellectual property rights grant can be found // in the file PATENTS. All contributing project authors may // be found in the AUTHORS file in the root of the source tree. // #include "system_wrappers/include/field_trial.h" #include #include #include #include "absl/strings/string_view.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/string_encode.h" // Simple field trial implementation, which allows client to // specify desired flags in InitFieldTrialsFromString. namespace webrtc { namespace field_trial { static const char* trials_init_string = NULL; #ifndef WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT namespace { constexpr char kPersistentStringSeparator = '/'; // Validates the given field trial string. // E.g.: // "WebRTC-experimentFoo/Enabled/WebRTC-experimentBar/Enabled100kbps/" // Assigns the process to group "Enabled" on WebRTCExperimentFoo trial // and to group "Enabled100kbps" on WebRTCExperimentBar. // // E.g. invalid config: // "WebRTC-experiment1/Enabled" (note missing / separator at the end). bool FieldTrialsStringIsValidInternal(const absl::string_view trials) { if (trials.empty()) return true; size_t next_item = 0; std::map field_trials; while (next_item < trials.length()) { size_t name_end = trials.find(kPersistentStringSeparator, next_item); if (name_end == trials.npos || next_item == name_end) return false; size_t group_name_end = trials.find(kPersistentStringSeparator, name_end + 1); if (group_name_end == trials.npos || name_end + 1 == group_name_end) return false; absl::string_view name = trials.substr(next_item, name_end - next_item); absl::string_view group_name = trials.substr(name_end + 1, group_name_end - name_end - 1); next_item = group_name_end + 1; // Fail if duplicate with different group name. if (field_trials.find(name) != field_trials.end() && field_trials.find(name)->second != group_name) { return false; } field_trials[name] = group_name; } return true; } } // namespace bool FieldTrialsStringIsValid(const char* trials_string) { return FieldTrialsStringIsValidInternal(trials_string); } void InsertOrReplaceFieldTrialStringsInMap( std::map* fieldtrial_map, const absl::string_view trials_string) { if (FieldTrialsStringIsValidInternal(trials_string)) { std::vector tokens; rtc::split(std::string(trials_string), '/', &tokens); // Skip last token which is empty due to trailing '/'. for (size_t idx = 0; idx < tokens.size() - 1; idx += 2) { (*fieldtrial_map)[tokens[idx]] = tokens[idx + 1]; } } else { RTC_DCHECK(false) << "Invalid field trials string:" << trials_string; } } std::string MergeFieldTrialsStrings(const char* first, const char* second) { std::map fieldtrial_map; InsertOrReplaceFieldTrialStringsInMap(&fieldtrial_map, first); InsertOrReplaceFieldTrialStringsInMap(&fieldtrial_map, second); // Merge into fieldtrial string. std::string merged = ""; for (auto const& fieldtrial : fieldtrial_map) { merged += fieldtrial.first + '/' + fieldtrial.second + '/'; } return merged; } std::string FindFullName(const std::string& name) { if (trials_init_string == NULL) return std::string(); std::string trials_string(trials_init_string); if (trials_string.empty()) return std::string(); size_t next_item = 0; while (next_item < trials_string.length()) { // Find next name/value pair in field trial configuration string. size_t field_name_end = trials_string.find(kPersistentStringSeparator, next_item); if (field_name_end == trials_string.npos || field_name_end == next_item) break; size_t field_value_end = trials_string.find(kPersistentStringSeparator, field_name_end + 1); if (field_value_end == trials_string.npos || field_value_end == field_name_end + 1) break; std::string field_name(trials_string, next_item, field_name_end - next_item); std::string field_value(trials_string, field_name_end + 1, field_value_end - field_name_end - 1); next_item = field_value_end + 1; if (name == field_name) return field_value; } return std::string(); } #endif // WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT // Optionally initialize field trial from a string. void InitFieldTrialsFromString(const char* trials_string) { RTC_LOG(LS_INFO) << "Setting field trial string:" << trials_string; #ifndef WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT if (trials_string) { RTC_DCHECK(FieldTrialsStringIsValidInternal(trials_string)) << "Invalid field trials string:" << trials_string; }; #endif // WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT trials_init_string = trials_string; } const char* GetFieldTrialString() { return trials_init_string; } } // namespace field_trial } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/system_wrappers/source/metrics.cc0000664000175000017500000002334014475643423024702 0ustar00arunarun// Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. // // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file in the root of the source // tree. An additional intellectual property rights grant can be found // in the file PATENTS. All contributing project authors may // be found in the AUTHORS file in the root of the source tree. // #include "system_wrappers/include/metrics.h" #include #include "rtc_base/constructor_magic.h" #include "rtc_base/synchronization/mutex.h" #include "rtc_base/thread_annotations.h" // Default implementation of histogram methods for WebRTC clients that do not // want to provide their own implementation. namespace webrtc { namespace metrics { class Histogram; namespace { // Limit for the maximum number of sample values that can be stored. // TODO(asapersson): Consider using bucket count (and set up // linearly/exponentially spaced buckets) if samples are logged more frequently. const int kMaxSampleMapSize = 300; class RtcHistogram { public: RtcHistogram(const std::string& name, int min, int max, int bucket_count) : min_(min), max_(max), info_(name, min, max, bucket_count) { RTC_DCHECK_GT(bucket_count, 0); } void Add(int sample) { sample = std::min(sample, max_); sample = std::max(sample, min_ - 1); // Underflow bucket. MutexLock lock(&mutex_); if (info_.samples.size() == kMaxSampleMapSize && info_.samples.find(sample) == info_.samples.end()) { return; } ++info_.samples[sample]; } // Returns a copy (or nullptr if there are no samples) and clears samples. std::unique_ptr GetAndReset() { MutexLock lock(&mutex_); if (info_.samples.empty()) return nullptr; SampleInfo* copy = new SampleInfo(info_.name, info_.min, info_.max, info_.bucket_count); std::swap(info_.samples, copy->samples); return std::unique_ptr(copy); } const std::string& name() const { return info_.name; } // Functions only for testing. void Reset() { MutexLock lock(&mutex_); info_.samples.clear(); } int NumEvents(int sample) const { MutexLock lock(&mutex_); const auto it = info_.samples.find(sample); return (it == info_.samples.end()) ? 0 : it->second; } int NumSamples() const { int num_samples = 0; MutexLock lock(&mutex_); for (const auto& sample : info_.samples) { num_samples += sample.second; } return num_samples; } int MinSample() const { MutexLock lock(&mutex_); return (info_.samples.empty()) ? -1 : info_.samples.begin()->first; } std::map Samples() const { MutexLock lock(&mutex_); return info_.samples; } private: mutable Mutex mutex_; const int min_; const int max_; SampleInfo info_ RTC_GUARDED_BY(mutex_); RTC_DISALLOW_COPY_AND_ASSIGN(RtcHistogram); }; class RtcHistogramMap { public: RtcHistogramMap() {} ~RtcHistogramMap() {} Histogram* GetCountsHistogram(const std::string& name, int min, int max, int bucket_count) { MutexLock lock(&mutex_); const auto& it = map_.find(name); if (it != map_.end()) return reinterpret_cast(it->second.get()); RtcHistogram* hist = new RtcHistogram(name, min, max, bucket_count); map_[name].reset(hist); return reinterpret_cast(hist); } Histogram* GetEnumerationHistogram(const std::string& name, int boundary) { MutexLock lock(&mutex_); const auto& it = map_.find(name); if (it != map_.end()) return reinterpret_cast(it->second.get()); RtcHistogram* hist = new RtcHistogram(name, 1, boundary, boundary + 1); map_[name].reset(hist); return reinterpret_cast(hist); } void GetAndReset( std::map>* histograms) { MutexLock lock(&mutex_); for (const auto& kv : map_) { std::unique_ptr info = kv.second->GetAndReset(); if (info) histograms->insert(std::make_pair(kv.first, std::move(info))); } } // Functions only for testing. void Reset() { MutexLock lock(&mutex_); for (const auto& kv : map_) kv.second->Reset(); } int NumEvents(const std::string& name, int sample) const { MutexLock lock(&mutex_); const auto& it = map_.find(name); return (it == map_.end()) ? 0 : it->second->NumEvents(sample); } int NumSamples(const std::string& name) const { MutexLock lock(&mutex_); const auto& it = map_.find(name); return (it == map_.end()) ? 0 : it->second->NumSamples(); } int MinSample(const std::string& name) const { MutexLock lock(&mutex_); const auto& it = map_.find(name); return (it == map_.end()) ? -1 : it->second->MinSample(); } std::map Samples(const std::string& name) const { MutexLock lock(&mutex_); const auto& it = map_.find(name); return (it == map_.end()) ? std::map() : it->second->Samples(); } private: mutable Mutex mutex_; std::map> map_ RTC_GUARDED_BY(mutex_); RTC_DISALLOW_COPY_AND_ASSIGN(RtcHistogramMap); }; // RtcHistogramMap is allocated upon call to Enable(). // The histogram getter functions, which return pointer values to the histograms // in the map, are cached in WebRTC. Therefore, this memory is not freed by the // application (the memory will be reclaimed by the OS). static RtcHistogramMap* volatile g_rtc_histogram_map = nullptr; void CreateMap() { RtcHistogramMap* map = rtc::AtomicOps::AcquireLoadPtr(&g_rtc_histogram_map); if (map == nullptr) { RtcHistogramMap* new_map = new RtcHistogramMap(); RtcHistogramMap* old_map = rtc::AtomicOps::CompareAndSwapPtr( &g_rtc_histogram_map, static_cast(nullptr), new_map); if (old_map != nullptr) delete new_map; } } // Set the first time we start using histograms. Used to make sure Enable() is // not called thereafter. #if RTC_DCHECK_IS_ON static volatile int g_rtc_histogram_called = 0; #endif // Gets the map (or nullptr). RtcHistogramMap* GetMap() { #if RTC_DCHECK_IS_ON rtc::AtomicOps::ReleaseStore(&g_rtc_histogram_called, 1); #endif return g_rtc_histogram_map; } } // namespace #ifndef WEBRTC_EXCLUDE_METRICS_DEFAULT // Implementation of histogram methods in // webrtc/system_wrappers/interface/metrics.h. // Histogram with exponentially spaced buckets. // Creates (or finds) histogram. // The returned histogram pointer is cached (and used for adding samples in // subsequent calls). Histogram* HistogramFactoryGetCounts(const std::string& name, int min, int max, int bucket_count) { // TODO(asapersson): Alternative implementation will be needed if this // histogram type should be truly exponential. return HistogramFactoryGetCountsLinear(name, min, max, bucket_count); } // Histogram with linearly spaced buckets. // Creates (or finds) histogram. // The returned histogram pointer is cached (and used for adding samples in // subsequent calls). Histogram* HistogramFactoryGetCountsLinear(const std::string& name, int min, int max, int bucket_count) { RtcHistogramMap* map = GetMap(); if (!map) return nullptr; return map->GetCountsHistogram(name, min, max, bucket_count); } // Histogram with linearly spaced buckets. // Creates (or finds) histogram. // The returned histogram pointer is cached (and used for adding samples in // subsequent calls). Histogram* HistogramFactoryGetEnumeration(const std::string& name, int boundary) { RtcHistogramMap* map = GetMap(); if (!map) return nullptr; return map->GetEnumerationHistogram(name, boundary); } // Our default implementation reuses the non-sparse histogram. Histogram* SparseHistogramFactoryGetEnumeration(const std::string& name, int boundary) { return HistogramFactoryGetEnumeration(name, boundary); } // Fast path. Adds |sample| to cached |histogram_pointer|. void HistogramAdd(Histogram* histogram_pointer, int sample) { RtcHistogram* ptr = reinterpret_cast(histogram_pointer); ptr->Add(sample); } #endif // WEBRTC_EXCLUDE_METRICS_DEFAULT SampleInfo::SampleInfo(const std::string& name, int min, int max, size_t bucket_count) : name(name), min(min), max(max), bucket_count(bucket_count) {} SampleInfo::~SampleInfo() {} // Implementation of global functions in metrics.h. void Enable() { RTC_DCHECK(g_rtc_histogram_map == nullptr); #if RTC_DCHECK_IS_ON RTC_DCHECK_EQ(0, rtc::AtomicOps::AcquireLoad(&g_rtc_histogram_called)); #endif CreateMap(); } void GetAndReset( std::map>* histograms) { histograms->clear(); RtcHistogramMap* map = GetMap(); if (map) map->GetAndReset(histograms); } void Reset() { RtcHistogramMap* map = GetMap(); if (map) map->Reset(); } int NumEvents(const std::string& name, int sample) { RtcHistogramMap* map = GetMap(); return map ? map->NumEvents(name, sample) : 0; } int NumSamples(const std::string& name) { RtcHistogramMap* map = GetMap(); return map ? map->NumSamples(name) : 0; } int MinSample(const std::string& name) { RtcHistogramMap* map = GetMap(); return map ? map->MinSample(name) : -1; } std::map Samples(const std::string& name) { RtcHistogramMap* map = GetMap(); return map ? map->Samples(name) : std::map(); } } // namespace metrics } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/system_wrappers/source/sleep.cc0000664000175000017500000000160114475643423024340 0ustar00arunarun/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // An OS-independent sleep function. #include "system_wrappers/include/sleep.h" #ifdef _WIN32 // For Sleep() #include #else // For nanosleep() #include #endif namespace webrtc { void SleepMs(int msecs) { #ifdef _WIN32 Sleep(msecs); #else struct timespec short_wait; struct timespec remainder; short_wait.tv_sec = msecs / 1000; short_wait.tv_nsec = (msecs % 1000) * 1000 * 1000; nanosleep(&short_wait, &remainder); #endif } } // namespace webrtc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/third_party/0000775000175000017500000000000014475643423020505 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/third_party/pffft/0000775000175000017500000000000014475643423021612 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/third_party/pffft/BUILD.gn0000664000175000017500000000467514475643423023013 0ustar00arunarun# Copyright 2019 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import("//build/config/arm.gni") import("//testing/libfuzzer/fuzzer_test.gni") import("//testing/test.gni") config("common_config") { if (is_win) { defines = [ # Required to use math constants from math.h. "_USE_MATH_DEFINES", ] } # PFFFT doesn't support SIMD on some cpus, so build a scalar version. if ((current_cpu == "arm" && !arm_use_neon) || current_cpu == "mipsel" || current_cpu == "mips64el" || current_cpu == "ppc64" || current_cpu == "s390x") { defines = [ "PFFFT_SIMD_DISABLE" ] } } static_library("pffft") { configs += [ ":common_config" ] sources = [ "src/pffft.c", "src/pffft.h", ] } # Fuzzing. group("fuzzers") { testonly = true deps = [ ":pffft_complex_fuzzer", ":pffft_real_fuzzer", ] } fuzzer_testdata_dir = "$target_gen_dir/testdata" action("generate_pffft_fuzzer_corpus") { script = "generate_seed_corpus.py" sources = [ "generate_seed_corpus.py" ] args = [ rebase_path(fuzzer_testdata_dir, root_build_dir) ] outputs = [ fuzzer_testdata_dir ] } fuzzer_test("pffft_complex_fuzzer") { sources = [ "pffft_fuzzer.cc" ] cflags = [ "-DTRANSFORM_COMPLEX" ] deps = [ ":pffft" ] seed_corpus = fuzzer_testdata_dir seed_corpus_deps = [ ":generate_pffft_fuzzer_corpus" ] } fuzzer_test("pffft_real_fuzzer") { sources = [ "pffft_fuzzer.cc" ] cflags = [ "-DTRANSFORM_REAL" ] deps = [ ":pffft" ] seed_corpus = fuzzer_testdata_dir seed_corpus_deps = [ ":generate_pffft_fuzzer_corpus" ] } # Unit tests and benchmark. # This target must be used only for testing and benchmark purposes. static_library("fftpack") { testonly = true configs += [ ":common_config" ] sources = [ "src/fftpack.c", "src/fftpack.h", ] visibility = [ ":*" ] } config("pffft_benchmark_internal_config") { cflags = [ # test_pffft.c contains an `exit(1)` following a `break` statement. "-Wno-unreachable-code", ] } executable("pffft_benchmark") { testonly = true configs += [ ":common_config", ":pffft_benchmark_internal_config", ] sources = [ "src/test_pffft.c" ] deps = [ ":fftpack", ":pffft", ] } test("pffft_unittest") { testonly = true sources = [ "pffft_unittest.cc" ] deps = [ ":fftpack", ":pffft", "//testing/gtest", "//testing/gtest:gtest_main", ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/third_party/pffft/LICENSE0000664000175000017500000000500014475643423022612 0ustar00arunarunQ29weXJpZ2h0IChjKSAyMDEzICBKdWxpZW4gUG9tbWllciAoIHBvbW1pZXJAbW9kYXJ0dC5jb20gKQoKQmFzZWQgb24gb3JpZ2luYWwgZm9ydHJhbiA3NyBjb2RlIGZyb20gRkZUUEFDS3Y0IGZyb20gTkVUTElCLAphdXRob3JlZCBieSBEciBQYXVsIFN3YXJ6dHJhdWJlciBvZiBOQ0FSLCBpbiAxOTg1LgoKQXMgY29uZmlybWVkIGJ5IHRoZSBOQ0FSIGZmdHBhY2sgc29mdHdhcmUgY3VyYXRvcnMsIHRoZSBmb2xsb3dpbmcKRkZUUEFDS3Y1IGxpY2Vuc2UgYXBwbGllcyB0byBGRlRQQUNLdjQgc291cmNlcy4gTXkgY2hhbmdlcyBhcmUKcmVsZWFzZWQgdW5kZXIgdGhlIHNhbWUgdGVybXMuCgpGRlRQQUNLIGxpY2Vuc2U6CgpodHRwOi8vd3d3LmNpc2wudWNhci5lZHUvY3NzL3NvZnR3YXJlL2ZmdHBhY2s1L2Z0cGsuaHRtbAoKQ29weXJpZ2h0IChjKSAyMDA0IHRoZSBVbml2ZXJzaXR5IENvcnBvcmF0aW9uIGZvciBBdG1vc3BoZXJpYwpSZXNlYXJjaCAoIlVDQVIiKS4gQWxsIHJpZ2h0cyByZXNlcnZlZC4gRGV2ZWxvcGVkIGJ5IE5DQVIncwpDb21wdXRhdGlvbmFsIGFuZCBJbmZvcm1hdGlvbiBTeXN0ZW1zIExhYm9yYXRvcnksIFVDQVIsCnd3dy5jaXNsLnVjYXIuZWR1LgoKUmVkaXN0cmlidXRpb24gYW5kIHVzZSBvZiB0aGUgU29mdHdhcmUgaW4gc291cmNlIGFuZCBiaW5hcnkgZm9ybXMsCndpdGggb3Igd2l0aG91dCBtb2RpZmljYXRpb24sIGlzIHBlcm1pdHRlZCBwcm92aWRlZCB0aGF0IHRoZQpmb2xsb3dpbmcgY29uZGl0aW9ucyBhcmUgbWV0OgoKLSBOZWl0aGVyIHRoZSBuYW1lcyBvZiBOQ0FSJ3MgQ29tcHV0YXRpb25hbCBhbmQgSW5mb3JtYXRpb24gU3lzdGVtcwpMYWJvcmF0b3J5LCB0aGUgVW5pdmVyc2l0eSBDb3Jwb3JhdGlvbiBmb3IgQXRtb3NwaGVyaWMgUmVzZWFyY2gsCm5vciB0aGUgbmFtZXMgb2YgaXRzIHNwb25zb3JzIG9yIGNvbnRyaWJ1dG9ycyBtYXkgYmUgdXNlZCB0bwplbmRvcnNlIG9yIHByb21vdGUgcHJvZHVjdHMgZGVyaXZlZCBmcm9tIHRoaXMgU29mdHdhcmUgd2l0aG91dApzcGVjaWZpYyBwcmlvciB3cml0dGVuIHBlcm1pc3Npb24uCgotIFJlZGlzdHJpYnV0aW9ucyBvZiBzb3VyY2UgY29kZSBtdXN0IHJldGFpbiB0aGUgYWJvdmUgY29weXJpZ2h0Cm5vdGljZXMsIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zLCBhbmQgdGhlIGRpc2NsYWltZXIgYmVsb3cuCgotIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0Cm5vdGljZSwgdGhpcyBsaXN0IG9mIGNvbmRpdGlvbnMsIGFuZCB0aGUgZGlzY2xhaW1lciBiZWxvdyBpbiB0aGUKZG9jdW1lbnRhdGlvbiBhbmQvb3Igb3RoZXIgbWF0ZXJpYWxzIHByb3ZpZGVkIHdpdGggdGhlCmRpc3RyaWJ1dGlvbi4KClRISVMgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwKRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRgpNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORApOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRSBDT05UUklCVVRPUlMgT1IgQ09QWVJJR0hUCkhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIElORElSRUNULCBJTkNJREVOVEFMLCBTUEVDSUFMLApFWEVNUExBUlksIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4KQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLCBPVVQgT0YgT1IgSU4KQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIFdJVEggVEhFClNPRlRXQVJFLgo=././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/third_party/pffft/meson.build0000664000175000017500000000070714475643423023760 0ustar00arunarunpffft_sources = [ 'src/pffft.c', ] pffft_cflags = [ '-D_GNU_SOURCE' ] if (have_arm and not have_neon) or (have_mips and host_machine.endian() == 'little') or have_mips64 pffft_cflags += [ '-DPFFFT_SIMD_DISABLE' ] endif libpffft = static_library('libpffft', pffft_sources, dependencies: common_deps, include_directories: webrtc_inc, c_args : common_cflags + pffft_cflags ) pffft_dep = declare_dependency( link_with: libpffft ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/third_party/pffft/src/0000775000175000017500000000000014475643423022401 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/third_party/pffft/src/pffft.c0000664000175000017500000020153114475643423023654 0ustar00arunarun/* Copyright (c) 2013 Julien Pommier ( pommier@modartt.com ) Based on original fortran 77 code from FFTPACKv4 from NETLIB (http://www.netlib.org/fftpack), authored by Dr Paul Swarztrauber of NCAR, in 1985. As confirmed by the NCAR fftpack software curators, the following FFTPACKv5 license applies to FFTPACKv4 sources. My changes are released under the same terms. FFTPACK license: http://www.cisl.ucar.edu/css/software/fftpack5/ftpk.html Copyright (c) 2004 the University Corporation for Atmospheric Research ("UCAR"). All rights reserved. Developed by NCAR's Computational and Information Systems Laboratory, UCAR, www.cisl.ucar.edu. Redistribution and use of the Software in source and binary forms, with or without modification, is permitted provided that the following conditions are met: - Neither the names of NCAR's Computational and Information Systems Laboratory, the University Corporation for Atmospheric Research, nor the names of its sponsors or contributors may be used to endorse or promote products derived from this Software without specific prior written permission. - Redistributions of source code must retain the above copyright notices, this list of conditions, and the disclaimer below. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the disclaimer below in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. PFFFT : a Pretty Fast FFT. This file is largerly based on the original FFTPACK implementation, modified in order to take advantage of SIMD instructions of modern CPUs. */ /* ChangeLog: - 2011/10/02, version 1: This is the very first release of this file. */ #include "pffft.h" #include #include #include #include /* detect compiler flavour */ #if defined(_MSC_VER) # define COMPILER_MSVC #elif defined(__GNUC__) # define COMPILER_GCC #endif #if defined(COMPILER_GCC) # define ALWAYS_INLINE(return_type) inline return_type __attribute__ ((always_inline)) # define NEVER_INLINE(return_type) return_type __attribute__ ((noinline)) # define RESTRICT __restrict # define VLA_ARRAY_ON_STACK(type__, varname__, size__) type__ varname__[size__]; # define VLA_ARRAY_ON_STACK_FREE(varname__) #elif defined(COMPILER_MSVC) #include # define ALWAYS_INLINE(return_type) __forceinline return_type # define NEVER_INLINE(return_type) __declspec(noinline) return_type # define RESTRICT __restrict # define VLA_ARRAY_ON_STACK(type__, varname__, size__) type__ *varname__ = (type__*)_malloca(size__ * sizeof(type__)) # define VLA_ARRAY_ON_STACK_FREE(varname__) _freea(varname__) #endif /* vector support macros: the rest of the code is independant of SSE/Altivec/NEON -- adding support for other platforms with 4-element vectors should be limited to these macros */ // define PFFFT_SIMD_DISABLE if you want to use scalar code instead of simd code //#define PFFFT_SIMD_DISABLE /* Altivec support macros */ #if !defined(PFFFT_SIMD_DISABLE) && (defined(__ppc__) || defined(__ppc64__)) typedef vector float v4sf; # define SIMD_SZ 4 # define VZERO() ((vector float) vec_splat_u8(0)) # define VMUL(a,b) vec_madd(a,b, VZERO()) # define VADD(a,b) vec_add(a,b) # define VMADD(a,b,c) vec_madd(a,b,c) # define VSUB(a,b) vec_sub(a,b) inline v4sf ld_ps1(const float *p) { v4sf v=vec_lde(0,p); return vec_splat(vec_perm(v, v, vec_lvsl(0, p)), 0); } # define LD_PS1(p) ld_ps1(&p) # define INTERLEAVE2(in1, in2, out1, out2) { v4sf tmp__ = vec_mergeh(in1, in2); out2 = vec_mergel(in1, in2); out1 = tmp__; } # define UNINTERLEAVE2(in1, in2, out1, out2) { \ vector unsigned char vperm1 = (vector unsigned char)(0,1,2,3,8,9,10,11,16,17,18,19,24,25,26,27); \ vector unsigned char vperm2 = (vector unsigned char)(4,5,6,7,12,13,14,15,20,21,22,23,28,29,30,31); \ v4sf tmp__ = vec_perm(in1, in2, vperm1); out2 = vec_perm(in1, in2, vperm2); out1 = tmp__; \ } # define VTRANSPOSE4(x0,x1,x2,x3) { \ v4sf y0 = vec_mergeh(x0, x2); \ v4sf y1 = vec_mergel(x0, x2); \ v4sf y2 = vec_mergeh(x1, x3); \ v4sf y3 = vec_mergel(x1, x3); \ x0 = vec_mergeh(y0, y2); \ x1 = vec_mergel(y0, y2); \ x2 = vec_mergeh(y1, y3); \ x3 = vec_mergel(y1, y3); \ } # define VSWAPHL(a,b) vec_perm(a,b, (vector unsigned char)(16,17,18,19,20,21,22,23,8,9,10,11,12,13,14,15)) # define VALIGNED(ptr) ((((uintptr_t)(ptr)) & 0xF) == 0) /* SSE1 support macros */ #elif !defined(PFFFT_SIMD_DISABLE) && (defined(__x86_64__) || defined(_M_X64) || defined(i386) || defined(__i386__) || defined(_M_IX86)) #include typedef __m128 v4sf; # define SIMD_SZ 4 // 4 floats by simd vector -- this is pretty much hardcoded in the preprocess/finalize functions anyway so you will have to work if you want to enable AVX with its 256-bit vectors. # define VZERO() _mm_setzero_ps() # define VMUL(a,b) _mm_mul_ps(a,b) # define VADD(a,b) _mm_add_ps(a,b) # define VMADD(a,b,c) _mm_add_ps(_mm_mul_ps(a,b), c) # define VSUB(a,b) _mm_sub_ps(a,b) # define LD_PS1(p) _mm_set1_ps(p) # define INTERLEAVE2(in1, in2, out1, out2) { v4sf tmp__ = _mm_unpacklo_ps(in1, in2); out2 = _mm_unpackhi_ps(in1, in2); out1 = tmp__; } # define UNINTERLEAVE2(in1, in2, out1, out2) { v4sf tmp__ = _mm_shuffle_ps(in1, in2, _MM_SHUFFLE(2,0,2,0)); out2 = _mm_shuffle_ps(in1, in2, _MM_SHUFFLE(3,1,3,1)); out1 = tmp__; } # define VTRANSPOSE4(x0,x1,x2,x3) _MM_TRANSPOSE4_PS(x0,x1,x2,x3) # define VSWAPHL(a,b) _mm_shuffle_ps(b, a, _MM_SHUFFLE(3,2,1,0)) # define VALIGNED(ptr) ((((uintptr_t)(ptr)) & 0xF) == 0) /* ARM NEON support macros */ #elif !defined(PFFFT_SIMD_DISABLE) && (defined(__arm__) || defined(__ARMEL__) || defined(__aarch64__) || defined(_M_ARM64)) # include typedef float32x4_t v4sf; # define SIMD_SZ 4 # define VZERO() vdupq_n_f32(0) # define VMUL(a,b) vmulq_f32(a,b) # define VADD(a,b) vaddq_f32(a,b) # define VMADD(a,b,c) vmlaq_f32(c,a,b) # define VSUB(a,b) vsubq_f32(a,b) # define LD_PS1(p) vld1q_dup_f32(&(p)) # define INTERLEAVE2(in1, in2, out1, out2) { float32x4x2_t tmp__ = vzipq_f32(in1,in2); out1=tmp__.val[0]; out2=tmp__.val[1]; } # define UNINTERLEAVE2(in1, in2, out1, out2) { float32x4x2_t tmp__ = vuzpq_f32(in1,in2); out1=tmp__.val[0]; out2=tmp__.val[1]; } # define VTRANSPOSE4(x0,x1,x2,x3) { \ float32x4x2_t t0_ = vzipq_f32(x0, x2); \ float32x4x2_t t1_ = vzipq_f32(x1, x3); \ float32x4x2_t u0_ = vzipq_f32(t0_.val[0], t1_.val[0]); \ float32x4x2_t u1_ = vzipq_f32(t0_.val[1], t1_.val[1]); \ x0 = u0_.val[0]; x1 = u0_.val[1]; x2 = u1_.val[0]; x3 = u1_.val[1]; \ } // marginally faster version //# define VTRANSPOSE4(x0,x1,x2,x3) { asm("vtrn.32 %q0, %q1;\n vtrn.32 %q2,%q3\n vswp %f0,%e2\n vswp %f1,%e3" : "+w"(x0), "+w"(x1), "+w"(x2), "+w"(x3)::); } # define VSWAPHL(a,b) vcombine_f32(vget_low_f32(b), vget_high_f32(a)) # define VALIGNED(ptr) ((((uintptr_t)(ptr)) & 0x3) == 0) #else # if !defined(PFFFT_SIMD_DISABLE) # warning "building with simd disabled !\n"; # define PFFFT_SIMD_DISABLE // fallback to scalar code # endif #endif // fallback mode for situations where SSE/Altivec are not available, use scalar mode instead #ifdef PFFFT_SIMD_DISABLE typedef float v4sf; # define SIMD_SZ 1 # define VZERO() 0.f # define VMUL(a,b) ((a)*(b)) # define VADD(a,b) ((a)+(b)) # define VMADD(a,b,c) ((a)*(b)+(c)) # define VSUB(a,b) ((a)-(b)) # define LD_PS1(p) (p) # define VALIGNED(ptr) ((((uintptr_t)(ptr)) & 0x3) == 0) #endif // shortcuts for complex multiplcations #define VCPLXMUL(ar,ai,br,bi) { v4sf tmp; tmp=VMUL(ar,bi); ar=VMUL(ar,br); ar=VSUB(ar,VMUL(ai,bi)); ai=VMUL(ai,br); ai=VADD(ai,tmp); } #define VCPLXMULCONJ(ar,ai,br,bi) { v4sf tmp; tmp=VMUL(ar,bi); ar=VMUL(ar,br); ar=VADD(ar,VMUL(ai,bi)); ai=VMUL(ai,br); ai=VSUB(ai,tmp); } #ifndef SVMUL // multiply a scalar with a vector #define SVMUL(f,v) VMUL(LD_PS1(f),v) #endif #if !defined(PFFFT_SIMD_DISABLE) typedef union v4sf_union { v4sf v; float f[4]; } v4sf_union; #include #define assertv4(v,f0,f1,f2,f3) assert(v.f[0] == (f0) && v.f[1] == (f1) && v.f[2] == (f2) && v.f[3] == (f3)) /* detect bugs with the vector support macros */ void validate_pffft_simd() { float f[16] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 }; v4sf_union a0, a1, a2, a3, t, u; memcpy(a0.f, f, 4*sizeof(float)); memcpy(a1.f, f+4, 4*sizeof(float)); memcpy(a2.f, f+8, 4*sizeof(float)); memcpy(a3.f, f+12, 4*sizeof(float)); t = a0; u = a1; t.v = VZERO(); assertv4(t, 0, 0, 0, 0); t.v = VADD(a1.v, a2.v); assertv4(t, 12, 14, 16, 18); t.v = VMUL(a1.v, a2.v); assertv4(t, 32, 45, 60, 77); t.v = VMADD(a1.v, a2.v,a0.v); assertv4(t, 32, 46, 62, 80); INTERLEAVE2(a1.v,a2.v,t.v,u.v); assertv4(t, 4, 8, 5, 9); assertv4(u, 6, 10, 7, 11); UNINTERLEAVE2(a1.v,a2.v,t.v,u.v); assertv4(t, 4, 6, 8, 10); assertv4(u, 5, 7, 9, 11); t.v=LD_PS1(f[15]); assertv4(t, 15, 15, 15, 15); t.v = VSWAPHL(a1.v, a2.v); assertv4(t, 8, 9, 6, 7); VTRANSPOSE4(a0.v, a1.v, a2.v, a3.v); assertv4(a0, 0, 4, 8, 12); assertv4(a1, 1, 5, 9, 13); assertv4(a2, 2, 6, 10, 14); assertv4(a3, 3, 7, 11, 15); } #endif //!PFFFT_SIMD_DISABLE /* SSE and co like 16-bytes aligned pointers */ #define MALLOC_V4SF_ALIGNMENT 64 // with a 64-byte alignment, we are even aligned on L2 cache lines... void *pffft_aligned_malloc(size_t nb_bytes) { void *p, *p0 = malloc(nb_bytes + MALLOC_V4SF_ALIGNMENT); if (!p0) return (void *) 0; p = (void *) (((size_t) p0 + MALLOC_V4SF_ALIGNMENT) & (~((size_t) (MALLOC_V4SF_ALIGNMENT-1)))); *((void **) p - 1) = p0; return p; } void pffft_aligned_free(void *p) { if (p) free(*((void **) p - 1)); } int pffft_simd_size() { return SIMD_SZ; } /* passf2 and passb2 has been merged here, fsign = -1 for passf2, +1 for passb2 */ static NEVER_INLINE(void) passf2_ps(int ido, int l1, const v4sf *cc, v4sf *ch, const float *wa1, float fsign) { int k, i; int l1ido = l1*ido; if (ido <= 2) { for (k=0; k < l1ido; k += ido, ch += ido, cc+= 2*ido) { ch[0] = VADD(cc[0], cc[ido+0]); ch[l1ido] = VSUB(cc[0], cc[ido+0]); ch[1] = VADD(cc[1], cc[ido+1]); ch[l1ido + 1] = VSUB(cc[1], cc[ido+1]); } } else { for (k=0; k < l1ido; k += ido, ch += ido, cc += 2*ido) { for (i=0; i 2); for (k=0; k< l1ido; k += ido, cc+= 3*ido, ch +=ido) { for (i=0; i 2); for (k = 0; k < l1; ++k, cc += 5*ido, ch += ido) { for (i = 0; i < ido-1; i += 2) { ti5 = VSUB(cc_ref(i , 2), cc_ref(i , 5)); ti2 = VADD(cc_ref(i , 2), cc_ref(i , 5)); ti4 = VSUB(cc_ref(i , 3), cc_ref(i , 4)); ti3 = VADD(cc_ref(i , 3), cc_ref(i , 4)); tr5 = VSUB(cc_ref(i-1, 2), cc_ref(i-1, 5)); tr2 = VADD(cc_ref(i-1, 2), cc_ref(i-1, 5)); tr4 = VSUB(cc_ref(i-1, 3), cc_ref(i-1, 4)); tr3 = VADD(cc_ref(i-1, 3), cc_ref(i-1, 4)); ch_ref(i-1, 1) = VADD(cc_ref(i-1, 1), VADD(tr2, tr3)); ch_ref(i , 1) = VADD(cc_ref(i , 1), VADD(ti2, ti3)); cr2 = VADD(cc_ref(i-1, 1), VADD(SVMUL(tr11, tr2),SVMUL(tr12, tr3))); ci2 = VADD(cc_ref(i , 1), VADD(SVMUL(tr11, ti2),SVMUL(tr12, ti3))); cr3 = VADD(cc_ref(i-1, 1), VADD(SVMUL(tr12, tr2),SVMUL(tr11, tr3))); ci3 = VADD(cc_ref(i , 1), VADD(SVMUL(tr12, ti2),SVMUL(tr11, ti3))); cr5 = VADD(SVMUL(ti11, tr5), SVMUL(ti12, tr4)); ci5 = VADD(SVMUL(ti11, ti5), SVMUL(ti12, ti4)); cr4 = VSUB(SVMUL(ti12, tr5), SVMUL(ti11, tr4)); ci4 = VSUB(SVMUL(ti12, ti5), SVMUL(ti11, ti4)); dr3 = VSUB(cr3, ci4); dr4 = VADD(cr3, ci4); di3 = VADD(ci3, cr4); di4 = VSUB(ci3, cr4); dr5 = VADD(cr2, ci5); dr2 = VSUB(cr2, ci5); di5 = VSUB(ci2, cr5); di2 = VADD(ci2, cr5); wr1=wa1[i], wi1=fsign*wa1[i+1], wr2=wa2[i], wi2=fsign*wa2[i+1]; wr3=wa3[i], wi3=fsign*wa3[i+1], wr4=wa4[i], wi4=fsign*wa4[i+1]; VCPLXMUL(dr2, di2, LD_PS1(wr1), LD_PS1(wi1)); ch_ref(i - 1, 2) = dr2; ch_ref(i, 2) = di2; VCPLXMUL(dr3, di3, LD_PS1(wr2), LD_PS1(wi2)); ch_ref(i - 1, 3) = dr3; ch_ref(i, 3) = di3; VCPLXMUL(dr4, di4, LD_PS1(wr3), LD_PS1(wi3)); ch_ref(i - 1, 4) = dr4; ch_ref(i, 4) = di4; VCPLXMUL(dr5, di5, LD_PS1(wr4), LD_PS1(wi4)); ch_ref(i - 1, 5) = dr5; ch_ref(i, 5) = di5; } } #undef ch_ref #undef cc_ref } static NEVER_INLINE(void) radf2_ps(int ido, int l1, const v4sf * RESTRICT cc, v4sf * RESTRICT ch, const float *wa1) { static const float minus_one = -1.f; int i, k, l1ido = l1*ido; for (k=0; k < l1ido; k += ido) { v4sf a = cc[k], b = cc[k + l1ido]; ch[2*k] = VADD(a, b); ch[2*(k+ido)-1] = VSUB(a, b); } if (ido < 2) return; if (ido != 2) { for (k=0; k < l1ido; k += ido) { for (i=2; i 5) { wa[i1-1] = wa[i-1]; wa[i1] = wa[i]; } } l1 = l2; } } /* cffti1 */ v4sf *cfftf1_ps(int n, const v4sf *input_readonly, v4sf *work1, v4sf *work2, const float *wa, const int *ifac, int isign) { v4sf *in = (v4sf*)input_readonly; v4sf *out = (in == work2 ? work1 : work2); int nf = ifac[1], k1; int l1 = 1; int iw = 0; assert(in != out && work1 != work2); for (k1=2; k1<=nf+1; k1++) { int ip = ifac[k1]; int l2 = ip*l1; int ido = n / l2; int idot = ido + ido; switch (ip) { case 5: { int ix2 = iw + idot; int ix3 = ix2 + idot; int ix4 = ix3 + idot; passf5_ps(idot, l1, in, out, &wa[iw], &wa[ix2], &wa[ix3], &wa[ix4], isign); } break; case 4: { int ix2 = iw + idot; int ix3 = ix2 + idot; passf4_ps(idot, l1, in, out, &wa[iw], &wa[ix2], &wa[ix3], isign); } break; case 2: { passf2_ps(idot, l1, in, out, &wa[iw], isign); } break; case 3: { int ix2 = iw + idot; passf3_ps(idot, l1, in, out, &wa[iw], &wa[ix2], isign); } break; default: assert(0); } l1 = l2; iw += (ip - 1)*idot; if (out == work2) { out = work1; in = work2; } else { out = work2; in = work1; } } return in; /* this is in fact the output .. */ } struct PFFFT_Setup { int N; int Ncvec; // nb of complex simd vectors (N/4 if PFFFT_COMPLEX, N/8 if PFFFT_REAL) int ifac[15]; pffft_transform_t transform; v4sf *data; // allocated room for twiddle coefs float *e; // points into 'data' , N/4*3 elements float *twiddle; // points into 'data', N/4 elements }; PFFFT_Setup *pffft_new_setup(int N, pffft_transform_t transform) { PFFFT_Setup *s = (PFFFT_Setup*)malloc(sizeof(PFFFT_Setup)); int k, m; /* unfortunately, the fft size must be a multiple of 16 for complex FFTs and 32 for real FFTs -- a lot of stuff would need to be rewritten to handle other cases (or maybe just switch to a scalar fft, I don't know..) */ if (transform == PFFFT_REAL) { assert((N%(2*SIMD_SZ*SIMD_SZ))==0 && N>0); } if (transform == PFFFT_COMPLEX) { assert((N%(SIMD_SZ*SIMD_SZ))==0 && N>0); } //assert((N % 32) == 0); s->N = N; s->transform = transform; /* nb of complex simd vectors */ s->Ncvec = (transform == PFFFT_REAL ? N/2 : N)/SIMD_SZ; s->data = (v4sf*)pffft_aligned_malloc(2*s->Ncvec * sizeof(v4sf)); s->e = (float*)s->data; s->twiddle = (float*)(s->data + (2*s->Ncvec*(SIMD_SZ-1))/SIMD_SZ); if (transform == PFFFT_REAL) { for (k=0; k < s->Ncvec; ++k) { int i = k/SIMD_SZ; int j = k%SIMD_SZ; for (m=0; m < SIMD_SZ-1; ++m) { float A = -2*M_PI*(m+1)*k / N; s->e[(2*(i*3 + m) + 0) * SIMD_SZ + j] = cos(A); s->e[(2*(i*3 + m) + 1) * SIMD_SZ + j] = sin(A); } } rffti1_ps(N/SIMD_SZ, s->twiddle, s->ifac); } else { for (k=0; k < s->Ncvec; ++k) { int i = k/SIMD_SZ; int j = k%SIMD_SZ; for (m=0; m < SIMD_SZ-1; ++m) { float A = -2*M_PI*(m+1)*k / N; s->e[(2*(i*3 + m) + 0)*SIMD_SZ + j] = cos(A); s->e[(2*(i*3 + m) + 1)*SIMD_SZ + j] = sin(A); } } cffti1_ps(N/SIMD_SZ, s->twiddle, s->ifac); } /* check that N is decomposable with allowed prime factors */ for (k=0, m=1; k < s->ifac[1]; ++k) { m *= s->ifac[2+k]; } if (m != N/SIMD_SZ) { pffft_destroy_setup(s); s = 0; } return s; } void pffft_destroy_setup(PFFFT_Setup *s) { pffft_aligned_free(s->data); free(s); } #if !defined(PFFFT_SIMD_DISABLE) /* [0 0 1 2 3 4 5 6 7 8] -> [0 8 7 6 5 4 3 2 1] */ static void reversed_copy(int N, const v4sf *in, int in_stride, v4sf *out) { v4sf g0, g1; int k; INTERLEAVE2(in[0], in[1], g0, g1); in += in_stride; *--out = VSWAPHL(g0, g1); // [g0l, g0h], [g1l g1h] -> [g1l, g0h] for (k=1; k < N; ++k) { v4sf h0, h1; INTERLEAVE2(in[0], in[1], h0, h1); in += in_stride; *--out = VSWAPHL(g1, h0); *--out = VSWAPHL(h0, h1); g1 = h1; } *--out = VSWAPHL(g1, g0); } static void unreversed_copy(int N, const v4sf *in, v4sf *out, int out_stride) { v4sf g0, g1, h0, h1; int k; g0 = g1 = in[0]; ++in; for (k=1; k < N; ++k) { h0 = *in++; h1 = *in++; g1 = VSWAPHL(g1, h0); h0 = VSWAPHL(h0, h1); UNINTERLEAVE2(h0, g1, out[0], out[1]); out += out_stride; g1 = h1; } h0 = *in++; h1 = g0; g1 = VSWAPHL(g1, h0); h0 = VSWAPHL(h0, h1); UNINTERLEAVE2(h0, g1, out[0], out[1]); } void pffft_zreorder(PFFFT_Setup *setup, const float *in, float *out, pffft_direction_t direction) { int k, N = setup->N, Ncvec = setup->Ncvec; const v4sf *vin = (const v4sf*)in; v4sf *vout = (v4sf*)out; assert(in != out); if (setup->transform == PFFFT_REAL) { int k, dk = N/32; if (direction == PFFFT_FORWARD) { for (k=0; k < dk; ++k) { INTERLEAVE2(vin[k*8 + 0], vin[k*8 + 1], vout[2*(0*dk + k) + 0], vout[2*(0*dk + k) + 1]); INTERLEAVE2(vin[k*8 + 4], vin[k*8 + 5], vout[2*(2*dk + k) + 0], vout[2*(2*dk + k) + 1]); } reversed_copy(dk, vin+2, 8, (v4sf*)(out + N/2)); reversed_copy(dk, vin+6, 8, (v4sf*)(out + N)); } else { for (k=0; k < dk; ++k) { UNINTERLEAVE2(vin[2*(0*dk + k) + 0], vin[2*(0*dk + k) + 1], vout[k*8 + 0], vout[k*8 + 1]); UNINTERLEAVE2(vin[2*(2*dk + k) + 0], vin[2*(2*dk + k) + 1], vout[k*8 + 4], vout[k*8 + 5]); } unreversed_copy(dk, (v4sf*)(in + N/4), (v4sf*)(out + N - 6*SIMD_SZ), -8); unreversed_copy(dk, (v4sf*)(in + 3*N/4), (v4sf*)(out + N - 2*SIMD_SZ), -8); } } else { if (direction == PFFFT_FORWARD) { for (k=0; k < Ncvec; ++k) { int kk = (k/4) + (k%4)*(Ncvec/4); INTERLEAVE2(vin[k*2], vin[k*2+1], vout[kk*2], vout[kk*2+1]); } } else { for (k=0; k < Ncvec; ++k) { int kk = (k/4) + (k%4)*(Ncvec/4); UNINTERLEAVE2(vin[kk*2], vin[kk*2+1], vout[k*2], vout[k*2+1]); } } } } void pffft_cplx_finalize(int Ncvec, const v4sf *in, v4sf *out, const v4sf *e) { int k, dk = Ncvec/SIMD_SZ; // number of 4x4 matrix blocks v4sf r0, i0, r1, i1, r2, i2, r3, i3; v4sf sr0, dr0, sr1, dr1, si0, di0, si1, di1; assert(in != out); for (k=0; k < dk; ++k) { r0 = in[8*k+0]; i0 = in[8*k+1]; r1 = in[8*k+2]; i1 = in[8*k+3]; r2 = in[8*k+4]; i2 = in[8*k+5]; r3 = in[8*k+6]; i3 = in[8*k+7]; VTRANSPOSE4(r0,r1,r2,r3); VTRANSPOSE4(i0,i1,i2,i3); VCPLXMUL(r1,i1,e[k*6+0],e[k*6+1]); VCPLXMUL(r2,i2,e[k*6+2],e[k*6+3]); VCPLXMUL(r3,i3,e[k*6+4],e[k*6+5]); sr0 = VADD(r0,r2); dr0 = VSUB(r0, r2); sr1 = VADD(r1,r3); dr1 = VSUB(r1, r3); si0 = VADD(i0,i2); di0 = VSUB(i0, i2); si1 = VADD(i1,i3); di1 = VSUB(i1, i3); /* transformation for each column is: [1 1 1 1 0 0 0 0] [r0] [1 0 -1 0 0 -1 0 1] [r1] [1 -1 1 -1 0 0 0 0] [r2] [1 0 -1 0 0 1 0 -1] [r3] [0 0 0 0 1 1 1 1] * [i0] [0 1 0 -1 1 0 -1 0] [i1] [0 0 0 0 1 -1 1 -1] [i2] [0 -1 0 1 1 0 -1 0] [i3] */ r0 = VADD(sr0, sr1); i0 = VADD(si0, si1); r1 = VADD(dr0, di1); i1 = VSUB(di0, dr1); r2 = VSUB(sr0, sr1); i2 = VSUB(si0, si1); r3 = VSUB(dr0, di1); i3 = VADD(di0, dr1); *out++ = r0; *out++ = i0; *out++ = r1; *out++ = i1; *out++ = r2; *out++ = i2; *out++ = r3; *out++ = i3; } } void pffft_cplx_preprocess(int Ncvec, const v4sf *in, v4sf *out, const v4sf *e) { int k, dk = Ncvec/SIMD_SZ; // number of 4x4 matrix blocks v4sf r0, i0, r1, i1, r2, i2, r3, i3; v4sf sr0, dr0, sr1, dr1, si0, di0, si1, di1; assert(in != out); for (k=0; k < dk; ++k) { r0 = in[8*k+0]; i0 = in[8*k+1]; r1 = in[8*k+2]; i1 = in[8*k+3]; r2 = in[8*k+4]; i2 = in[8*k+5]; r3 = in[8*k+6]; i3 = in[8*k+7]; sr0 = VADD(r0,r2); dr0 = VSUB(r0, r2); sr1 = VADD(r1,r3); dr1 = VSUB(r1, r3); si0 = VADD(i0,i2); di0 = VSUB(i0, i2); si1 = VADD(i1,i3); di1 = VSUB(i1, i3); r0 = VADD(sr0, sr1); i0 = VADD(si0, si1); r1 = VSUB(dr0, di1); i1 = VADD(di0, dr1); r2 = VSUB(sr0, sr1); i2 = VSUB(si0, si1); r3 = VADD(dr0, di1); i3 = VSUB(di0, dr1); VCPLXMULCONJ(r1,i1,e[k*6+0],e[k*6+1]); VCPLXMULCONJ(r2,i2,e[k*6+2],e[k*6+3]); VCPLXMULCONJ(r3,i3,e[k*6+4],e[k*6+5]); VTRANSPOSE4(r0,r1,r2,r3); VTRANSPOSE4(i0,i1,i2,i3); *out++ = r0; *out++ = i0; *out++ = r1; *out++ = i1; *out++ = r2; *out++ = i2; *out++ = r3; *out++ = i3; } } static ALWAYS_INLINE(void) pffft_real_finalize_4x4(const v4sf *in0, const v4sf *in1, const v4sf *in, const v4sf *e, v4sf *out) { v4sf r0, i0, r1, i1, r2, i2, r3, i3; v4sf sr0, dr0, sr1, dr1, si0, di0, si1, di1; r0 = *in0; i0 = *in1; r1 = *in++; i1 = *in++; r2 = *in++; i2 = *in++; r3 = *in++; i3 = *in++; VTRANSPOSE4(r0,r1,r2,r3); VTRANSPOSE4(i0,i1,i2,i3); /* transformation for each column is: [1 1 1 1 0 0 0 0] [r0] [1 0 -1 0 0 -1 0 1] [r1] [1 0 -1 0 0 1 0 -1] [r2] [1 -1 1 -1 0 0 0 0] [r3] [0 0 0 0 1 1 1 1] * [i0] [0 -1 0 1 -1 0 1 0] [i1] [0 -1 0 1 1 0 -1 0] [i2] [0 0 0 0 -1 1 -1 1] [i3] */ //cerr << "matrix initial, before e , REAL:\n 1: " << r0 << "\n 1: " << r1 << "\n 1: " << r2 << "\n 1: " << r3 << "\n"; //cerr << "matrix initial, before e, IMAG :\n 1: " << i0 << "\n 1: " << i1 << "\n 1: " << i2 << "\n 1: " << i3 << "\n"; VCPLXMUL(r1,i1,e[0],e[1]); VCPLXMUL(r2,i2,e[2],e[3]); VCPLXMUL(r3,i3,e[4],e[5]); //cerr << "matrix initial, real part:\n 1: " << r0 << "\n 1: " << r1 << "\n 1: " << r2 << "\n 1: " << r3 << "\n"; //cerr << "matrix initial, imag part:\n 1: " << i0 << "\n 1: " << i1 << "\n 1: " << i2 << "\n 1: " << i3 << "\n"; sr0 = VADD(r0,r2); dr0 = VSUB(r0,r2); sr1 = VADD(r1,r3); dr1 = VSUB(r3,r1); si0 = VADD(i0,i2); di0 = VSUB(i0,i2); si1 = VADD(i1,i3); di1 = VSUB(i3,i1); r0 = VADD(sr0, sr1); r3 = VSUB(sr0, sr1); i0 = VADD(si0, si1); i3 = VSUB(si1, si0); r1 = VADD(dr0, di1); r2 = VSUB(dr0, di1); i1 = VSUB(dr1, di0); i2 = VADD(dr1, di0); *out++ = r0; *out++ = i0; *out++ = r1; *out++ = i1; *out++ = r2; *out++ = i2; *out++ = r3; *out++ = i3; } static NEVER_INLINE(void) pffft_real_finalize(int Ncvec, const v4sf *in, v4sf *out, const v4sf *e) { int k, dk = Ncvec/SIMD_SZ; // number of 4x4 matrix blocks /* fftpack order is f0r f1r f1i f2r f2i ... f(n-1)r f(n-1)i f(n)r */ v4sf_union cr, ci, *uout = (v4sf_union*)out; v4sf save = in[7], zero=VZERO(); float xr0, xi0, xr1, xi1, xr2, xi2, xr3, xi3; static const float s = M_SQRT2/2; cr.v = in[0]; ci.v = in[Ncvec*2-1]; assert(in != out); pffft_real_finalize_4x4(&zero, &zero, in+1, e, out); /* [cr0 cr1 cr2 cr3 ci0 ci1 ci2 ci3] [Xr(1)] ] [1 1 1 1 0 0 0 0] [Xr(N/4) ] [0 0 0 0 1 s 0 -s] [Xr(N/2) ] [1 0 -1 0 0 0 0 0] [Xr(3N/4)] [0 0 0 0 1 -s 0 s] [Xi(1) ] [1 -1 1 -1 0 0 0 0] [Xi(N/4) ] [0 0 0 0 0 -s -1 -s] [Xi(N/2) ] [0 -1 0 1 0 0 0 0] [Xi(3N/4)] [0 0 0 0 0 -s 1 -s] */ xr0=(cr.f[0]+cr.f[2]) + (cr.f[1]+cr.f[3]); uout[0].f[0] = xr0; xi0=(cr.f[0]+cr.f[2]) - (cr.f[1]+cr.f[3]); uout[1].f[0] = xi0; xr2=(cr.f[0]-cr.f[2]); uout[4].f[0] = xr2; xi2=(cr.f[3]-cr.f[1]); uout[5].f[0] = xi2; xr1= ci.f[0] + s*(ci.f[1]-ci.f[3]); uout[2].f[0] = xr1; xi1=-ci.f[2] - s*(ci.f[1]+ci.f[3]); uout[3].f[0] = xi1; xr3= ci.f[0] - s*(ci.f[1]-ci.f[3]); uout[6].f[0] = xr3; xi3= ci.f[2] - s*(ci.f[1]+ci.f[3]); uout[7].f[0] = xi3; for (k=1; k < dk; ++k) { v4sf save_next = in[8*k+7]; pffft_real_finalize_4x4(&save, &in[8*k+0], in + 8*k+1, e + k*6, out + k*8); save = save_next; } } static ALWAYS_INLINE(void) pffft_real_preprocess_4x4(const v4sf *in, const v4sf *e, v4sf *out, int first) { v4sf r0=in[0], i0=in[1], r1=in[2], i1=in[3], r2=in[4], i2=in[5], r3=in[6], i3=in[7]; /* transformation for each column is: [1 1 1 1 0 0 0 0] [r0] [1 0 0 -1 0 -1 -1 0] [r1] [1 -1 -1 1 0 0 0 0] [r2] [1 0 0 -1 0 1 1 0] [r3] [0 0 0 0 1 -1 1 -1] * [i0] [0 -1 1 0 1 0 0 1] [i1] [0 0 0 0 1 1 -1 -1] [i2] [0 1 -1 0 1 0 0 1] [i3] */ v4sf sr0 = VADD(r0,r3), dr0 = VSUB(r0,r3); v4sf sr1 = VADD(r1,r2), dr1 = VSUB(r1,r2); v4sf si0 = VADD(i0,i3), di0 = VSUB(i0,i3); v4sf si1 = VADD(i1,i2), di1 = VSUB(i1,i2); r0 = VADD(sr0, sr1); r2 = VSUB(sr0, sr1); r1 = VSUB(dr0, si1); r3 = VADD(dr0, si1); i0 = VSUB(di0, di1); i2 = VADD(di0, di1); i1 = VSUB(si0, dr1); i3 = VADD(si0, dr1); VCPLXMULCONJ(r1,i1,e[0],e[1]); VCPLXMULCONJ(r2,i2,e[2],e[3]); VCPLXMULCONJ(r3,i3,e[4],e[5]); VTRANSPOSE4(r0,r1,r2,r3); VTRANSPOSE4(i0,i1,i2,i3); if (!first) { *out++ = r0; *out++ = i0; } *out++ = r1; *out++ = i1; *out++ = r2; *out++ = i2; *out++ = r3; *out++ = i3; } static NEVER_INLINE(void) pffft_real_preprocess(int Ncvec, const v4sf *in, v4sf *out, const v4sf *e) { int k, dk = Ncvec/SIMD_SZ; // number of 4x4 matrix blocks /* fftpack order is f0r f1r f1i f2r f2i ... f(n-1)r f(n-1)i f(n)r */ v4sf_union Xr, Xi, *uout = (v4sf_union*)out; float cr0, ci0, cr1, ci1, cr2, ci2, cr3, ci3; static const float s = M_SQRT2; assert(in != out); for (k=0; k < 4; ++k) { Xr.f[k] = ((float*)in)[8*k]; Xi.f[k] = ((float*)in)[8*k+4]; } pffft_real_preprocess_4x4(in, e, out+1, 1); // will write only 6 values /* [Xr0 Xr1 Xr2 Xr3 Xi0 Xi1 Xi2 Xi3] [cr0] [1 0 2 0 1 0 0 0] [cr1] [1 0 0 0 -1 0 -2 0] [cr2] [1 0 -2 0 1 0 0 0] [cr3] [1 0 0 0 -1 0 2 0] [ci0] [0 2 0 2 0 0 0 0] [ci1] [0 s 0 -s 0 -s 0 -s] [ci2] [0 0 0 0 0 -2 0 2] [ci3] [0 -s 0 s 0 -s 0 -s] */ for (k=1; k < dk; ++k) { pffft_real_preprocess_4x4(in+8*k, e + k*6, out-1+k*8, 0); } cr0=(Xr.f[0]+Xi.f[0]) + 2*Xr.f[2]; uout[0].f[0] = cr0; cr1=(Xr.f[0]-Xi.f[0]) - 2*Xi.f[2]; uout[0].f[1] = cr1; cr2=(Xr.f[0]+Xi.f[0]) - 2*Xr.f[2]; uout[0].f[2] = cr2; cr3=(Xr.f[0]-Xi.f[0]) + 2*Xi.f[2]; uout[0].f[3] = cr3; ci0= 2*(Xr.f[1]+Xr.f[3]); uout[2*Ncvec-1].f[0] = ci0; ci1= s*(Xr.f[1]-Xr.f[3]) - s*(Xi.f[1]+Xi.f[3]); uout[2*Ncvec-1].f[1] = ci1; ci2= 2*(Xi.f[3]-Xi.f[1]); uout[2*Ncvec-1].f[2] = ci2; ci3=-s*(Xr.f[1]-Xr.f[3]) - s*(Xi.f[1]+Xi.f[3]); uout[2*Ncvec-1].f[3] = ci3; } void pffft_transform_internal(PFFFT_Setup *setup, const float *finput, float *foutput, v4sf *scratch, pffft_direction_t direction, int ordered) { int k, Ncvec = setup->Ncvec; int nf_odd = (setup->ifac[1] & 1); // temporary buffer is allocated on the stack if the scratch pointer is NULL int stack_allocate = (scratch == 0 ? Ncvec*2 : 1); VLA_ARRAY_ON_STACK(v4sf, scratch_on_stack, stack_allocate); const v4sf *vinput = (const v4sf*)finput; v4sf *voutput = (v4sf*)foutput; v4sf *buff[2] = { voutput, scratch ? scratch : scratch_on_stack }; int ib = (nf_odd ^ ordered ? 1 : 0); assert(VALIGNED(finput) && VALIGNED(foutput)); //assert(finput != foutput); if (direction == PFFFT_FORWARD) { ib = !ib; if (setup->transform == PFFFT_REAL) { ib = (rfftf1_ps(Ncvec*2, vinput, buff[ib], buff[!ib], setup->twiddle, &setup->ifac[0]) == buff[0] ? 0 : 1); pffft_real_finalize(Ncvec, buff[ib], buff[!ib], (v4sf*)setup->e); } else { v4sf *tmp = buff[ib]; for (k=0; k < Ncvec; ++k) { UNINTERLEAVE2(vinput[k*2], vinput[k*2+1], tmp[k*2], tmp[k*2+1]); } ib = (cfftf1_ps(Ncvec, buff[ib], buff[!ib], buff[ib], setup->twiddle, &setup->ifac[0], -1) == buff[0] ? 0 : 1); pffft_cplx_finalize(Ncvec, buff[ib], buff[!ib], (v4sf*)setup->e); } if (ordered) { pffft_zreorder(setup, (float*)buff[!ib], (float*)buff[ib], PFFFT_FORWARD); } else ib = !ib; } else { if (vinput == buff[ib]) { ib = !ib; // may happen when finput == foutput } if (ordered) { pffft_zreorder(setup, (float*)vinput, (float*)buff[ib], PFFFT_BACKWARD); vinput = buff[ib]; ib = !ib; } if (setup->transform == PFFFT_REAL) { pffft_real_preprocess(Ncvec, vinput, buff[ib], (v4sf*)setup->e); ib = (rfftb1_ps(Ncvec*2, buff[ib], buff[0], buff[1], setup->twiddle, &setup->ifac[0]) == buff[0] ? 0 : 1); } else { pffft_cplx_preprocess(Ncvec, vinput, buff[ib], (v4sf*)setup->e); ib = (cfftf1_ps(Ncvec, buff[ib], buff[0], buff[1], setup->twiddle, &setup->ifac[0], +1) == buff[0] ? 0 : 1); for (k=0; k < Ncvec; ++k) { INTERLEAVE2(buff[ib][k*2], buff[ib][k*2+1], buff[ib][k*2], buff[ib][k*2+1]); } } } if (buff[ib] != voutput) { /* extra copy required -- this situation should only happen when finput == foutput */ assert(finput==foutput); for (k=0; k < Ncvec; ++k) { v4sf a = buff[ib][2*k], b = buff[ib][2*k+1]; voutput[2*k] = a; voutput[2*k+1] = b; } ib = !ib; } assert(buff[ib] == voutput); VLA_ARRAY_ON_STACK_FREE(scratch_on_stack); } void pffft_zconvolve_accumulate(PFFFT_Setup *s, const float *a, const float *b, float *ab, float scaling) { int Ncvec = s->Ncvec; const v4sf * RESTRICT va = (const v4sf*)a; const v4sf * RESTRICT vb = (const v4sf*)b; v4sf * RESTRICT vab = (v4sf*)ab; #ifdef __arm__ __builtin_prefetch(va); __builtin_prefetch(vb); __builtin_prefetch(vab); __builtin_prefetch(va+2); __builtin_prefetch(vb+2); __builtin_prefetch(vab+2); __builtin_prefetch(va+4); __builtin_prefetch(vb+4); __builtin_prefetch(vab+4); __builtin_prefetch(va+6); __builtin_prefetch(vb+6); __builtin_prefetch(vab+6); # ifndef __clang__ # define ZCONVOLVE_USING_INLINE_NEON_ASM # endif #endif float ar, ai, br, bi, abr, abi; #ifndef ZCONVOLVE_USING_INLINE_ASM v4sf vscal = LD_PS1(scaling); int i; #endif assert(VALIGNED(a) && VALIGNED(b) && VALIGNED(ab)); ar = ((v4sf_union*)va)[0].f[0]; ai = ((v4sf_union*)va)[1].f[0]; br = ((v4sf_union*)vb)[0].f[0]; bi = ((v4sf_union*)vb)[1].f[0]; abr = ((v4sf_union*)vab)[0].f[0]; abi = ((v4sf_union*)vab)[1].f[0]; #ifdef ZCONVOLVE_USING_INLINE_ASM // inline asm version, unfortunately miscompiled by clang 3.2, at least on ubuntu.. so this will be restricted to gcc const float *a_ = a, *b_ = b; float *ab_ = ab; int N = Ncvec; asm volatile("mov r8, %2 \n" "vdup.f32 q15, %4 \n" "1: \n" "pld [%0,#64] \n" "pld [%1,#64] \n" "pld [%2,#64] \n" "pld [%0,#96] \n" "pld [%1,#96] \n" "pld [%2,#96] \n" "vld1.f32 {q0,q1}, [%0,:128]! \n" "vld1.f32 {q4,q5}, [%1,:128]! \n" "vld1.f32 {q2,q3}, [%0,:128]! \n" "vld1.f32 {q6,q7}, [%1,:128]! \n" "vld1.f32 {q8,q9}, [r8,:128]! \n" "vmul.f32 q10, q0, q4 \n" "vmul.f32 q11, q0, q5 \n" "vmul.f32 q12, q2, q6 \n" "vmul.f32 q13, q2, q7 \n" "vmls.f32 q10, q1, q5 \n" "vmla.f32 q11, q1, q4 \n" "vld1.f32 {q0,q1}, [r8,:128]! \n" "vmls.f32 q12, q3, q7 \n" "vmla.f32 q13, q3, q6 \n" "vmla.f32 q8, q10, q15 \n" "vmla.f32 q9, q11, q15 \n" "vmla.f32 q0, q12, q15 \n" "vmla.f32 q1, q13, q15 \n" "vst1.f32 {q8,q9},[%2,:128]! \n" "vst1.f32 {q0,q1},[%2,:128]! \n" "subs %3, #2 \n" "bne 1b \n" : "+r"(a_), "+r"(b_), "+r"(ab_), "+r"(N) : "r"(scaling) : "r8", "q0","q1","q2","q3","q4","q5","q6","q7","q8","q9", "q10","q11","q12","q13","q15","memory"); #else // default routine, works fine for non-arm cpus with current compilers for (i=0; i < Ncvec; i += 2) { v4sf ar, ai, br, bi; ar = va[2*i+0]; ai = va[2*i+1]; br = vb[2*i+0]; bi = vb[2*i+1]; VCPLXMUL(ar, ai, br, bi); vab[2*i+0] = VMADD(ar, vscal, vab[2*i+0]); vab[2*i+1] = VMADD(ai, vscal, vab[2*i+1]); ar = va[2*i+2]; ai = va[2*i+3]; br = vb[2*i+2]; bi = vb[2*i+3]; VCPLXMUL(ar, ai, br, bi); vab[2*i+2] = VMADD(ar, vscal, vab[2*i+2]); vab[2*i+3] = VMADD(ai, vscal, vab[2*i+3]); } #endif if (s->transform == PFFFT_REAL) { ((v4sf_union*)vab)[0].f[0] = abr + ar*br*scaling; ((v4sf_union*)vab)[1].f[0] = abi + ai*bi*scaling; } } #else // defined(PFFFT_SIMD_DISABLE) // standard routine using scalar floats, without SIMD stuff. #define pffft_zreorder_nosimd pffft_zreorder void pffft_zreorder_nosimd(PFFFT_Setup *setup, const float *in, float *out, pffft_direction_t direction) { int k, N = setup->N; if (setup->transform == PFFFT_COMPLEX) { for (k=0; k < 2*N; ++k) out[k] = in[k]; return; } else if (direction == PFFFT_FORWARD) { float x_N = in[N-1]; for (k=N-1; k > 1; --k) out[k] = in[k-1]; out[0] = in[0]; out[1] = x_N; } else { float x_N = in[1]; for (k=1; k < N-1; ++k) out[k] = in[k+1]; out[0] = in[0]; out[N-1] = x_N; } } #define pffft_transform_internal_nosimd pffft_transform_internal void pffft_transform_internal_nosimd(PFFFT_Setup *setup, const float *input, float *output, float *scratch, pffft_direction_t direction, int ordered) { int Ncvec = setup->Ncvec; int nf_odd = (setup->ifac[1] & 1); // temporary buffer is allocated on the stack if the scratch pointer is NULL int stack_allocate = (scratch == 0 ? Ncvec*2 : 1); VLA_ARRAY_ON_STACK(v4sf, scratch_on_stack, stack_allocate); float *buff[2]; int ib; if (scratch == 0) scratch = scratch_on_stack; buff[0] = output; buff[1] = scratch; if (setup->transform == PFFFT_COMPLEX) ordered = 0; // it is always ordered. ib = (nf_odd ^ ordered ? 1 : 0); if (direction == PFFFT_FORWARD) { if (setup->transform == PFFFT_REAL) { ib = (rfftf1_ps(Ncvec*2, input, buff[ib], buff[!ib], setup->twiddle, &setup->ifac[0]) == buff[0] ? 0 : 1); } else { ib = (cfftf1_ps(Ncvec, input, buff[ib], buff[!ib], setup->twiddle, &setup->ifac[0], -1) == buff[0] ? 0 : 1); } if (ordered) { pffft_zreorder(setup, buff[ib], buff[!ib], PFFFT_FORWARD); ib = !ib; } } else { if (input == buff[ib]) { ib = !ib; // may happen when finput == foutput } if (ordered) { pffft_zreorder(setup, input, buff[!ib], PFFFT_BACKWARD); input = buff[!ib]; } if (setup->transform == PFFFT_REAL) { ib = (rfftb1_ps(Ncvec*2, input, buff[ib], buff[!ib], setup->twiddle, &setup->ifac[0]) == buff[0] ? 0 : 1); } else { ib = (cfftf1_ps(Ncvec, input, buff[ib], buff[!ib], setup->twiddle, &setup->ifac[0], +1) == buff[0] ? 0 : 1); } } if (buff[ib] != output) { int k; // extra copy required -- this situation should happens only when finput == foutput assert(input==output); for (k=0; k < Ncvec; ++k) { float a = buff[ib][2*k], b = buff[ib][2*k+1]; output[2*k] = a; output[2*k+1] = b; } ib = !ib; } assert(buff[ib] == output); VLA_ARRAY_ON_STACK_FREE(scratch_on_stack); } #define pffft_zconvolve_accumulate_nosimd pffft_zconvolve_accumulate void pffft_zconvolve_accumulate_nosimd(PFFFT_Setup *s, const float *a, const float *b, float *ab, float scaling) { int i, Ncvec = s->Ncvec; if (s->transform == PFFFT_REAL) { // take care of the fftpack ordering ab[0] += a[0]*b[0]*scaling; ab[2*Ncvec-1] += a[2*Ncvec-1]*b[2*Ncvec-1]*scaling; ++ab; ++a; ++b; --Ncvec; } for (i=0; i < Ncvec; ++i) { float ar, ai, br, bi; ar = a[2*i+0]; ai = a[2*i+1]; br = b[2*i+0]; bi = b[2*i+1]; VCPLXMUL(ar, ai, br, bi); ab[2*i+0] += ar*scaling; ab[2*i+1] += ai*scaling; } } #endif // defined(PFFFT_SIMD_DISABLE) void pffft_transform(PFFFT_Setup *setup, const float *input, float *output, float *work, pffft_direction_t direction) { pffft_transform_internal(setup, input, output, (v4sf*)work, direction, 0); } void pffft_transform_ordered(PFFFT_Setup *setup, const float *input, float *output, float *work, pffft_direction_t direction) { pffft_transform_internal(setup, input, output, (v4sf*)work, direction, 1); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/third_party/pffft/src/pffft.h0000664000175000017500000001573614475643423023673 0ustar00arunarun/* Copyright (c) 2013 Julien Pommier ( pommier@modartt.com ) Based on original fortran 77 code from FFTPACKv4 from NETLIB, authored by Dr Paul Swarztrauber of NCAR, in 1985. As confirmed by the NCAR fftpack software curators, the following FFTPACKv5 license applies to FFTPACKv4 sources. My changes are released under the same terms. FFTPACK license: http://www.cisl.ucar.edu/css/software/fftpack5/ftpk.html Copyright (c) 2004 the University Corporation for Atmospheric Research ("UCAR"). All rights reserved. Developed by NCAR's Computational and Information Systems Laboratory, UCAR, www.cisl.ucar.edu. Redistribution and use of the Software in source and binary forms, with or without modification, is permitted provided that the following conditions are met: - Neither the names of NCAR's Computational and Information Systems Laboratory, the University Corporation for Atmospheric Research, nor the names of its sponsors or contributors may be used to endorse or promote products derived from this Software without specific prior written permission. - Redistributions of source code must retain the above copyright notices, this list of conditions, and the disclaimer below. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the disclaimer below in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. */ /* PFFFT : a Pretty Fast FFT. This is basically an adaptation of the single precision fftpack (v4) as found on netlib taking advantage of SIMD instruction found on cpus such as intel x86 (SSE1), powerpc (Altivec), and arm (NEON). For architectures where no SIMD instruction is available, the code falls back to a scalar version. Restrictions: - 1D transforms only, with 32-bit single precision. - supports only transforms for inputs of length N of the form N=(2^a)*(3^b)*(5^c), a >= 5, b >=0, c >= 0 (32, 48, 64, 96, 128, 144, 160, etc are all acceptable lengths). Performance is best for 128<=N<=8192. - all (float*) pointers in the functions below are expected to have an "simd-compatible" alignment, that is 16 bytes on x86 and powerpc CPUs. You can allocate such buffers with the functions pffft_aligned_malloc / pffft_aligned_free (or with stuff like posix_memalign..) */ #ifndef PFFFT_H #define PFFFT_H #include // for size_t #ifdef __cplusplus extern "C" { #endif #ifndef PFFFT_SIMD_DISABLE // Detects compiler bugs with respect to simd instruction. void validate_pffft_simd(); #endif /* opaque struct holding internal stuff (precomputed twiddle factors) this struct can be shared by many threads as it contains only read-only data. */ typedef struct PFFFT_Setup PFFFT_Setup; /* direction of the transform */ typedef enum { PFFFT_FORWARD, PFFFT_BACKWARD } pffft_direction_t; /* type of transform */ typedef enum { PFFFT_REAL, PFFFT_COMPLEX } pffft_transform_t; /* prepare for performing transforms of size N -- the returned PFFFT_Setup structure is read-only so it can safely be shared by multiple concurrent threads. */ PFFFT_Setup* pffft_new_setup(int N, pffft_transform_t transform); void pffft_destroy_setup(PFFFT_Setup*); /* Perform a Fourier transform , The z-domain data is stored in the most efficient order for transforming it back, or using it for convolution. If you need to have its content sorted in the "usual" way, that is as an array of interleaved complex numbers, either use pffft_transform_ordered , or call pffft_zreorder after the forward fft, and before the backward fft. Transforms are not scaled: PFFFT_BACKWARD(PFFFT_FORWARD(x)) = N*x. Typically you will want to scale the backward transform by 1/N. The 'work' pointer should point to an area of N (2*N for complex fft) floats, properly aligned. If 'work' is NULL, then stack will be used instead (this is probably the best strategy for small FFTs, say for N < 16384). input and output may alias. */ void pffft_transform(PFFFT_Setup* setup, const float* input, float* output, float* work, pffft_direction_t direction); /* Similar to pffft_transform, but makes sure that the output is ordered as expected (interleaved complex numbers). This is similar to calling pffft_transform and then pffft_zreorder. input and output may alias. */ void pffft_transform_ordered(PFFFT_Setup* setup, const float* input, float* output, float* work, pffft_direction_t direction); /* call pffft_zreorder(.., PFFFT_FORWARD) after pffft_transform(..., PFFFT_FORWARD) if you want to have the frequency components in the correct "canonical" order, as interleaved complex numbers. (for real transforms, both 0-frequency and half frequency components, which are real, are assembled in the first entry as F(0)+i*F(n/2+1). Note that the original fftpack did place F(n/2+1) at the end of the arrays). input and output should not alias. */ void pffft_zreorder(PFFFT_Setup* setup, const float* input, float* output, pffft_direction_t direction); /* Perform a multiplication of the frequency components of dft_a and dft_b and accumulate them into dft_ab. The arrays should have been obtained with pffft_transform(.., PFFFT_FORWARD) and should *not* have been reordered with pffft_zreorder (otherwise just perform the operation yourself as the dft coefs are stored as interleaved complex numbers). the operation performed is: dft_ab += (dft_a * fdt_b)*scaling The dft_a, dft_b and dft_ab pointers may alias. */ void pffft_zconvolve_accumulate(PFFFT_Setup* setup, const float* dft_a, const float* dft_b, float* dft_ab, float scaling); /* the float buffers must have the correct alignment (16-byte boundary on intel and powerpc). This function may be used to obtain such correctly aligned buffers. */ void* pffft_aligned_malloc(size_t nb_bytes); void pffft_aligned_free(void*); /* return 4 or 1 wether support SSE/Altivec instructions was enable when * building pffft.c */ int pffft_simd_size(); #ifdef __cplusplus } #endif #endif // PFFFT_H ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/third_party/rnnoise/0000775000175000017500000000000014475643423022162 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/third_party/rnnoise/BUILD.gn0000664000175000017500000000076014475643423023352 0ustar00arunarunIyBDb3B5cmlnaHQgMjAxOCBUaGUgQ2hyb21pdW0gQXV0aG9ycy4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KIyBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhIEJTRC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlCiMgZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZS4KCmltcG9ydCgiLy90ZXN0aW5nL3Rlc3QuZ25pIikKCmdyb3VwKCJybm5vaXNlIikgewogIGRlcHMgPSBbICI6cm5uX3ZhZCIgXQp9Cgpzb3VyY2Vfc2V0KCJybm5fdmFkIikgewogIHNvdXJjZXMgPSBbCiAgICAic3JjL3Jubl9hY3RpdmF0aW9ucy5oIiwKICAgICJzcmMvcm5uX3ZhZF93ZWlnaHRzLmNjIiwKICAgICJzcmMvcm5uX3ZhZF93ZWlnaHRzLmgiLAogIF0KfQo=././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/third_party/rnnoise/COPYING0000664000175000017500000000407414475643423023222 0ustar00arunarunQ29weXJpZ2h0IChjKSAyMDE3LCBNb3ppbGxhCkNvcHlyaWdodCAoYykgMjAwNy0yMDE3LCBKZWFuLU1hcmMgVmFsaW4KQ29weXJpZ2h0IChjKSAyMDA1LTIwMTcsIFhpcGguT3JnIEZvdW5kYXRpb24KQ29weXJpZ2h0IChjKSAyMDAzLTIwMDQsIE1hcmsgQm9yZ2VyZGluZwoKUmVkaXN0cmlidXRpb24gYW5kIHVzZSBpbiBzb3VyY2UgYW5kIGJpbmFyeSBmb3Jtcywgd2l0aCBvciB3aXRob3V0Cm1vZGlmaWNhdGlvbiwgYXJlIHBlcm1pdHRlZCBwcm92aWRlZCB0aGF0IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9ucwphcmUgbWV0OgoKLSBSZWRpc3RyaWJ1dGlvbnMgb2Ygc291cmNlIGNvZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodApub3RpY2UsIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIuCgotIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0Cm5vdGljZSwgdGhpcyBsaXN0IG9mIGNvbmRpdGlvbnMgYW5kIHRoZSBmb2xsb3dpbmcgZGlzY2xhaW1lciBpbiB0aGUKZG9jdW1lbnRhdGlvbiBhbmQvb3Igb3RoZXIgbWF0ZXJpYWxzIHByb3ZpZGVkIHdpdGggdGhlIGRpc3RyaWJ1dGlvbi4KCi0gTmVpdGhlciB0aGUgbmFtZSBvZiB0aGUgWGlwaC5PcmcgRm91bmRhdGlvbiBub3IgdGhlIG5hbWVzIG9mIGl0cwpjb250cmlidXRvcnMgbWF5IGJlIHVzZWQgdG8gZW5kb3JzZSBvciBwcm9tb3RlIHByb2R1Y3RzIGRlcml2ZWQgZnJvbQp0aGlzIHNvZnR3YXJlIHdpdGhvdXQgc3BlY2lmaWMgcHJpb3Igd3JpdHRlbiBwZXJtaXNzaW9uLgoKVEhJUyBTT0ZUV0FSRSBJUyBQUk9WSURFRCBCWSBUSEUgQ09QWVJJR0hUIEhPTERFUlMgQU5EIENPTlRSSUJVVE9SUwpgYEFTIElTJycgQU5EIEFOWSBFWFBSRVNTIE9SIElNUExJRUQgV0FSUkFOVElFUywgSU5DTFVESU5HLCBCVVQgTk9UCkxJTUlURUQgVE8sIFRIRSBJTVBMSUVEIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZIEFORCBGSVRORVNTIEZPUgpBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBUkUgRElTQ0xBSU1FRC4gIElOIE5PIEVWRU5UIFNIQUxMIFRIRSBGT1VOREFUSU9OCk9SIENPTlRSSUJVVE9SUyBCRSBMSUFCTEUgRk9SIEFOWSBESVJFQ1QsIElORElSRUNULCBJTkNJREVOVEFMLApTUEVDSUFMLCBFWEVNUExBUlksIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUyAoSU5DTFVESU5HLCBCVVQgTk9UCkxJTUlURUQgVE8sIFBST0NVUkVNRU5UIE9GIFNVQlNUSVRVVEUgR09PRFMgT1IgU0VSVklDRVM7IExPU1MgT0YgVVNFLApEQVRBLCBPUiBQUk9GSVRTOyBPUiBCVVNJTkVTUyBJTlRFUlJVUFRJT04pIEhPV0VWRVIgQ0FVU0VEIEFORCBPTiBBTlkKVEhFT1JZIE9GIExJQUJJTElUWSwgV0hFVEhFUiBJTiBDT05UUkFDVCwgU1RSSUNUIExJQUJJTElUWSwgT1IgVE9SVAooSU5DTFVESU5HIE5FR0xJR0VOQ0UgT1IgT1RIRVJXSVNFKSBBUklTSU5HIElOIEFOWSBXQVkgT1VUIE9GIFRIRSBVU0UKT0YgVEhJUyBTT0ZUV0FSRSwgRVZFTiBJRiBBRFZJU0VEIE9GIFRIRSBQT1NTSUJJTElUWSBPRiBTVUNIIERBTUFHRS4K././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/third_party/rnnoise/meson.build0000664000175000017500000000042714475643423024327 0ustar00arunarunrnnoise_sources = [ 'src/rnn_vad_weights.cc', ] librnnoise = static_library('librnnoise', rnnoise_sources, dependencies: common_deps, include_directories: webrtc_inc, cpp_args : common_cxxflags ) rnnoise_dep = declare_dependency( link_with: librnnoise ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/third_party/rnnoise/src/0000775000175000017500000000000014475643423022751 5ustar00arunarun././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/third_party/rnnoise/src/rnn_activations.h0000664000175000017500000001114514475643423026325 0ustar00arunarun/* Copyright (c) 2008-2011 Octasic Inc. 2012-2017 Jean-Marc Valin */ /* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef THIRD_PARTY_RNNOISE_SRC_RNN_ACTIVATIONS_H_ #define THIRD_PARTY_RNNOISE_SRC_RNN_ACTIVATIONS_H_ #include namespace rnnoise { inline float TansigApproximated(float x) { static constexpr float kTansigTable[201] = { 0.000000f, 0.039979f, 0.079830f, 0.119427f, 0.158649f, 0.197375f, 0.235496f, 0.272905f, 0.309507f, 0.345214f, 0.379949f, 0.413644f, 0.446244f, 0.477700f, 0.507977f, 0.537050f, 0.564900f, 0.591519f, 0.616909f, 0.641077f, 0.664037f, 0.685809f, 0.706419f, 0.725897f, 0.744277f, 0.761594f, 0.777888f, 0.793199f, 0.807569f, 0.821040f, 0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f, 0.885352f, 0.893698f, 0.901468f, 0.908698f, 0.915420f, 0.921669f, 0.927473f, 0.932862f, 0.937863f, 0.942503f, 0.946806f, 0.950795f, 0.954492f, 0.957917f, 0.961090f, 0.964028f, 0.966747f, 0.969265f, 0.971594f, 0.973749f, 0.975743f, 0.977587f, 0.979293f, 0.980869f, 0.982327f, 0.983675f, 0.984921f, 0.986072f, 0.987136f, 0.988119f, 0.989027f, 0.989867f, 0.990642f, 0.991359f, 0.992020f, 0.992631f, 0.993196f, 0.993718f, 0.994199f, 0.994644f, 0.995055f, 0.995434f, 0.995784f, 0.996108f, 0.996407f, 0.996682f, 0.996937f, 0.997172f, 0.997389f, 0.997590f, 0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f, 0.998508f, 0.998623f, 0.998728f, 0.998826f, 0.998916f, 0.999000f, 0.999076f, 0.999147f, 0.999213f, 0.999273f, 0.999329f, 0.999381f, 0.999428f, 0.999472f, 0.999513f, 0.999550f, 0.999585f, 0.999617f, 0.999646f, 0.999673f, 0.999699f, 0.999722f, 0.999743f, 0.999763f, 0.999781f, 0.999798f, 0.999813f, 0.999828f, 0.999841f, 0.999853f, 0.999865f, 0.999875f, 0.999885f, 0.999893f, 0.999902f, 0.999909f, 0.999916f, 0.999923f, 0.999929f, 0.999934f, 0.999939f, 0.999944f, 0.999948f, 0.999952f, 0.999956f, 0.999959f, 0.999962f, 0.999965f, 0.999968f, 0.999970f, 0.999973f, 0.999975f, 0.999977f, 0.999978f, 0.999980f, 0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f, 0.999988f, 0.999989f, 0.999990f, 0.999990f, 0.999991f, 0.999992f, 0.999992f, 0.999993f, 0.999994f, 0.999994f, 0.999994f, 0.999995f, 0.999995f, 0.999996f, 0.999996f, 0.999996f, 0.999997f, 0.999997f, 0.999997f, 0.999997f, 0.999997f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, }; // Tests are reversed to catch NaNs. if (!(x < 8.f)) return 1.f; if (!(x > -8.f)) return -1.f; float sign = 1.f; if (x < 0.f) { x = -x; sign = -1.f; } // Look-up. int i = static_cast(std::floor(0.5f + 25 * x)); float y = kTansigTable[i]; // Map i back to x's scale (undo 25 factor). x -= 0.04f * i; y = y + x * (1.f - y * y) * (1.f - y * x); return sign * y; } inline float SigmoidApproximated(const float x) { return 0.5f + 0.5f * TansigApproximated(0.5f * x); } inline float RectifiedLinearUnit(const float x) { return x < 0.f ? 0.f : x; } } // namespace rnnoise #endif // THIRD_PARTY_RNNOISE_SRC_RNN_ACTIVATIONS_H_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/third_party/rnnoise/src/rnn_vad_weights.cc0000664000175000017500000007037514475643423026455 0ustar00arunarun#include "third_party/rnnoise/src/rnn_vad_weights.h" namespace rnnoise { const int8_t kInputDenseWeights[kInputLayerWeights] = { -10, 0, -3, 1, -8, -6, 3, -13, 1, 0, -3, -7, -5, -3, 6, -1, -6, 0, -6, -4, -1, -2, 1, 1, -7, 2, 21, 10, -5, -20, 24, 23, 37, 8, -2, 33, -6, 22, 13, -2, 50, 8, 13, 1, -15, 30, -10, 30, 0, 3, 5, 27, 1, 4, -3, 41, 56, 35, -2, 49, -13, 11, 13, -2, -47, 5, -16, -60, -15, 77, -17, 26, -3, 14, -21, 19, -5, -19, -13, 0, 10, 14, 9, 31, -13, -41, -10, 4, 22, 18, -48, -6, -10, 62, -3, -18, -14, 12, 26, -28, 3, 14, 25, -13, -19, 6, 5, 36, -3, -65, -12, 0, 31, -7, -9, 101, -4, 26, 16, 17, -12, -12, 14, -36, -3, 5, -15, 21, 2, 30, -3, 38, -4, 1, -6, 7, -7, 14, 38, -22, -30, -3, -7, 3, -39, -70, -126, 25, 34, 94, -67, -22, -33, 83, -47, -118, 4, 70, 33, 25, 62, -128, -76, -118, -113, 49, -12, -100, -18, -114, -33, 43, 32, 61, 40, -9, -106, 2, 36, -100, -40, -5, 20, -75, 61, -51, -9, 126, -27, -52, 5, -24, -21, -126, -114, -12, 15, 106, -2, 73, -125, 50, 13, -120, 35, 35, 4, -61, 29, -124, 6, -53, -69, -125, 64, -89, 36, -107, -103, -7, 27, 121, 69, 77, -35, 35, 95, -125, -49, 97, -45, -43, -23, 23, -28, -65, -118, 2, 8, -126, 27, -97, 92, 5, 55, 82, 17, -57, -115, 37, 8, -106, -46, 41, -2, 21, -44, 8, -73, -58, -39, 34, 89, -95, 95, -117, 120, -58, 31, 123, 1, -32, -109, -110, 60, -120, -43, -74, 5, 91, 26, 21, 114, 82, -83, -126, 123, 22, -16, -67, 25, -83, 46, 48, -34, -121, -124, -63, -35, -9, 31, 82, 123, 6, -3, 117, 93, -2, -13, -36, 124, -112, -6, -102, -5, -33, -15, 44, -69, -127, -23, -40, -34, -85, 68, 83, -1, 40, 8, 84, 118, -58, -55, -102, 123, -55, -14, -123, 44, -63, -14, 21, 35, 16, 24, -126, -13, -114, 35, 20, -36, 61, -9, 97, 34, 19, -32, -109, 76, -104, 99, -119, 45, -125, -51, -28, -8, -69, -8, 125, -45, -93, 113, 103, -41, -82, 52, 7, 126, 0, -40, 104, 55, -58, 17, -124, -93, -58, 8, -45, 1, 56, -123, 108, -47, -23, 115, 127, 17, -68, -13, 116, -82, -44, 45, 67, -120, -101, -15, -125, 120, -113, 17, -48, -73, 126, -64, -86, -118, -19, 112, -1, -66, -27, -62, 121, -86, -58, 50, 89, -38, -75, 95, -111, 12, -113, 2, -68, 2, -94, -121, 91, -5, 0, 79, 43, -7, -18, 79, 35, -38, 47, 1, -45, 83, -50, 102, 32, 55, -96, 15, -122, -69, 45, -27, 91, -62, -30, 46, -95, 22, -72, -97, -1, 14, -122, 28, 127, 61, -126, 121, 9, 68, -120, 49, -60, 90, 3, 43, 68, 54, 34, -10, 28, 21, -24, -54, 22, -113, -12, 82, -2, -17, -9, 127, 8, 116, -92, 0, -70, -33, 123, 66, 116, -74, -4, 74, -72, -22, -47, 1, -83, -60, -124, 1, 122, -57, -43, 49, 40, -126, -128, -8, -29, 28, -24, -123, -121, -70, -93, -37, -126, 11, -125, -37, 11, -31, -51, -124, 116, -128, 8, -25, 109, 75, -12, 7, 8, 10, 117, 124, -128, -128, 29, -26, 101, 21, -128, 87, 8, -39, 23, -128, 127, -127, 74, -55, 74, 112, 127, 4, 55, 44, -92, 123, 34, -93, 47, -21, -92, 17, 49, -121, 92, 7, -126, -125, 124, -74, 3, -59, 18, -91, 3, -9, 9, 56, 116, 7, -29, 33, 87, -21, -128, -13, 57, 74, 9, -29, -61, -97, -21, -95, -12, -114, 16, 82, 125, -7, 10, -24, 9, 77, -128, -102, -25, 3, -126, 10, 13, -18, 51, 26, 127, -79, 35, 51, 12, -50, -24, 1, -7, 22, 81, 65, 120, -30, -38, 85, 122, -4, -106, -11, 27, 53, 41, 8, -104, -66, -38, -124, 10, 12, 76, 117, -109, 9, 11, 2, -18, 3, 113, -16, -79, -39, -123, -20, -128, 2, 13, -33, -58, 10, 84, -104, 13, 64, 109, 1, 54, -12, 28, 24, 63, -126, 118, -82, 46, -12, -15, 14, -43, 60, 22, -32, -19, -46, 91, -107, 24, -94, 26, -47, 125, 6, 58, -15, -75, -26, -38, -35, 103, -16, -17, -13, 63, -2, 45, -45, -73, -23, 70, -87, 51, -17, 53, 76, 14, -18, -31, -14, 103, 8, 21, -28, -33, -20, -47, 6, 39, 40, -30, 7, -76, 55, 31, -20, -21, -59, 1, 25, -11, 17, 5, -13, -39, 0, -76, 50, -33, -29, -50, -16, -11, -12, -1, -46, 40, -10, 65, -19, 21, -41, -32, -83, -19, -4, 49, -60, 118, -24, -46, 9, 102, -20, 8, -19, 25, 31, -3, -37, 0, 25, 7, 29, 2, -39, 127, -64, -20, 64, 115, -30, 36, 100, 35, 122, 127, 127, -127, 127, -127, 19, 127, -89, -79, -32, 39, -127, 125, -80, 126, -127, 26, 8, 98, -8, -57, -90, -50, 126, 61, 127, -126, 40, -106, -68, 104, -125, -119, 11, 10, -127, 66, -56, -12, -126, -104, 27, 75, 38, -124, -126, -125, 84, -123, -45, -114, -128, 127, 103, -101, -124, 127, -11, -23, -123, 92, -123, 24, 126, 41, -2, -39, -27, -94, 40, -112, -48, 127, 58, 14, 38, -75, -64, 73, 117, 100, -119, -11, 6, 32, -126, -14, 35, 121, -10, 54, -60, 89, -3, 69, -25, -20, 43, -86, -34, 24, 27, 7, -81, -99, -23, -16, -26, 13, 35, -97, 80, -29, -13, -121, -12, -65, -94, 70, -89, -126, -95, 88, 33, 96, 29, -90, 69, 114, -78, 65, 90, -47, -47, 89, 1, -12, 3, 8, 30, 5, 2, -30, -1, 6, -7, 10, -4, 46, -27, -40, 22, -6, -17, 45, 24, -9, 23, -14, -63, -26, -12, -57, 27, 25, 55, -76, -47, 21, 34, 33, 26, 17, 14, 6, 9, 26, 25, -25, -25, -18}; const int8_t kInputDenseBias[kInputLayerOutputSize] = { 38, -6, 127, 127, 127, -43, -127, 78, 127, 5, 127, 123, 127, 127, -128, -76, -126, 28, 127, 125, -30, 127, -89, -20}; const int8_t kHiddenGruWeights[kHiddenLayerWeights] = { -124, 23, -123, -33, -95, -4, 8, -84, 4, 101, -119, 116, -4, 123, 103, -51, 29, -124, -114, -49, 31, 9, 75, -128, 0, -49, 37, -50, 46, -21, -63, -104, 54, 82, 33, 21, 70, 127, -9, -79, -39, -23, -127, 107, 122, -96, -46, -18, -39, 13, -28, -48, 14, 56, -52, 49, -1, -121, 25, -18, -36, -52, -57, -30, 54, -124, -26, -47, 10, 39, 12, 2, 9, -127, -128, 102, 21, 11, -64, -71, 89, -113, -111, 54, 31, 94, 121, -40, 30, 40, -109, 73, -9, 108, -92, 2, -127, 116, 127, 127, -122, 95, 127, -37, -127, 28, 89, 10, 24, -104, -62, -67, -14, 38, 14, -71, 22, -41, 20, -50, 39, 63, 86, 127, -18, 79, 4, -51, 2, 33, 117, -113, -78, 56, -91, 37, 34, -45, -44, -22, 21, -16, 56, 30, -84, -79, 38, -74, 127, 9, -25, 2, 82, 61, 25, -26, 26, 11, 117, -65, 12, -58, 42, -62, -93, 11, 11, 124, -123, 80, -125, 11, -90, 42, 94, 4, -109, -1, 85, -52, 45, -26, -27, 77, -5, 30, 90, 0, 95, -7, 53, 29, -82, 22, -9, 74, 2, -12, -73, 114, 97, -64, 122, -77, 43, 91, 86, 126, 106, 72, 90, -43, 46, 96, -51, 21, 22, 68, 22, 41, 79, 75, -46, -105, 23, -116, 127, -123, 102, 57, 85, 10, -29, 34, 125, 126, 124, 81, -15, 54, 96, -128, 39, -124, 103, 74, 126, 127, -50, -71, -122, -64, 93, -75, 71, 105, 122, 123, 126, 122, -127, 33, -63, -74, 124, -71, 33, 41, -56, 19, 6, 65, 41, 90, -116, -3, -46, 75, -13, 98, -74, -42, 74, -95, -96, 81, 24, 32, -19, -123, 74, 55, 109, 115, 0, 32, 33, 12, -20, 9, 127, 127, -61, 79, -48, -54, -49, 101, -9, 27, -106, 74, 119, 77, 87, -126, -24, 127, 124, 31, 34, 127, 40, 3, -90, 127, 23, 57, -53, 127, -69, -88, -33, 127, 19, -46, -9, -125, 13, -126, -113, 127, -41, 46, 106, -62, 3, -10, 111, 49, -34, -24, -20, -112, 11, 101, -50, -34, 50, 65, -64, -106, 70, -48, 60, 9, -122, -45, 15, -112, -26, -4, 1, 39, 23, 58, -45, -80, 127, 82, 58, 30, -94, -119, 51, -89, 95, -107, 30, 127, 125, 58, -52, -42, -38, -20, -122, 115, 39, -26, 5, 73, 13, -39, 43, -23, -20, -125, 23, 35, 53, -61, -66, 72, -20, 33, 8, 35, 4, 7, 18, 19, 16, -45, -50, -71, 31, -29, -41, -27, 10, 14, 27, 9, -23, 98, 6, -94, 92, 127, -114, 59, -26, -100, -62, -127, -17, -85, -60, 126, -42, -6, 33, -120, -26, -126, -127, -35, -114, -31, 25, -126, -100, -126, -64, -46, -31, 30, 25, -74, -111, -97, -81, -104, -114, -19, -9, -116, -69, 22, 30, 59, 8, -51, 16, -97, 18, -4, -89, 80, -50, 3, 36, -67, 56, 69, -26, 107, -10, 58, -28, -4, -57, -72, -111, 0, -75, -119, 14, -75, -49, -66, -49, 8, -121, 22, -54, 121, 30, 54, -26, -126, -123, 56, 5, 48, 21, -127, -11, 23, 25, -82, 6, -25, 119, 78, 4, -104, 27, 61, -48, 37, -13, -52, 50, -50, 44, -1, -22, -43, -59, -78, -67, -32, -26, 9, -3, 40, 16, 19, 3, -9, 20, -6, -37, 28, 39, 17, -19, -10, 1, 6, -59, 74, 47, 3, -119, 0, -128, -107, -25, -22, -69, -23, -111, -42, -93, -120, 90, -85, -54, -118, 76, -79, 124, 101, -77, -75, -17, -71, -114, 68, 55, 79, -1, -123, -20, 127, -65, -123, -128, -87, 123, 9, -115, -14, 7, -4, 127, -79, -115, 125, -28, 89, -83, 49, 89, 119, -69, -5, 12, -49, 60, 57, -24, -99, -110, 76, -83, 125, 73, 81, 11, 8, -45, 1, 83, 13, -70, -2, 97, 112, -97, 53, -9, -94, 124, 44, -49, -24, 52, 76, -110, -70, -114, -12, 72, -4, -114, 43, -43, 81, 102, -84, -27, 62, -40, 52, 58, 124, -35, -51, -123, -43, 56, -75, -34, -35, -106, 93, -43, 14, -16, 46, 62, -97, 21, 30, -53, 21, -11, -33, -20, -95, 4, -126, 12, 45, 20, 108, 85, 11, 20, -40, 99, 4, -25, -18, -23, -12, -126, -55, -20, -44, -51, 91, -127, 127, -44, 7, 127, 78, 38, 125, -6, -94, -103, 73, 126, -126, 18, 59, -46, 106, 76, 116, -31, 75, -4, 92, 102, 32, -31, 73, 42, -21, -28, 57, 127, -8, -107, 115, 124, -94, -4, -128, 29, -57, 70, -82, 50, -13, -44, 38, 67, -93, 6, -39, -46, 56, 68, 27, 61, 26, 18, -72, 127, 22, 18, -31, 127, 61, -65, -38, 1, -67, -1, 8, -73, 46, -116, -94, 58, -49, 71, -40, -63, -82, -20, -60, 93, 76, 69, -106, 34, -31, 4, -25, 107, -18, 45, 4, -61, 126, 54, -126, -125, 41, 19, 44, 32, -98, 125, -24, 125, -96, -125, 15, 87, -4, -90, 18, -40, 28, -69, 67, 22, 41, 39, 7, -48, -44, 12, 69, -13, 2, 44, -38, 111, -7, -126, -22, -9, 74, -128, -36, -7, -123, -15, -79, -91, -37, -127, -122, 104, 30, 7, 98, -37, 111, -116, -47, 127, -45, 118, -111, -123, -120, -77, -64, -125, 124, 77, 111, 77, 18, -113, 117, -9, 67, -77, 126, 49, -20, -124, 39, 41, -124, -34, 114, -87, -126, 98, -20, 59, -17, -24, 125, 107, 54, 35, 33, -44, 12, -29, 125, -71, -28, -63, -114, 28, -17, 121, -36, 127, 89, -122, -49, -18, -48, 17, 24, 19, -64, -128, 13, 86, 45, 13, -49, 55, 84, 48, 80, -39, 99, -127, 70, -33, 30, 50, 126, -65, -117, -13, -20, -24, 127, 115, -72, -104, 63, 126, -42, 57, 17, 46, 21, 119, 110, -100, -60, -112, 62, -33, 28, 26, -22, -60, -33, -54, 78, 25, 32, -114, 86, 44, 26, 43, 76, 121, 19, 97, -2, -3, -73, -68, 6, -116, 6, -43, -97, 46, -128, -120, -31, -119, -29, 16, 16, -126, -128, -126, -46, -9, -3, 92, -31, -76, -126, -3, -107, -12, -23, -69, 5, 51, 27, -42, 23, -70, -128, -29, 22, 29, -126, -55, 50, -71, -3, 127, 44, -27, -70, -63, -66, -70, 104, 86, 115, 29, -92, 41, -90, 44, -11, -28, 20, -11, -63, -16, 43, 31, 17, -73, -31, -1, -17, -11, -39, 56, 18, 124, 72, -14, 28, 69, -121, -125, 34, 127, 63, 86, -80, -126, -125, -124, -47, 124, 77, 124, -19, 23, -7, -50, 96, -128, -93, 102, -53, -36, -87, 119, -125, 92, -126, 118, 102, 72, -2, 125, 10, 97, 124, -125, 125, 71, -20, -47, -116, -121, -4, -9, -32, 79, -124, -36, 33, -128, -74, 125, 23, 127, -29, -115, -32, 124, -89, 32, -107, 43, -17, 24, 24, 18, 29, -13, -15, -36, 62, -91, 4, -41, 95, 28, -23, 6, 46, 84, 66, 77, 68, -70, -1, -23, -6, 65, 70, -21, 9, 77, -12, 2, -118, 4, 9, -108, 84, 52, 2, 52, 13, -10, 58, -110, 18, 66, -95, -23, 70, 31, -3, 56, 56, -3, -7, 1, -27, -48, -61, 41, -4, 10, -62, 32, -7, -24, 9, -48, -60, -4, 79, -20, -38, -76, 68, -49, -97, 0, -15, 5, -100, -49, -95, -99, -115, -9, -40, 10, 104, 13, 56, 127, -27, -109, -94, -118, -102, -44, -85, 52, 127, -4, 14, 62, 121, -122, -26, -79, -42, -34, 1, 25, -38, -79, -58, -31, -31, -90, -30, -123, 32, -56, 125, 66, 124, -1, 3, 91, -103, -7, 23, 78, -18, 9, 69, -69, 76, -38, -33, -2, -98, 18, 106, 84, 55, 87, -47, 35, -124, 64, 41, -14, 46, 25, -2, 120, -21, 82, 19, -79, -37, -3, -8, -16, 21, 19, -5, -28, -112, 39, -6, -30, 53, -69, 53, 46, 127, 123, 78, 20, 28, -7, 73, 72, 17, -40, 41, 111, 57, 32, -95, 29, 28, -39, -65, 54, -20, -63, 29, -67, 3, 44, -57, -47, 11, 61, -22, -44, 61, 48, -100, 20, 125, 96, -24, -16, 3, -69, -126, 74, -125, 9, 45, -67, -123, -59, -72, 118, 69, 45, 50, -57, 67, 13, -66, -106, 47, 62, 22, -1, -22, -25, -40, -125, 3, 125, 32, 102, -56, -25, -75, -30, 122, 60, -13, 36, -73, 7, -84, 124, 40, -118, 17, -87, -118, -8, 3, -27, 111, -40, 40, -51, 127, 125, -45, -30, -54, 46, 80, -1, -30, 101, -17, 18, 26, 54, 7, -12, 1, -127, 123, -122, -27, -75, 64, 10, 25, -15, -44, 127, -127, 5, -84, -81, -7, 19, -26, 126, 15, 116, -126, 14, -76, 44, 62, -110, -124, 125, -29, -87, -3, -69, 82, 90, 57, -123, 123, 100, -19, -51, -32, 69, 37, -57, -128, -124, -72, -13, 51, -7, -45, -73, 5, 99, -26, -117, -96, -109, 4, -31, -12, 0, 31, -42, -27, 12, -81, 118, 39, 83, 14, 41, -126, 107, -82, 94, -116, -122, -47, -109, -84, -128, -35, -56, 66, 8, -65, 19, 42, -46, -72, -109, 41, 43, -127, -113, 58, 127, 42, -75, -1, 65, 117, -55, -113, -123, 124, 43, -96, -115, -19, 68, 15, 94, 3, 75, 0, 34, 9, 42, 110, -48, 92, -76, 99, -17, 27, 32, 13, 125, 50, -17, 56, 4, 53, 34, -8, 99, 80, -126, -21, -65, -11, -46, 44, -81, -3, -121, 123, 66, -81, -84, 119, 127, 84, 105, 45, -66, -42, -23, 32, -25, 12, 111, 127, 88, 125, 30, 24, -127, -9, -54, 127, -116, -119, 88, 70, 94, -120, 35, -93, 15, 22, -21, 25, -110, -123, -45, 8, -109, 125, -122, -86, -126, 8, -14, -120, -45, -45, 69, -125, -122, 6, 81, 86, 125, 95, 54, 77, 54, -123, 126, -85, -117, 56, 11, 0, -61, -91, -12, -2, -113, -3, -15, -122, -63, -91, 10, 84, -111, 125, 93, 21, 62, -78, -116, 13, -57, 28, -124, 126, 110, 12, 15, 95, 15, -19, -125, -97, 52, -7, 101, 9, 20, -125, -26, -56, 72, 77, 12, -126, 22, -29, 47, 62, 95, 112, 69, 32, 97, -83, -8, -5, 67, -63, -123, 79, 59, 0, -6, -17, 4, -111, -52, 27, 65, 0}; const int8_t kHiddenGruRecurrentWeights[kHiddenLayerWeights] = { 65, 83, 35, 56, 24, -34, -28, -2, 125, 19, 42, -9, 124, -53, 24, -87, 11, 35, -81, -35, -125, -31, 123, -21, 33, -91, 113, -93, 45, -6, 53, 38, -92, 8, -27, 87, 4, 43, 43, 10, -128, -128, -46, 127, -38, -45, 25, -87, 19, 5, 52, -96, -23, -29, 121, -126, -24, -20, -2, 69, -50, 6, 71, -81, -125, 90, -94, 1, -38, 36, 89, 17, -60, 71, -48, 18, -15, 44, -18, 59, 11, 114, -51, 32, 110, 1, 4, 109, -24, 127, 27, 60, 88, 24, 45, -59, 75, -36, 8, 57, -32, -25, 13, 126, -89, -61, -76, 127, 18, -62, -68, 23, -113, 5, 126, 43, -88, 26, -78, 18, 75, 21, 9, -74, 20, 41, 126, -118, -15, 9, 116, 126, -127, 34, -6, 126, -128, -53, -54, -55, -121, 70, 127, -12, -68, 82, -25, 104, -126, 126, -21, -26, 124, -75, -127, -120, 13, 61, -64, -108, -63, -65, -44, -35, -61, -39, 109, -74, 113, -3, 108, -30, 125, 120, 39, 125, -128, -95, -99, 111, 9, 25, 114, -75, -92, -54, -12, -32, -38, 10, 31, 10, 63, 51, 40, -99, 74, 4, 50, -128, -36, -35, -11, -28, -126, -7, 66, -58, -126, -22, -83, -61, -127, 49, 126, -8, 7, 62, 36, -11, -32, -44, 63, 116, 41, 65, -127, 126, 63, -30, -96, 74, -92, 127, 38, -18, -128, 68, -5, 101, -4, 85, 58, 79, 0, -58, 8, 119, -70, -1, -79, -68, 114, -28, -90, -6, -112, 2, 127, -8, 10, 55, -59, -126, 127, 125, 80, 72, 35, -54, 95, -124, -124, 79, 23, -46, -61, -127, -100, 99, -77, 8, -87, 5, -2, 49, 85, 7, -71, 82, 53, -41, 22, -22, -93, -103, 6, 52, -56, 14, -8, -111, 85, 16, 54, 32, -118, -24, 61, -53, 96, -70, -5, -17, -67, -84, -7, -82, -107, -96, 21, -83, -58, 50, 12, -126, -1, -28, 34, -126, 115, 17, 91, 1, -127, 72, 11, 126, -81, 6, 96, -8, 77, 15, -6, 63, -27, 20, -123, -109, 85, -79, -17, 126, -92, 2, -61, 20, 14, 17, 121, 123, 30, 57, 120, 127, 57, 42, 117, 98, 67, 39, -20, -70, 100, 7, 125, 122, 40, 16, -79, 125, 83, 41, -106, -57, 24, 55, 27, -66, -111, -44, -7, -43, -66, 121, 42, -128, -45, 35, 15, -127, 34, -35, -34, -40, -18, -6, 63, 111, 31, 116, 127, 19, 24, -71, -39, 34, 11, 19, -40, 27, 12, 106, -10, 56, -82, -106, -2, -50, -52, 114, -126, -34, -43, -68, 10, 76, 57, -118, -128, 37, -104, 76, 125, 3, -76, 127, -29, 84, -94, -15, 55, 125, 79, 127, -57, -125, 104, -68, 126, 126, -77, 51, 45, 33, -109, 115, -11, 1, 95, -121, -5, -9, -126, -114, 39, 68, -126, -107, -51, -42, 24, -8, 51, -27, -43, 66, -45, 62, -98, -109, 69, 67, 0, -125, -128, 49, 31, 126, -122, 2, -55, -67, -126, -70, -128, -125, -77, 25, 16, -8, -102, 11, -75, 82, 38, -5, 5, 19, 34, 47, -127, -93, 21, 24, -97, -18, 31, 39, 34, -20, 22, 123, 7, -77, -81, -46, -9, 1, 23, 39, -127, -43, -8, -50, 10, -21, 59, -9, -4, -13, -27, 44, 127, 52, -47, 70, -43, 52, 101, -49, 27, 45, 49, 33, -125, 55, 114, 20, -1, 76, -24, -96, 105, 24, 126, 75, -21, -105, 13, -42, 40, 126, -30, -39, -95, 125, -63, 11, 6, 125, 125, -14, 5, 42, -61, -4, 49, 88, 6, -107, -28, 19, -29, 47, 126, 6, -46, -89, -18, 91, -20, -6, 118, -21, -22, 39, 115, 11, -42, 54, 73, -55, -77, 62, -27, -59, -99, -12, -127, -40, 56, -3, -124, -91, 71, -111, 6, -19, 82, -24, -35, 102, -42, 7, -126, -126, -125, 18, 98, -52, 127, 105, -52, 40, -83, 126, -122, 109, 5, 127, 48, 6, 5, -125, 100, -16, 29, 85, -89, 8, 4, 41, 62, -127, 62, 122, 85, 122, -107, 8, -125, 93, -127, 127, 102, 19, 19, -66, 41, -42, 114, 127, -48, -117, -29, -6, -73, -102, -3, -19, 0, 88, 42, 87, -117, -20, 2, 122, 28, 63, 71, 66, 120, 93, 124, -43, 49, 103, 31, 90, -91, -22, -126, 26, -24, -21, 51, -126, 87, -103, -69, -10, -66, -23, 20, 97, 36, 25, -127, 30, -20, -63, 30, 51, -116, 23, 40, -39, 36, -83, -77, -25, -50, 110, 14, 13, -109, 125, -65, -55, -87, 124, -126, -32, -72, -108, 127, 127, -125, -124, 61, 121, 102, -128, -127, 16, 100, 127, -124, -68, 72, -93, -128, 43, -93, -19, -125, -97, -113, -33, 83, 127, -44, 127, -75, 127, 16, 44, 50, -122, 23, 118, 46, 19, 26, -128, 10, 4, 99, -14, -82, -13, 30, 125, 57, 65, 60, -71, 35, 98, 28, 7, 1, 43, 89, 70, 75, 121, -59, 82, -126, -53, -16, -116, -65, 52, -52, 0, 80, 35, 45, -61, 46, 8, 107, 27, -26, -118, 90, 57, -10, 7, -15, 0, -39, -4, 12, 29, -1, 116, 84, 79, 119, 125, -59, 28, -6, -25, -43, 2, 90, 79, 67, 103, -82, 2, -6, 125, 19, 73, 0, -105, 112, -17, 104, 107, 124, 106, 19, 56, -44, 55, -112, 6, -39, -83, 126, -93, -98, 57, -120, -23, -38, 2, -31, -48, 106, 127, 127, 69, 16, 110, 71, 104, 62, -12, -22, 42, -37, -94, 34, -1, -32, -12, -124, -47, -13, 60, -75, -66, 58, -127, -2, 64, 76, -106, 73, -49, -31, 127, 126, 31, 16, 127, -110, 107, -16, -53, 20, 69, -14, -125, 59, -44, 15, 120, 125, 125, 43, 6, 19, -58, 127, 127, 43, 16, 82, 97, -127, 127, -93, -41, 88, 0, 77, -15, 116, 16, -124, -31, -3, 95, -40, -126, -54, -126, -83, -8, -59, 6, 67, -29, 4, 124, -10, 112, -28, -8, 85, -21, 45, 84, 6, -8, 11, 72, 32, 84, -62, 77, 2, -36, 75, 31, -50, 116, 126, 119, -88, -55, -14, -37, 126, 40, -108, -6, -6, 57, 64, -28, -76, 30, -117, -93, 31, -92, -44, -64, 94, 58, 65, 114, 41, 47, 71, 42, -26, 99, -126, 57, -5, 74, -19, -113, -1, 67, -21, 126, 1, -3, 33, 60, -82, 37, -48, 89, 114, -38, 127, -114, 35, 58, -5, 21, -46, 121, -123, -43, 127, 115, 123, 122, -101, 126, 127, 81, 52, 89, -127, 102, 42, 117, -9, -2, 125, 127, 110, 96, 120, 66, 70, 124, 55, 84, -38, -58, 119, -127, -16, -79, 123, 18, -127, -50, -38, 120, -85, 1, 7, -56, 108, -77, -2, 21, 37, 1, 13, -105, -69, 28, -87, 33, -104, -51, 126, 41, 3, -121, 28, 71, 58, 86, -8, 127, 94, -55, 125, 40, -19, 127, -33, -87, -23, 7, -111, -68, 9, 84, -119, 55, -82, 78, -37, -20, -9, -23, 53, -13, 15, -46, 116, 126, -127, 56, -126, 125, -7, -1, 45, 26, 125, 121, 29, 47, -86, 30, 10, 76, -125, -7, 23, 92, -12, -39, -18, 92, -97, -8, -85, -41, 49, -50, 123, -37, -126, -30, 14, 79, -49, -65, 9, -36, -38, -96, 85, -24, -13, 37, -25, -5, -64, -127, 55, -60, -18, -61, -63, 127, 56, 67, 15, 124, 72, 120, 127, 40, -10, 114, 24, -23, 46, 78, -53, 125, 86, 124, 86, 0, 38, 93, 21, 127, 123, 75, -72, 13, 48, 33, 83, -51, 15, -32, -49, -33, 120, 64, 7, 9, 65, 60, 21, -21, -61, -53, -113, 84, -97, 101, 37, -114, -27, 41, 73, 126, -10, 59, 61, -15, 70, -13, 82, -4, 69, 56, 94, -91, -50, 92, -74, -48, 53, -7, -107, 127, 28, 30, -26, -21, -61, 77, 82, 64, -91, -125, 122, -104, 127, 123, 122, 123, 76, -126, 127, -6, -80, 7, 40, -66, -65, 54, -2, 23, 96, -64, 74, 2, -53, -12, -123, 39, 60, -20, 16, -17, -97, 23, -4, -53, -122, 32, -16, -54, -95, 43, 71, -1, -67, -33, 41, 18, 72, 28, -83, 31, -100, -91, -27, 10, -128, -106, 2, 76, -13, 42, 34, 112, -19, 44, 40, -9, -11, 65, 92, -43, -125, 2, 47, -32, 25, 122, -29, 12, 101, -8, -126, -23, 43, 7, 125, -20, -124, 82, -2, 13, -73, -106, 115, 31, 116, -23, -44, -71, 84, 3, 47, 91, 127, 127, -15, 95, 7, 93, 5, 113, -50, 54, 11, 13, -127, 17, 72, 43, -23, 5, -70, 20, 15, -27, 99, 69, -109, -122, -94, 16, 127, 0, 116, 104, 45, 108, -34, 87, 72, -14, 118, 46, 42, 109, -26, 95, 93, 127, 60, 127, -93, -54, -122, 34, -105, 56, 55, 103, 125, -71, -50, 95, -72, 127, 107, 21, 73, 126, 61, 127, 127, 24, -62, 90, 73, 90, -46, -78, -124, 72, 123, -42, 50, -107, 17, -32, -62, -89, 124, 1, 80, -2, 117, 119, -65, -127, -95, -121, -52, 103, 66, 75, -3, -62, -127, 127, -74, 124, 79, 49, 40, 105, -67, -71, -70, 43, 127, 119, -4, 66, 43, 23, 91, -126, 15, 63, -119, 112, 103, 15, -99, 31, -127, 69, 116, -46, -67, 2, -126, -29, 30, 30, -69, -98, -47, -87, -70, -127, 23, -73, 30, -7, 94, -52, -65, 98, -45, 97, 53, 23, -9, -22, -52, -47, 6, -1, -85, -15, -61, -14, 68, 110, -10, -121, -25, -35, -15, -94, -123, 27, 75, 48, -66, -56, -44, 93, 109, 67, -36, 24, 70, -126, 8, -127, 126, 52, 11, -32, 120, -13, -26, -28, -125, 127, 106, -50, 124, 36, -126, -12, 0, -23, 76, -71, -126, -12, -17, -82, 12, 124, 57, 33, 4, 77, -46, 71, -34, 72, 125, -128, 124, -24, -128, 75, -120, 69, -45, 55, 33, 127, -33, 4, -105, -41, -59, -91, 123, 44, -127, 127, -67, 52, 25, -125, -65, 100, -25, 123, 6, 11, -123, -92, -33, 126, -17, -4, 29, 33, 127, 96, 3, 87, -48, -18, -70, 123, 58, -127, -3, -52, -1, -36, -41, 127, 51, -52, -27, 46, -83, 57, 9, 126, 127, 94, 79, -37, -127, -40, 67, 52, 82, -66, 122, -13, -73, 127, -8, -80, 46, -48, 4, -54}; const int8_t kHiddenGruBias[kHiddenLayerBiases] = { 124, 125, -57, -126, 53, 123, 127, -75, 68, 102, -2, 116, 124, 127, 124, 125, 126, 123, -16, 48, 125, 126, 78, 85, 11, 126, -30, -30, -64, -3, -105, -29, -17, 69, 63, 2, -32, -10, -62, 113, -52, 112, -109, 112, 7, -40, 73, 53, 62, 6, -2, 0, 0, 100, -16, 26, -24, 56, 26, -10, -33, 41, 70, 109, -29, 127, 34, -66, 49, 53, 27, 62}; const int8_t kOutputDenseWeights[kOutputLayerWeights] = { 127, 127, 127, 127, 127, 20, 127, -126, -126, -54, 14, 125, -126, -126, 127, -125, -126, 127, -127, -127, -57, -30, 127, 80}; const int8_t kOutputDenseBias[kOutputLayerOutputSize] = {-50}; } // namespace rnnoise ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1693927187.0 webrtc-audio-processing-1.3/webrtc/third_party/rnnoise/src/rnn_vad_weights.h0000664000175000017500000000242414475643423026305 0ustar00arunarun#ifndef THIRD_PARTY_RNNOISE_SRC_RNN_VAD_WEIGHTS_H_ #define THIRD_PARTY_RNNOISE_SRC_RNN_VAD_WEIGHTS_H_ #include #include namespace rnnoise { // Weights scaling factor. const float kWeightsScale = 1.f / 256.f; // Input layer (dense). const size_t kInputLayerInputSize = 42; const size_t kInputLayerOutputSize = 24; const size_t kInputLayerWeights = kInputLayerInputSize * kInputLayerOutputSize; extern const int8_t kInputDenseWeights[kInputLayerWeights]; extern const int8_t kInputDenseBias[kInputLayerOutputSize]; // Hidden layer (GRU). const size_t kHiddenLayerOutputSize = 24; const size_t kHiddenLayerWeights = 3 * kInputLayerOutputSize * kHiddenLayerOutputSize; const size_t kHiddenLayerBiases = 3 * kHiddenLayerOutputSize; extern const int8_t kHiddenGruWeights[kHiddenLayerWeights]; extern const int8_t kHiddenGruRecurrentWeights[kHiddenLayerWeights]; extern const int8_t kHiddenGruBias[kHiddenLayerBiases]; // Output layer (dense). const size_t kOutputLayerOutputSize = 1; const size_t kOutputLayerWeights = kHiddenLayerOutputSize * kOutputLayerOutputSize; extern const int8_t kOutputDenseWeights[kOutputLayerWeights]; extern const int8_t kOutputDenseBias[kOutputLayerOutputSize]; } // namespace rnnoise #endif // THIRD_PARTY_RNNOISE_SRC_RNN_VAD_WEIGHTS_H_