diff options
author | Jean-Marc Valin <Jean-Marc.Valin@csiro.au> | 2007-05-04 09:11:18 +0400 |
---|---|---|
committer | Jean-Marc Valin <Jean-Marc.Valin@csiro.au> | 2008-05-19 08:53:14 +0400 |
commit | 3d7a6f0bd0a60145d8ac3a2f4037da623f407fba (patch) | |
tree | f90d32540ec3269ef8a405a2e97daaf2f83ffcab | |
parent | 6bd022014a21ecca9c27d6041397009a5933ac39 (diff) | |
parent | d2cddf7e2f3c1a75265c43cabaa391037c830745 (diff) |
Big update in the multi-channel AEC to bring it up-to-date with the single
channel AEC. Mainly this means:
1) dual-path adaptive filter
2) Adaptive (pseudo-proportional) learning rate for different taps
3) API change
4) Other minor details
Merge commit 'd2cddf7e2f3c1a75265c43cabaa391037c830745' into stereo
Conflicts:
include/speex/speex_echo.h
libspeex/mdf.c
libspeex/testecho.c
107 files changed, 17232 insertions, 4636 deletions
@@ -1,4 +1,4 @@ -Copyright 2002-2006 +Copyright 2002-2007 Xiph.org Foundation Jean-Marc Valin David Rowe @@ -1,1218 +1,225 @@ -# Doxyfile 1.4.2 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") +# Doxyfile 1.5.1-KDevelop #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - PROJECT_NAME = Speex - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = 1.2-beta1 - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - +PROJECT_NUMBER = 1.2-beta2 OUTPUT_DIRECTORY = doc - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, -# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, -# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, -# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, -# Swedish, and Ukrainian. - OUTPUT_LANGUAGE = English - -# This tag can be used to specify the encoding used in the generated output. -# The encoding is not always determined by the language that is chosen, -# but also whether or not the output is meant for Windows or non-Windows users. -# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES -# forces the Windows encoding (this is the default for the Windows binary), -# whereas setting the tag to NO uses a Unix-style encoding (the default for -# all platforms other than Windows). - USE_WINDOWS_ENCODING = NO - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - FULL_PATH_NAMES = NO - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like the Qt-style comments (thus requiring an -# explicit @brief command for a brief description. - JAVADOC_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - MULTILINE_CPP_IS_BRIEF = NO - -# If the DETAILS_AT_TOP tag is set to YES then Doxygen -# will output the detailed description near the top, like JavaDoc. -# If set to NO, the detailed description appears after the member -# documentation. - DETAILS_AT_TOP = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - INHERIT_DOCS = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - TAB_SIZE = 8 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources -# only. Doxygen will then generate output that is more tailored for Java. -# For instance, namespaces will be presented as packages, qualified scopes -# will look different, etc. - OPTIMIZE_OUTPUT_JAVA = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - +BUILTIN_STL_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES - #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - EXTRACT_ALL = NO - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - EXTRACT_PRIVATE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - EXTRACT_LOCAL_METHODS = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - SHOW_INCLUDE_FILES = YES - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - SORT_BRIEF_DOCS = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - SORT_BY_SCOPE_NAME = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - SHOW_USED_FILES = YES - -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. - SHOW_DIRECTORIES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from the -# version control system). Doxygen will invoke the program by executing (via -# popen()) the command <command> <input-file>, where <command> is the value of -# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file -# provided by doxygen. Whatever the progam writes to standard output -# is used as the file version. See the manual for examples. - FILE_VERSION_FILTER = - #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - WARN_LOGFILE = - #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = include/speex # libspeex - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm - +INPUT = include/speex FILE_PATTERNS = - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - RECURSIVE = NO - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded -# from the input. - +EXCLUDE = EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. - EXCLUDE_PATTERNS = speex_config_types.h - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command <filter> <input-file>, where <filter> -# is the value of the INPUT_FILTER tag, and <input-file> is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be -# ignored. - INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. - FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - FILTER_SOURCE_FILES = NO - #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES (the default) -# then for each documented function all documented -# functions referencing it will be listed. - REFERENCED_BY_RELATION = YES - -# If the REFERENCES_RELATION tag is set to YES (the default) -# then for each documented function all documented entities -# called/used by that function will be listed. - REFERENCES_RELATION = YES - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO VERBATIM_HEADERS = YES - #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - ALPHABETICAL_INDEX = NO - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - IGNORE_PREFIX = - #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - HTML_STYLESHEET = - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - HTML_ALIGN_MEMBERS = YES - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) -# of the generated HTML documentation. - GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - TOC_EXPAND = NO - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - ENUM_VALUES_PER_LINE = 4 - -# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be -# generated containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. - GENERATE_TREEVIEW = NO - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - TREEVIEW_WIDTH = 250 - #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - GENERATE_LATEX = YES - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. - LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - LATEX_HIDE_INDICES = NO - #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - RTF_EXTENSIONS_FILE = - #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - MAN_LINKS = NO - #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - XML_PROGRAMLISTING = YES - #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - GENERATE_AUTOGEN_DEF = NO - #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - PERLMOD_MAKEVAR_PREFIX = - #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_PREDEFINED tags. - EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. - SKIP_FUNCTION_MACROS = YES - #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - PERL_PATH = /usr/bin/perl - #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. - CLASS_DIAGRAMS = YES - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - HAVE_DOT = NO - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - TEMPLATE_RELATIONS = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will -# generate a call dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. - CALL_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - +CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - DOT_IMAGE_FORMAT = gif - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - DOTFILE_DIRS = - -# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width -# (in pixels) of the graphs generated by dot. If a graph becomes larger than -# this value, doxygen will try to truncate the graph, so that it fits within -# the specified constraint. Beware that most browsers cannot cope with very -# large images. - MAX_DOT_GRAPH_WIDTH = 1024 - -# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height -# (in pixels) of the graphs generated by dot. If a graph becomes larger than -# this value, doxygen will try to truncate the graph, so that it fits within -# the specified constraint. Beware that most browsers cannot cope with very -# large images. - MAX_DOT_GRAPH_HEIGHT = 1024 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that a graph may be further truncated if the graph's -# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH -# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), -# the graph is not depth-constrained. - MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, which results in a white background. -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). - DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - DOT_CLEANUP = YES - #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - SEARCHENGINE = NO diff --git a/README.Trimedia b/README.Trimedia new file mode 100644 index 0000000..c2db8dc --- /dev/null +++ b/README.Trimedia @@ -0,0 +1,191 @@ +################# REMOVE warnings on trimedia compiler ##############################
+################# Not critical to compilation ##############################
+
+1. Change the following statements to remove warning for constant expression
+(i) mdf.c [if(0) --> #if 0]
+(ii) ltp.c [if(1) --> #if 1]
+(iii) preprocess.c [if(1) --> #if 1]
+(iv) sb_celp.c [if (SPEEX_SET_VBR_MAX_BITRATE<1) --> #if (SPEEX_SET_VBR_MAX_BITRATE<1)]
+
+2. add REMARK_ON macro to remove warning on not reference variable
+-- uses (void)<variable> to remove warning on not referenced variable
+-- #define REMARK_ON
+-- (void)<variable>
+-- #endif
+-- search for REMARK_ON on the following files
+(i) jitter.c
+(ii) lsp.c
+(iii) ltp.c
+(iv) mdf.c
+(v) filters.c
+(vi) filterbank.c
+(vii) cb_search.c
+(viii) vq.c
+(ix) vbr.c
+(x) stereo.c
+(xi) speex_callbacks.c
+(xii) preprocess.c
+
+3. commented out the following in pseudofloat.h for unused variable
+//static const spx_float_t FLOAT_HALF = {16384,-15};
+
+4. commented out unused variable in nb_celp.c
+//spx_word16_t *sp; ***unused variable***
+//sp=out+offset; ***unused variable***
+//int submode; ***unused variable***
+// ***unused variable***
+// advance = submode = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS);
+advance = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS);
+// ***unused variable***
+//advance = submode = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS);
+advance = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS);
+// spx_word16_t *exc; ***unused variable***
+// exc=st->exc+offset; ***unused variable***
+
+5. commented out unused variable in vbr.c
+//int va; ***unused variable***
+//va = 0; ***unused variable***
+//va = 1; ***unused variable***
+
+6. added HAVE_CONFIG into medfilter.c
+
+################# Patches for trimedia compiler ##############################
+################# Critical to compilation ##############################
+-- change the following in modes.c and speex.h as compiler does not support const * const...
+(i) modes.c
+#ifdef __TCS__
+const SpeexMode * speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, &speex_uwb_mode};
+#else
+const SpeexMode * const speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, &speex_uwb_mode};
+#endif
+
+(ii) speex.h
+#ifdef __TCS__
+extern const SpeexMode * speex_mode_list[SPEEX_NB_MODES];
+#else
+extern const SpeexMode * const speex_mode_list[SPEEX_NB_MODES];
+#endif
+
+-- added the #elif defined (TM_ASM) to the following files for optimized codes
+(1) arch.h
+(2) cb_search.c
+(3) fftwrap.c
+(4) filterbank.c
+(5) filters.c
+(6) kiss_fft.c
+(7) kiss_fftr.c
+(8) lpc.c
+(9) lsp.c
+(10) ltp.c
+(11) mdf.c
+(12) misc.c
+(13) preprocess.c
+(14) quant_lsp.c
+(15) vq.c
+
+-- reorder macro definations in quant_lsp.c
+#ifdef FIXED_POINT
+
+#define LSP_LINEAR(i) (SHL16(i+1,11))
+#define LSP_LINEAR_HIGH(i) (ADD16(MULT16_16_16(i,2560),6144))
+#define LSP_DIV_256(x) (SHL16((spx_word16_t)x, 5))
+#define LSP_DIV_512(x) (SHL16((spx_word16_t)x, 4))
+#define LSP_DIV_1024(x) (SHL16((spx_word16_t)x, 3))
+#define LSP_PI 25736
+
+#else
+
+#define LSP_LINEAR(i) (.25*(i)+.25)
+#define LSP_LINEAR_HIGH(i) (.3125*(i)+.75)
+#define LSP_SCALE 256.
+#define LSP_DIV_256(x) (0.0039062*(x))
+#define LSP_DIV_512(x) (0.0019531*(x))
+#define LSP_DIV_1024(x) (0.00097656*(x))
+#define LSP_PI M_PI
+
+#endif
+
+#ifdef BFIN_ASM
+#include "quant_lsp_bfin.h"
+#elif defined (TM_ASM)
+#include "quant_lsp_tm.h"
+#endif
+
+-- added macro PREPROCESS_MDF_FLOAT to allow using of floating point
+-- in mdf and preprocess while keeping fixed point in encoder/decoder
+-- This is due to the fact that preprocess/mdf run faster on floating
+-- point on trimedia
+-- added the following 3 lines to the files below
+#ifdef PREPROCESS_MDF_FLOAT
+#undef FIXED_POINT
+#endif
+(1) mdf.c
+(2) preprocess.c
+(3) filterbank.c
+(4) fftwrap.c
+(5) kiss_fft.c
+(6) kiss_fftr.c
+
+-- created a new USE_COMPACT_KISS_FFT for fftwrap.c and shifted defination
+-- to config file so that user configure the usage of fft on config.h
+-- TOEXPLORE:is it possible to share table between mdf/preprocess?
+-- Introducing this macro made the following changes in C code
+-- New macro to facilitate integration
+(grouping real/complex for dc and nyquist frequency seems to require a large
+amount of memory for mdf, therefore did not made the changes for that)
+(1) modify preprocess.c on init and destroy
+(2) modify mdf.c on init and destroy
+(3) shifted power_spectrum to fftwrap.c to share optimised code between
+ preprocess.c and mdf.c
+
+################# NOTES ##############################
+(1) fixed point encoding/decoding is tested on narrowband
+ - some of the QX fractions are packed together to
+ (frac1 * a + frac2 * a) >> X (should be more accurate in rounding)
+ instead of
+ ((frac1 * a) >> X) + ((frac2 * a) >> X)
+ will cause some different between optimized and unoptimized code.
+ tried decoding/encoding optimized code on some audio files retains
+ the clearity of the word
+
+ - wideband/ultrawideband is not heavily tested yet
+
+(2) optimized fixed point code requires memory alignment
+ - used config to debug on functions where memory is not align
+
+(3) floating point optimization for preprocess/mdf is tested
+ fixed point is not tested yet (except fft/filterbank)
+ Note (1) also applies to sround in fft for fixed point
+ some optimization is provided for fixed point as it requires lesser
+ memory compared to floating point.
+
+(4) unroll configurations provided to reduce code size if required
+
+(5) use profile options only if compiler profiling fails to work
+
+(6) can't include the makefile as it is close proprietary
+
+################# TODO:For Trimedia ##############################
+(1) Possible add TSSA wrapper for codec but don't think this can be open source.
+(2) Optimizations for fixed point in mdf/preprocess
+
+################# Added Files ##############################
+- _kiss_fft_guts_tm.h
+- cb_search_tm.h
+- fftwrap_tm.h
+- filterbank_tm.h
+- filters_tm.h
+- fixed_tm.h
+- kiss_fft_tm.h
+- kiss_fftr_tm.h
+- lpc_tm.h
+- lsp_tm.h
+- ltp_tm.h
+- mdf_tm.h
+- misc_tm.h
+- preprocess_tm.h
+- profile_tm.h
+- quant_lsp_tm.h
+- vq_tm.h
+- config.h
+- speex_config_types.h
diff --git a/Speex.kdevelop b/Speex.kdevelop index e4e0749..46524c4 100644 --- a/Speex.kdevelop +++ b/Speex.kdevelop @@ -9,8 +9,11 @@ <ignoreparts/> <projectdirectory>.</projectdirectory> <absoluteprojectpath>false</absoluteprojectpath> - <description/> + <description></description> <secondaryLanguages/> + <versioncontrol>kdevsubversion</versioncontrol> + <defaultencoding></defaultencoding> + <projectname>Speex</projectname> </general> <kdevautoproject> <general> @@ -25,6 +28,8 @@ <terminal>false</terminal> <autocompile>true</autocompile> <envvars/> + <autoinstall>false</autoinstall> + <autokdesu>false</autokdesu> </run> <configurations> <optimized> @@ -42,6 +47,9 @@ <f77compiler>G77Options</f77compiler> <cflags>-O0 -g3</cflags> </debug> + <default> + <envvars/> + </default> </configurations> <make> <envvars> @@ -49,19 +57,21 @@ <envvar value="1" name="WANT_AUTOMAKE_1_6" /> </envvars> <abortonerror>false</abortonerror> - <numberofjobs>1</numberofjobs> + <numberofjobs>4</numberofjobs> <dontact>false</dontact> <makebin/> + <runmultiplejobs>true</runmultiplejobs> + <prio>0</prio> </make> </kdevautoproject> <kdevdebugger> <general> <dbgshell>libtool</dbgshell> <programargs/> - <gdbpath/> - <configGdbScript/> - <runShellScript/> - <runGdbScript/> + <gdbpath></gdbpath> + <configGdbScript></configGdbScript> + <runShellScript></runShellScript> + <runGdbScript></runGdbScript> <breakonloadinglibs>true</breakonloadinglibs> <separatetty>false</separatetty> <floatingtoolbar>false</floatingtoolbar> @@ -69,6 +79,7 @@ <display> <staticmembers>false</staticmembers> <demanglenames>true</demanglenames> + <outputradix>10</outputradix> </display> </kdevdebugger> <kdevfilecreate> @@ -88,10 +99,48 @@ <automaticCodeCompletion>true</automaticCodeCompletion> <automaticArgumentsHint>true</automaticArgumentsHint> <automaticHeaderCompletion>true</automaticHeaderCompletion> - <codeCompletionDelay>250</codeCompletionDelay> + <codeCompletionDelay>350</codeCompletionDelay> <argumentsHintDelay>400</argumentsHintDelay> <headerCompletionDelay>250</headerCompletionDelay> + <showOnlyAccessibleItems>false</showOnlyAccessibleItems> + <completionBoxItemOrder>0</completionBoxItemOrder> + <howEvaluationContextMenu>true</howEvaluationContextMenu> + <showCommentWithArgumentHint>true</showCommentWithArgumentHint> + <statusBarTypeEvaluation>false</statusBarTypeEvaluation> + <namespaceAliases>std=_GLIBCXX_STD;__gnu_cxx=std</namespaceAliases> + <processPrimaryTypes>true</processPrimaryTypes> + <processFunctionArguments>true</processFunctionArguments> + <preProcessAllHeaders>false</preProcessAllHeaders> + <parseMissingHeaders>false</parseMissingHeaders> + <resolveIncludePaths>true</resolveIncludePaths> + <alwaysParseInBackground>true</alwaysParseInBackground> + <usePermanentCaching>true</usePermanentCaching> + <alwaysIncludeNamespaces>true</alwaysIncludeNamespaces> + <includePaths>.;</includePaths> </codecompletion> + <qt> + <used>false</used> + <version>3</version> + <root>/usr/share/qt3</root> + <includestyle>3</includestyle> + <designerintegration>EmbeddedKDevDesigner</designerintegration> + <qmake>/usr/share/qt3/bin/qmake</qmake> + <designer></designer> + <designerpluginpaths/> + </qt> + <creategettersetter> + <prefixGet></prefixGet> + <prefixSet>set</prefixSet> + <prefixVariable>m_,_</prefixVariable> + <parameterName>theValue</parameterName> + <inlineGet>true</inlineGet> + <inlineSet>true</inlineSet> + </creategettersetter> + <splitheadersource> + <enabled>true</enabled> + <synchronize>true</synchronize> + <orientation>Horizontal</orientation> + </splitheadersource> </kdevcppsupport> <kdevfileview> <groups> @@ -101,6 +150,7 @@ <tree> <hidepatterns>*.o,*.lo,CVS</hidepatterns> <hidenonprojectfiles>true</hidenonprojectfiles> + <showvcsfields>false</showvcsfields> </tree> </kdevfileview> <kdevdoctreeview> @@ -120,4 +170,11 @@ <implementationsuffix>.cpp</implementationsuffix> </filetemplates> </cppsupportpart> + <kdevdocumentation> + <projectdoc> + <docsystem/> + <docurl/> + <usermanualurl/> + </projectdoc> + </kdevdocumentation> </kdevelop> @@ -1,39 +1,49 @@ -For 1.1.13: -Input buffer in new enhancer -(remove the if's in loops in interp_pitch()) -Fix --force-nb -Fix wideband PLC -change filter structure in vorbis-psy (use the numerator=LPC version) -Fix overflow in mdf +For 1.2beta2: +*Use full complex values for fft results? +*get rid of crap that shouldn't be exposed in speex.h +*Reduce wideband RAM requirements +*Make foreground filter 16 bits in AEC. +*Enable resampler in build +*Add dumping of data for debug purposes. +*remove wideband pseudo-stack +*pitch prediction saturation to prevent NaN-based DoS attacks. +*Fix jitter buffer + +speex_decoder_ctl() call to detect silence +Complete resampler API (error codes) +Fix resampler corner case +Use lower sinc oversampling when down-sampling +**Fix register issue on Blackfin +Merge TriMedia stuff +Make it possible to decode a "raw" packet with SpeexBits +Control delay in new AEC API. Later: -use 16-bit version of the filters in ltp.c -get rid of crap that shouldn't be exposed in speex.h +Do VAD properly +Warning/error handling +--enable-{aec,preprocessor,jitter,resampler} + + +Optimisations +- Add restrict in a few places? +- enable 4x4 version of pitch_xcorr()? Would be nice: +Implement wideband split as IIR instead of QMF. -Allocator override (speex_lib_ctl) +Allocator override (speex_lib_ctl?) Better error handling Fixed-point: - Wideband - - Initialization - Jitter buffer Denoiser: - - Smooth gain (remove musical noise) - Better noise adaptation - - Do some tuning AGC: - - Use median filtering instead of "non-linear mean" - - + - Use median filtering instead of "non-linear mean"? Features --Add maximum/minimum bit-rate control for VBR -Improve error handling (with perror-like call?) -Long-term quality improvements --Improve perceptual enhancement (including wideband) - Standards -Complete Speex RTP profile -MIME type registration @@ -41,4 +51,3 @@ Standards ideas: Peelable stream (double codebook, higher bands, stereo) LPC from spectral domain -Better psycho-acoustic model. Masking curve from Vorbis? @@ -25,20 +25,25 @@ VERSIONMKINT="sed -e s/[^0-9]//" # do we need automake? if test -r Makefile.am; then - AM_NEEDED=`fgrep AUTOMAKE_OPTIONS Makefile.am | $VERSIONGREP` + AM_OPTIONS=`fgrep AUTOMAKE_OPTIONS Makefile.am` + AM_NEEDED=`echo $AM_OPTIONS | $VERSIONGREP` + if test x"$AM_NEEDED" = "x$AM_OPTIONS"; then + AM_NEEDED="" + fi if test -z $AM_NEEDED; then echo -n "checking for automake... " AUTOMAKE=automake ACLOCAL=aclocal if ($AUTOMAKE --version < /dev/null > /dev/null 2>&1); then + echo "yes" + else echo "no" AUTOMAKE= - else - echo "yes" fi else echo -n "checking for automake $AM_NEEDED or later... " - for am in automake-$AM_NEEDED automake$AM_NEEDED automake; do + for am in automake-$AM_NEEDED automake$AM_NEEDED \ + automake automake-1.7 automake-1.8 automake-1.9; do ($am --version < /dev/null > /dev/null 2>&1) || continue ver=`$am --version < /dev/null | head -n 1 | $VERSIONGREP | $VERSIONMKINT` verneeded=`echo $AM_NEEDED | $VERSIONMKINT` @@ -50,7 +55,8 @@ if test -r Makefile.am; then done test -z $AUTOMAKE && echo "no" echo -n "checking for aclocal $AM_NEEDED or later... " - for ac in aclocal-$AM_NEEDED aclocal$AM_NEEDED aclocal; do + for ac in aclocal-$AM_NEEDED aclocal$AM_NEEDED \ + aclocal aclocal-1.7 aclocal-1.8 aclocal-1.9; do ($ac --version < /dev/null > /dev/null 2>&1) || continue ver=`$ac --version < /dev/null | head -n 1 | $VERSIONGREP | $VERSIONMKINT` verneeded=`echo $AM_NEEDED | $VERSIONMKINT` @@ -103,10 +109,10 @@ echo "Generating configuration files for $package, please wait...." echo " $ACLOCAL $ACLOCAL_FLAGS" $ACLOCAL $ACLOCAL_FLAGS || exit 1 -echo " autoheader" -autoheader || exit 1 echo " $LIBTOOLIZE --automake" $LIBTOOLIZE --automake || exit 1 +echo " autoheader" +autoheader || exit 1 echo " $AUTOMAKE --add-missing $AUTOMAKE_FLAGS" $AUTOMAKE --add-missing $AUTOMAKE_FLAGS || exit 1 echo " autoconf" diff --git a/configure.ac b/configure.ac index 4ae40fc..114eef0 100644 --- a/configure.ac +++ b/configure.ac @@ -6,15 +6,15 @@ AM_CONFIG_HEADER([config.h]) SPEEX_MAJOR_VERSION=1 SPEEX_MINOR_VERSION=1 -SPEEX_MICRO_VERSION=13 -SPEEX_EXTRA_VERSION= +SPEEX_MICRO_VERSION=14 +SPEEX_EXTRA_VERSION=-svn #SPEEX_VERSION= SPEEX_VERSION=$SPEEX_MAJOR_VERSION.$SPEEX_MINOR_VERSION.$SPEEX_MICRO_VERSION$SPEEX_EXTRA_VERSION -SPEEX_VERSION="1.2-beta1" +#SPEEX_VERSION="1.2beta1" -SPEEX_LT_CURRENT=3 +SPEEX_LT_CURRENT=5 SPEEX_LT_REVISION=0 -SPEEX_LT_AGE=2 +SPEEX_LT_AGE=4 AC_SUBST(SPEEX_LT_CURRENT) AC_SUBST(SPEEX_LT_REVISION) @@ -94,9 +94,9 @@ AC_ARG_ENABLE(wideband, [ --disable-wideband Disable wideband codec], AC_DEFINE([DISABLE_WIDEBAND], , [Disable wideband codec]) fi]) -AC_ARG_ENABLE(vorbis-psy, [ --enable-vorbis-psy Enable Vorbis-style psychoacoustics], +AC_ARG_ENABLE(vorbis-psy, [ --enable-vorbis-psy Enable Vorbis-style psychoacoustics (EXPERIMENTAL)], [if test "$enableval" = yes; then - AC_DEFINE([VORBIS_PSYCHO], , [Enable Vorbis-style psychoacoustics]) + AC_DEFINE([VORBIS_PSYCHO], , [Enable Vorbis-style psychoacoustics (EXPERIMENTAL)]) fi]) AC_ARG_ENABLE(valgrind, [ --enable-valgrind Enable valgrind extra checks], diff --git a/doc/echo_path.eps b/doc/echo_path.eps new file mode 100644 index 0000000..c5a458c --- /dev/null +++ b/doc/echo_path.eps @@ -0,0 +1,1298 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%BoundingBox: 0 0 415 235 +%%Pages: 0 +%%Creator: Sun Microsystems, Inc. +%%Title: none +%%CreationDate: none +%%LanguageLevel: 2 +%%EndComments +%%BeginProlog +%%BeginResource: procset SDRes-Prolog 1.0 0 +/b4_inc_state save def +/dict_count countdictstack def +/op_count count 1 sub def +userdict begin +0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit[] 0 setdash newpath +/languagelevel where {pop languagelevel 1 ne {false setstrokeadjust false setoverprint} if} if +/bdef {bind def} bind def +/c {setgray} bdef +/l {neg lineto} bdef +/rl {neg rlineto} bdef +/lc {setlinecap} bdef +/lj {setlinejoin} bdef +/lw {setlinewidth} bdef +/ml {setmiterlimit} bdef +/ld {setdash} bdef +/m {neg moveto} bdef +/ct {6 2 roll neg 6 2 roll neg 6 2 roll neg curveto} bdef +/r {rotate} bdef +/t {neg translate} bdef +/s {scale} bdef +/sw {show} bdef +/gs {gsave} bdef +/gr {grestore} bdef +/f {findfont dup length dict begin +{1 index /FID ne {def} {pop pop} ifelse} forall /Encoding ISOLatin1Encoding def +currentdict end /NFont exch definefont pop /NFont findfont} bdef +/p {closepath} bdef +/sf {scalefont setfont} bdef +/ef {eofill}bdef +/pc {closepath stroke}bdef +/ps {stroke}bdef +/pum {matrix currentmatrix}bdef +/pom {setmatrix}bdef +/bs {/aString exch def /nXOfs exch def /nWidth exch def currentpoint nXOfs 0 rmoveto pum nWidth aString stringwidth pop div 1 scale aString show pom moveto} bdef +%%EndResource +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%EndPageSetup +pum +0.02836 0.02836 s +0 -8286 t +/tm matrix currentmatrix def +tm setmatrix +-3900 -8857 t +1 1 s +0.000 c 10000 12000 m 9581 12419 l 9413 12084 l 10000 12000 l p ef +6989 13478 m 9586 12179 l 9609 12224 l 7011 13522 l 6989 13478 l p ef +0.996 c 8500 13800 m 7500 13800 l 7500 11800 l 9500 11800 l 9500 13800 l +8500 13800 l p ef +50 lw 1 lj 0.000 c 8500 13800 m 7500 13800 l 7500 11800 l 9500 11800 l +9500 13800 l 8500 13800 l pc +gs +gs +pum +8080 12960 t +103 -334 m 103 -334 103 -334 8 -334 ct 8 -334 8 -334 8 -323 ct 31 -318 34 -314 34 -294 ct +34 -294 34 -294 34 -42 ct 34 -21 30 -16 8 -12 ct 8 -12 8 -12 8 0 ct 8 0 8 0 127 0 ct +127 0 127 0 127 -12 ct 109 -14 103 -22 103 -40 ct 103 -40 103 -40 103 -172 ct 103 -174 106 -179 111 -184 ct +122 -195 134 -201 145 -201 ct 163 -201 171 -188 171 -160 ct 171 -160 171 -160 171 -40 ct +171 -22 165 -14 148 -12 ct 148 -12 148 -12 148 0 ct 148 0 148 0 264 0 ct 264 0 264 0 264 -12 ct +246 -13 240 -21 240 -42 ct 240 -42 240 -42 240 -164 ct 240 -207 213 -234 173 -234 ct +147 -234 128 -224 103 -195 ct 103 -195 103 -195 103 -334 ct p ef +pom +gr +gs +pum +8351 12960 t +143 -334 m 107 -310 92 -297 75 -274 ct 40 -231 23 -182 23 -124 ct 23 -62 41 -13 84 37 ct +104 61 116 72 141 87 ct 141 87 141 87 147 79 ct 108 48 95 31 82 -6 ct 70 -39 65 -76 65 -126 ct +65 -178 71 -218 84 -249 ct 98 -279 112 -297 147 -326 ct 147 -326 147 -326 143 -334 ct +p ef +pom +gr +gs +pum +8516 12960 t +227 -58 m 227 -58 227 -58 217 -45 ct 203 -27 194 -19 187 -19 ct 183 -19 179 -23 179 -27 ct +179 -31 179 -31 186 -58 ct 186 -58 186 -58 214 -160 ct 216 -170 218 -181 218 -188 ct +218 -206 205 -218 186 -218 ct 154 -218 123 -189 72 -110 ct 72 -110 72 -110 105 -217 ct +105 -217 105 -217 104 -218 ct 77 -213 67 -211 24 -203 ct 24 -203 24 -203 24 -195 ct +49 -195 55 -192 55 -182 ct 55 -179 55 -176 54 -173 ct 54 -173 54 -173 7 0 ct 7 0 7 0 44 0 ct +67 -78 72 -89 93 -123 ct 123 -168 148 -193 166 -193 ct 174 -193 178 -188 178 -179 ct +178 -173 175 -156 171 -141 ct 171 -141 171 -141 150 -60 ct 143 -35 142 -28 142 -23 ct +142 -4 149 4 165 4 ct 187 4 200 -6 234 -52 ct 234 -52 234 -52 227 -58 ct p ef +pom +gr +gs +pum +8766 12960 t +18 87 m 54 64 69 51 87 28 ct 121 -15 138 -64 138 -122 ct 138 -185 120 -233 77 -283 ct +58 -307 45 -318 20 -334 ct 20 -334 20 -334 14 -326 ct 53 -295 66 -277 79 -240 ct +91 -207 96 -170 96 -120 ct 96 -69 90 -28 77 2 ct 63 33 49 51 14 79 ct 14 79 14 79 18 87 ct +p ef +pom +gr +gr +14100 16000 m 13824 16000 13600 15776 13600 15500 ct 13600 15224 13824 15000 14100 15000 ct +14376 15000 14600 15224 14600 15500 ct 14600 15776 14376 16000 14100 16000 ct +pc +gs +gs +pum +13954 15668 t +121 -141 m 15 -141 l 15 -108 l 121 -108 l 121 0 l 153 0 l 153 -108 l +259 -108 l 259 -141 l 153 -141 l 153 -250 l 121 -250 l 121 -141 l +p ef +pom +gr +gr +8500 16000 m 8224 16000 8000 15776 8000 15500 ct 8000 15224 8224 15000 8500 15000 ct +8776 15000 9000 15224 9000 15500 ct 9000 15776 8776 16000 8500 16000 ct pc +8500 15000 m 8313 14438 l 8688 14438 l 8500 15000 l p ef +8525 13800 m 8525 14550 l 8475 14550 l 8475 13800 l 8525 13800 l p ef +9000 15500 m 9563 15313 l 9563 15688 l 9000 15500 l p ef +13600 15525 m 9450 15525 l 9450 15475 l 13600 15475 l 13600 15525 l +p ef +14100 13800 m 13100 13800 l 13100 11800 l 15100 11800 l 15100 13800 l +14100 13800 l pc +gs +gs +pum +13663 12960 t +103 -334 m 103 -334 103 -334 8 -334 ct 8 -334 8 -334 8 -323 ct 31 -318 34 -314 34 -294 ct +34 -294 34 -294 34 -42 ct 34 -21 30 -16 8 -12 ct 8 -12 8 -12 8 0 ct 8 0 8 0 127 0 ct +127 0 127 0 127 -12 ct 109 -14 103 -22 103 -40 ct 103 -40 103 -40 103 -172 ct 103 -174 106 -179 111 -184 ct +122 -195 134 -201 145 -201 ct 163 -201 171 -188 171 -160 ct 171 -160 171 -160 171 -40 ct +171 -22 165 -14 148 -12 ct 148 -12 148 -12 148 0 ct 148 0 148 0 264 0 ct 264 0 264 0 264 -12 ct +246 -13 240 -21 240 -42 ct 240 -42 240 -42 240 -164 ct 240 -207 213 -234 173 -234 ct +147 -234 128 -224 103 -195 ct 103 -195 103 -195 103 -334 ct p ef +pom +gr +gs +pum +13934 12960 t +143 -334 m 107 -310 92 -297 75 -274 ct 40 -231 23 -182 23 -124 ct 23 -62 41 -13 84 37 ct +104 61 116 72 141 87 ct 141 87 141 87 147 79 ct 108 48 95 31 82 -6 ct 70 -39 65 -76 65 -126 ct +65 -178 71 -218 84 -249 ct 98 -279 112 -297 147 -326 ct 147 -326 147 -326 143 -334 ct +p ef +pom +gr +gs +pum +14099 12960 t +227 -58 m 227 -58 227 -58 217 -45 ct 203 -27 194 -19 187 -19 ct 183 -19 179 -23 179 -27 ct +179 -31 179 -31 186 -58 ct 186 -58 186 -58 214 -160 ct 216 -170 218 -181 218 -188 ct +218 -206 205 -218 186 -218 ct 154 -218 123 -189 72 -110 ct 72 -110 72 -110 105 -217 ct +105 -217 105 -217 104 -218 ct 77 -213 67 -211 24 -203 ct 24 -203 24 -203 24 -195 ct +49 -195 55 -192 55 -182 ct 55 -179 55 -176 54 -173 ct 54 -173 54 -173 7 0 ct 7 0 7 0 44 0 ct +67 -78 72 -89 93 -123 ct 123 -168 148 -193 166 -193 ct 174 -193 178 -188 178 -179 ct +178 -173 175 -156 171 -141 ct 171 -141 171 -141 150 -60 ct 143 -35 142 -28 142 -23 ct +142 -4 149 4 165 4 ct 187 4 200 -6 234 -52 ct 234 -52 234 -52 227 -58 ct p ef +pom +gr +gs +pum +14349 12960 t +18 87 m 54 64 69 51 87 28 ct 121 -15 138 -64 138 -122 ct 138 -185 120 -233 77 -283 ct +58 -307 45 -318 20 -334 ct 20 -334 20 -334 14 -326 ct 53 -295 66 -277 79 -240 ct +91 -207 96 -170 96 -120 ct 96 -69 90 -28 77 2 ct 63 33 49 51 14 79 ct 14 79 14 79 18 87 ct +p ef +pom +gr +gr +14100 15000 m 13913 14438 l 14288 14438 l 14100 15000 l p ef +14125 13800 m 14125 14550 l 14075 14550 l 14075 13800 l 14125 13800 l +p ef +5900 15500 m 6463 15313 l 6463 15688 l 5900 15500 l p ef +8000 15525 m 6350 15525 l 6350 15475 l 8000 15475 l 8000 15525 l p ef +8500 11800 m 8313 11238 l 8688 11238 l 8500 11800 l p ef +5600 10575 m 8500 10575 l 8500 10600 l 8500 10625 l 5600 10625 l 5600 10600 l +5600 10575 l p ef +8500 10600 m 8500 10575 l 8504 10575 l 8509 10577 l 8512 10578 l 8516 10581 l +8519 10584 l 8522 10587 l 8523 10591 l 8525 10596 l 8525 10600 l 8525 10600 l +8500 10600 l p ef +8525 10600 m 8525 11350 l 8500 11350 l 8475 11350 l 8475 10600 l 8500 10600 l +8525 10600 l p ef +14600 15500 m 15163 15313 l 15163 15688 l 14600 15500 l p ef +15900 15525 m 15050 15525 l 15050 15475 l 15900 15475 l 15900 15525 l +p ef +14100 11800 m 13913 11238 l 14288 11238 l 14100 11800 l p ef +5600 10575 m 14100 10575 l 14100 10600 l 14100 10625 l 5600 10625 l +5600 10600 l 5600 10575 l p ef +14100 10600 m 14100 10575 l 14104 10575 l 14109 10577 l 14112 10578 l +14116 10581 l 14119 10584 l 14122 10587 l 14123 10591 l 14125 10596 l +14125 10600 l 14125 10600 l 14100 10600 l p ef +14125 10600 m 14125 11350 l 14100 11350 l 14075 11350 l 14075 10600 l +14100 10600 l 14125 10600 l p ef +7000 15500 m 7000 13500 l ps +gs +gs +pum +16150 15536 t +10 -200 m 16 -200 20 -200 25 -200 ct 44 -200 49 -192 56 -146 ct 61 -112 67 -37 67 -8 ct +67 6 68 9 72 9 ct 84 9 130 -43 180 -114 ct 198 -138 210 -170 210 -189 ct 210 -205 198 -218 183 -218 ct +172 -218 165 -212 165 -201 ct 165 -193 167 -188 176 -180 ct 183 -174 185 -170 185 -165 ct +185 -142 153 -87 118 -50 ct 118 -50 118 -50 102 -35 ct 99 -104 96 -130 89 -167 ct +80 -217 80 -218 75 -218 ct 73 -218 69 -217 65 -216 ct 56 -214 29 -209 10 -206 ct +10 -206 10 -206 10 -200 ct p ef +pom +gr +gs +pum +16370 15536 t +143 -334 m 107 -310 92 -297 75 -274 ct 40 -231 23 -182 23 -124 ct 23 -62 41 -13 84 37 ct +104 61 116 72 141 87 ct 141 87 141 87 147 79 ct 108 48 95 31 82 -6 ct 70 -39 65 -76 65 -126 ct +65 -178 71 -218 84 -249 ct 98 -279 112 -297 147 -326 ct 147 -326 147 -326 143 -334 ct +p ef +pom +gr +gs +pum +16535 15536 t +227 -58 m 227 -58 227 -58 217 -45 ct 203 -27 194 -19 187 -19 ct 183 -19 179 -23 179 -27 ct +179 -31 179 -31 186 -58 ct 186 -58 186 -58 214 -160 ct 216 -170 218 -181 218 -188 ct +218 -206 205 -218 186 -218 ct 154 -218 123 -189 72 -110 ct 72 -110 72 -110 105 -217 ct +105 -217 105 -217 104 -218 ct 77 -213 67 -211 24 -203 ct 24 -203 24 -203 24 -195 ct +49 -195 55 -192 55 -182 ct 55 -179 55 -176 54 -173 ct 54 -173 54 -173 7 0 ct 7 0 7 0 44 0 ct +67 -78 72 -89 93 -123 ct 123 -168 148 -193 166 -193 ct 174 -193 178 -188 178 -179 ct +178 -173 175 -156 171 -141 ct 171 -141 171 -141 150 -60 ct 143 -35 142 -28 142 -23 ct +142 -4 149 4 165 4 ct 187 4 200 -6 234 -52 ct 234 -52 234 -52 227 -58 ct p ef +pom +gr +gs +pum +16785 15536 t +18 87 m 54 64 69 51 87 28 ct 121 -15 138 -64 138 -122 ct 138 -185 120 -233 77 -283 ct +58 -307 45 -318 20 -334 ct 20 -334 20 -334 14 -326 ct 53 -295 66 -277 79 -240 ct +91 -207 96 -170 96 -120 ct 96 -69 90 -28 77 2 ct 63 33 49 51 14 79 ct 14 79 14 79 18 87 ct +p ef +pom +gr +gr +gs +gs +pum +9747 15298 t +229 -55 m 202 -24 197 -20 188 -20 ct 183 -20 179 -24 179 -30 ct 179 -37 195 -97 211 -152 ct +225 -197 235 -237 260 -336 ct 260 -336 260 -336 258 -338 ct 232 -333 214 -330 182 -327 ct +182 -327 182 -327 182 -318 ct 209 -318 213 -316 213 -306 ct 213 -299 212 -296 206 -271 ct +206 -271 206 -271 184 -190 ct 180 -210 171 -218 152 -218 ct 87 -218 7 -125 7 -51 ct +7 -16 27 5 59 5 ct 93 5 115 -11 148 -60 ct 143 -35 142 -27 142 -16 ct 142 -3 150 6 163 6 ct +183 6 209 -14 235 -50 ct 235 -50 235 -50 229 -55 ct p +154 -207 m 168 -207 176 -198 176 -180 ct 176 -104 124 -19 79 -19 ct 62 -19 50 -32 50 -51 ct +50 -92 75 -149 108 -183 ct 122 -198 140 -207 154 -207 ct p ef +pom +gr +gs +pum +9997 15298 t +143 -334 m 107 -310 92 -297 75 -274 ct 40 -231 23 -182 23 -124 ct 23 -62 41 -13 84 37 ct +104 61 116 72 141 87 ct 141 87 141 87 147 79 ct 108 48 95 31 82 -6 ct 70 -39 65 -76 65 -126 ct +65 -178 71 -218 84 -249 ct 98 -279 112 -297 147 -326 ct 147 -326 147 -326 143 -334 ct +p ef +pom +gr +gs +pum +10162 15298 t +227 -58 m 227 -58 227 -58 217 -45 ct 203 -27 194 -19 187 -19 ct 183 -19 179 -23 179 -27 ct +179 -31 179 -31 186 -58 ct 186 -58 186 -58 214 -160 ct 216 -170 218 -181 218 -188 ct +218 -206 205 -218 186 -218 ct 154 -218 123 -189 72 -110 ct 72 -110 72 -110 105 -217 ct +105 -217 105 -217 104 -218 ct 77 -213 67 -211 24 -203 ct 24 -203 24 -203 24 -195 ct +49 -195 55 -192 55 -182 ct 55 -179 55 -176 54 -173 ct 54 -173 54 -173 7 0 ct 7 0 7 0 44 0 ct +67 -78 72 -89 93 -123 ct 123 -168 148 -193 166 -193 ct 174 -193 178 -188 178 -179 ct +178 -173 175 -156 171 -141 ct 171 -141 171 -141 150 -60 ct 143 -35 142 -28 142 -23 ct +142 -4 149 4 165 4 ct 187 4 200 -6 234 -52 ct 234 -52 234 -52 227 -58 ct p ef +pom +gr +gs +pum +10412 15298 t +18 87 m 54 64 69 51 87 28 ct 121 -15 138 -64 138 -122 ct 138 -185 120 -233 77 -283 ct +58 -307 45 -318 20 -334 ct 20 -334 20 -334 14 -326 ct 53 -295 66 -277 79 -240 ct +91 -207 96 -170 96 -120 ct 96 -69 90 -28 77 2 ct 63 33 49 51 14 79 ct 14 79 14 79 18 87 ct +p ef +pom +gr +gr +gs +gs +pum +4561 10747 t +199 -55 m 195 -51 192 -48 188 -42 ct 176 -27 170 -22 165 -22 ct 158 -22 153 -29 150 -42 ct +149 -46 148 -49 148 -51 ct 135 -101 130 -123 130 -131 ct 152 -169 169 -190 178 -190 ct +181 -190 185 -189 190 -186 ct 196 -183 200 -182 204 -182 ct 214 -182 221 -189 221 -200 ct +221 -210 212 -218 201 -218 ct 179 -218 160 -200 126 -147 ct 126 -147 126 -147 121 -175 ct +114 -208 108 -218 95 -218 ct 84 -218 67 -214 37 -204 ct 37 -204 37 -204 32 -202 ct +32 -202 32 -202 34 -194 ct 52 -199 57 -200 61 -200 ct 74 -200 77 -195 83 -166 ct +83 -166 83 -166 98 -105 ct 98 -105 98 -105 57 -47 ct 47 -33 38 -24 32 -24 ct 29 -24 24 -25 19 -28 ct +13 -32 7 -33 3 -33 ct -6 -33 -13 -26 -13 -16 ct -13 -3 -3 5 11 5 ct 27 5 33 1 57 -30 ct +71 -45 81 -59 102 -87 ct 102 -87 102 -87 117 -28 ct 123 -3 129 5 145 5 ct 164 5 177 -7 206 -51 ct +206 -51 206 -51 199 -55 ct p ef +pom +gr +gs +pum +4781 10747 t +143 -334 m 107 -310 92 -297 75 -274 ct 40 -231 23 -182 23 -124 ct 23 -62 41 -13 84 37 ct +104 61 116 72 141 87 ct 141 87 141 87 147 79 ct 108 48 95 31 82 -6 ct 70 -39 65 -76 65 -126 ct +65 -178 71 -218 84 -249 ct 98 -279 112 -297 147 -326 ct 147 -326 147 -326 143 -334 ct +p ef +pom +gr +gs +pum +4946 10747 t +227 -58 m 227 -58 227 -58 217 -45 ct 203 -27 194 -19 187 -19 ct 183 -19 179 -23 179 -27 ct +179 -31 179 -31 186 -58 ct 186 -58 186 -58 214 -160 ct 216 -170 218 -181 218 -188 ct +218 -206 205 -218 186 -218 ct 154 -218 123 -189 72 -110 ct 72 -110 72 -110 105 -217 ct +105 -217 105 -217 104 -218 ct 77 -213 67 -211 24 -203 ct 24 -203 24 -203 24 -195 ct +49 -195 55 -192 55 -182 ct 55 -179 55 -176 54 -173 ct 54 -173 54 -173 7 0 ct 7 0 7 0 44 0 ct +67 -78 72 -89 93 -123 ct 123 -168 148 -193 166 -193 ct 174 -193 178 -188 178 -179 ct +178 -173 175 -156 171 -141 ct 171 -141 171 -141 150 -60 ct 143 -35 142 -28 142 -23 ct +142 -4 149 4 165 4 ct 187 4 200 -6 234 -52 ct 234 -52 234 -52 227 -58 ct p ef +pom +gr +gs +pum +5196 10747 t +18 87 m 54 64 69 51 87 28 ct 121 -15 138 -64 138 -122 ct 138 -185 120 -233 77 -283 ct +58 -307 45 -318 20 -334 ct 20 -334 20 -334 14 -326 ct 53 -295 66 -277 79 -240 ct +91 -207 96 -170 96 -120 ct 96 -69 90 -28 77 2 ct 63 33 49 51 14 79 ct 14 79 14 79 18 87 ct +p ef +pom +gr +gr +gs +gs +pum +4932 15694 t +177 -54 m 141 -25 126 -17 105 -17 ct 77 -17 58 -35 58 -62 ct 58 -69 59 -77 63 -92 ct +63 -92 63 -92 77 -94 ct 151 -105 204 -142 204 -185 ct 204 -206 189 -218 164 -218 ct +93 -218 15 -137 15 -63 ct 15 -23 42 5 81 5 ct 116 5 154 -15 183 -48 ct 183 -48 183 -48 177 -54 ct +p +75 -125 m 92 -169 128 -207 154 -207 ct 164 -207 171 -199 171 -188 ct 171 -172 162 -155 146 -140 ct +128 -123 109 -114 67 -103 ct 67 -103 67 -103 75 -125 ct p ef +pom +gr +gs +pum +5152 15694 t +143 -334 m 107 -310 92 -297 75 -274 ct 40 -231 23 -182 23 -124 ct 23 -62 41 -13 84 37 ct +104 61 116 72 141 87 ct 141 87 141 87 147 79 ct 108 48 95 31 82 -6 ct 70 -39 65 -76 65 -126 ct +65 -178 71 -218 84 -249 ct 98 -279 112 -297 147 -326 ct 147 -326 147 -326 143 -334 ct +p ef +pom +gr +gs +pum +5317 15694 t +227 -58 m 227 -58 227 -58 217 -45 ct 203 -27 194 -19 187 -19 ct 183 -19 179 -23 179 -27 ct +179 -31 179 -31 186 -58 ct 186 -58 186 -58 214 -160 ct 216 -170 218 -181 218 -188 ct +218 -206 205 -218 186 -218 ct 154 -218 123 -189 72 -110 ct 72 -110 72 -110 105 -217 ct +105 -217 105 -217 104 -218 ct 77 -213 67 -211 24 -203 ct 24 -203 24 -203 24 -195 ct +49 -195 55 -192 55 -182 ct 55 -179 55 -176 54 -173 ct 54 -173 54 -173 7 0 ct 7 0 7 0 44 0 ct +67 -78 72 -89 93 -123 ct 123 -168 148 -193 166 -193 ct 174 -193 178 -188 178 -179 ct +178 -173 175 -156 171 -141 ct 171 -141 171 -141 150 -60 ct 143 -35 142 -28 142 -23 ct +142 -4 149 4 165 4 ct 187 4 200 -6 234 -52 ct 234 -52 234 -52 227 -58 ct p ef +pom +gr +gs +pum +5567 15694 t +18 87 m 54 64 69 51 87 28 ct 121 -15 138 -64 138 -122 ct 138 -185 120 -233 77 -283 ct +58 -307 45 -318 20 -334 ct 20 -334 20 -334 14 -326 ct 53 -295 66 -277 79 -240 ct +91 -207 96 -170 96 -120 ct 96 -69 90 -28 77 2 ct 63 33 49 51 14 79 ct 14 79 14 79 18 87 ct +p ef +pom +gr +gr +gs +gs +pum +8954 15959 t +121 -141 m 15 -141 l 15 -108 l 121 -108 l 121 0 l 153 0 l 153 -108 l +259 -108 l 259 -141 l 153 -141 l 153 -250 l 121 -250 l 121 -141 l +p ef +pom +gr +gr +gs +gs +pum +8848 15033 t +19 -127 m 19 -96 l 138 -96 l 138 -127 l 19 -127 l p ef +pom +gr +gr +gs +gs +pum +8080 12705 t +45 -147 m 114 -290 l 183 -147 l 216 -147 l 128 -327 l 99 -327 l 12 -147 l +45 -147 l p ef +pom +gr +gr +0.996 c 12400 9601 m 12394 11602 l 11895 11099 l 11897 10099 l 12400 9601 l +p ef +0.000 c 12400 9601 m 12394 11602 l 11895 11099 l 11897 10099 l 12400 9601 l +pc +0.996 c 11397 10599 m 11398 10099 l 11898 10100 l 11895 11100 l 11395 11099 l +11397 10599 l p ef +0.000 c 11397 10599 m 11398 10099 l 11898 10100 l 11895 11100 l 11395 11099 l +11397 10599 l pc +0.996 c 11900 16000 m 11624 16000 11400 15776 11400 15500 ct 11400 15224 11624 15000 11900 15000 ct +12176 15000 12400 15224 12400 15500 ct 12400 15776 12176 16000 11900 16000 ct +p ef +0.000 c 11900 16000 m 11624 16000 11400 15776 11400 15500 ct 11400 15224 11624 15000 11900 15000 ct +12176 15000 12400 15224 12400 15500 ct 12400 15776 12176 16000 11900 16000 ct +pc +12400 15000 m 12400 16000 l ps +gs +gs +pum +14880 16144 t +8 -196 m 11 -198 15 -198 21 -198 ct 34 -198 39 -191 39 -166 ct 39 -166 39 -166 39 -44 ct +39 -15 33 -8 9 -8 ct 9 -8 9 -8 9 0 ct 9 0 9 0 111 0 ct 111 0 111 0 111 -8 ct 87 -8 79 -14 79 -32 ct +79 -32 79 -32 79 -171 ct 103 -194 113 -200 129 -200 ct 153 -200 165 -184 165 -152 ct +165 -152 165 -152 165 -48 ct 165 -17 158 -8 134 -8 ct 134 -8 134 -8 134 0 ct 134 0 134 0 235 0 ct +235 0 235 0 235 -7 ct 211 -10 205 -16 205 -40 ct 205 -40 205 -40 205 -153 ct 205 -199 184 -227 148 -227 ct +126 -227 111 -219 78 -187 ct 78 -187 78 -187 78 -226 ct 78 -226 78 -226 75 -227 ct +51 -218 34 -213 8 -205 ct 8 -205 8 -205 8 -196 ct p ef +448 -81 m 424 -43 403 -29 372 -29 ct 345 -29 324 -43 310 -72 ct 301 -90 298 -107 297 -137 ct +297 -137 297 -137 446 -137 ct 442 -169 437 -183 425 -199 ct 411 -217 388 -227 363 -227 ct +339 -227 316 -218 298 -201 ct 275 -181 262 -146 262 -106 ct 262 -37 297 5 353 5 ct +399 5 435 -24 455 -78 ct 455 -78 455 -78 448 -81 ct p +298 -153 m 303 -191 320 -209 349 -209 ct 379 -209 390 -196 397 -153 ct 397 -153 397 -153 298 -153 ct +p ef +684 -32 m 676 -26 670 -23 663 -23 ct 652 -23 648 -30 648 -52 ct 648 -52 648 -52 648 -148 ct +648 -173 646 -188 638 -200 ct 628 -218 607 -227 578 -227 ct 533 -227 497 -203 497 -171 ct +497 -160 507 -150 518 -150 ct 530 -150 540 -160 540 -171 ct 540 -173 539 -175 539 -179 ct +538 -183 537 -187 537 -191 ct 537 -204 553 -215 572 -215 ct 596 -215 609 -201 609 -174 ct +609 -174 609 -174 609 -144 ct 534 -113 526 -109 505 -90 ct 495 -81 488 -64 488 -48 ct +488 -17 509 5 539 5 ct 560 5 580 -5 609 -31 ct 612 -5 621 5 640 5 ct 657 5 667 -1 684 -20 ct +684 -20 684 -20 684 -32 ct p +609 -61 m 609 -45 607 -41 596 -35 ct 585 -28 571 -24 561 -24 ct 544 -24 531 -40 531 -62 ct +531 -62 531 -62 531 -63 ct 531 -92 550 -110 609 -132 ct 609 -132 609 -132 609 -61 ct +p ef +693 -192 m 700 -194 705 -194 710 -194 ct 722 -194 727 -186 727 -164 ct 727 -164 727 -164 727 -41 ct +727 -17 723 -13 692 -7 ct 692 -7 692 -7 692 0 ct 692 0 692 0 809 0 ct 809 0 809 0 809 -8 ct +776 -8 767 -15 767 -44 ct 767 -44 767 -44 767 -155 ct 767 -171 788 -196 801 -196 ct +804 -196 809 -193 814 -188 ct 822 -182 827 -179 833 -179 ct 845 -179 852 -187 852 -201 ct +852 -217 842 -227 826 -227 ct 805 -227 791 -216 767 -181 ct 767 -181 767 -181 767 -226 ct +767 -226 767 -226 765 -227 ct 739 -216 722 -210 693 -200 ct 693 -200 693 -200 693 -192 ct +p ef +1176 -81 m 1152 -43 1131 -29 1100 -29 ct 1073 -29 1052 -43 1038 -72 ct 1029 -90 1026 -107 1025 -137 ct +1025 -137 1025 -137 1174 -137 ct 1170 -169 1165 -183 1153 -199 ct 1139 -217 1116 -227 1091 -227 ct +1067 -227 1044 -218 1026 -201 ct 1003 -181 990 -146 990 -106 ct 990 -37 1025 5 1081 5 ct +1127 5 1163 -24 1183 -78 ct 1183 -78 1183 -78 1176 -81 ct p +1026 -153 m 1031 -191 1048 -209 1077 -209 ct 1107 -209 1118 -196 1125 -153 ct +1125 -153 1125 -153 1026 -153 ct p ef +1206 -196 m 1209 -198 1213 -198 1219 -198 ct 1232 -198 1237 -191 1237 -166 ct +1237 -166 1237 -166 1237 -44 ct 1237 -15 1231 -8 1207 -8 ct 1207 -8 1207 -8 1207 0 ct +1207 0 1207 0 1309 0 ct 1309 0 1309 0 1309 -8 ct 1285 -8 1277 -14 1277 -32 ct 1277 -32 1277 -32 1277 -171 ct +1301 -194 1311 -200 1327 -200 ct 1351 -200 1363 -184 1363 -152 ct 1363 -152 1363 -152 1363 -48 ct +1363 -17 1356 -8 1332 -8 ct 1332 -8 1332 -8 1332 0 ct 1332 0 1332 0 1433 0 ct 1433 0 1433 0 1433 -7 ct +1409 -10 1403 -16 1403 -40 ct 1403 -40 1403 -40 1403 -153 ct 1403 -199 1382 -227 1346 -227 ct +1324 -227 1309 -219 1276 -187 ct 1276 -187 1276 -187 1276 -226 ct 1276 -226 1276 -226 1273 -227 ct +1249 -218 1232 -213 1206 -205 ct 1206 -205 1206 -205 1206 -196 ct p ef +1615 5 m 1615 5 1615 5 1686 -21 ct 1686 -21 1686 -21 1686 -28 ct 1677 -28 1676 -28 1675 -28 ct +1657 -28 1653 -33 1653 -56 ct 1653 -56 1653 -56 1653 -336 ct 1653 -336 1653 -336 1651 -337 ct +1628 -329 1611 -324 1580 -315 ct 1580 -315 1580 -315 1580 -308 ct 1584 -308 1586 -308 1590 -308 ct +1608 -308 1613 -303 1613 -283 ct 1613 -283 1613 -283 1613 -206 ct 1594 -222 1581 -227 1562 -227 ct +1506 -227 1461 -171 1461 -101 ct 1461 -38 1497 5 1551 5 ct 1578 5 1596 -5 1613 -28 ct +1613 -28 1613 -28 1613 4 ct 1613 4 1613 4 1615 5 ct p +1613 -50 m 1613 -47 1609 -41 1604 -35 ct 1596 -26 1584 -21 1570 -21 ct 1529 -21 1503 -60 1503 -121 ct +1503 -177 1526 -213 1563 -213 ct 1589 -213 1613 -190 1613 -164 ct 1613 -164 1613 -164 1613 -50 ct +p ef +1973 -155 m 1973 -155 1973 -155 1971 -222 ct 1971 -222 1971 -222 1965 -222 ct +1965 -222 1965 -222 1964 -221 ct 1960 -218 1959 -217 1957 -217 ct 1955 -217 1950 -218 1944 -221 ct +1934 -225 1923 -227 1911 -227 ct 1872 -227 1845 -202 1845 -166 ct 1845 -138 1860 -118 1901 -95 ct +1901 -95 1901 -95 1929 -78 ct 1946 -69 1955 -57 1955 -41 ct 1955 -20 1939 -6 1914 -6 ct +1898 -6 1883 -12 1874 -23 ct 1864 -35 1859 -47 1853 -75 ct 1853 -75 1853 -75 1845 -75 ct +1845 -75 1845 -75 1845 2 ct 1845 2 1845 2 1851 2 ct 1855 -3 1857 -4 1863 -4 ct +1867 -4 1874 -3 1885 0 ct 1898 3 1912 5 1920 5 ct 1957 5 1988 -24 1988 -58 ct 1988 -83 1977 -99 1948 -117 ct +1948 -117 1948 -117 1896 -148 ct 1882 -156 1875 -169 1875 -182 ct 1875 -202 1890 -216 1912 -216 ct +1940 -216 1954 -199 1965 -155 ct 1965 -155 1965 -155 1973 -155 ct p ef +2019 -195 m 2024 -195 2027 -195 2031 -195 ct 2048 -195 2051 -190 2051 -167 ct +2051 -167 2051 -167 2051 65 ct 2051 90 2046 96 2017 99 ct 2017 99 2017 99 2017 107 ct +2017 107 2017 107 2135 107 ct 2135 107 2135 107 2135 98 ct 2098 98 2092 93 2092 61 ct +2092 61 2092 61 2092 -16 ct 2109 0 2121 5 2141 5 ct 2198 5 2243 -50 2243 -122 ct +2243 -183 2209 -227 2162 -227 ct 2135 -227 2113 -215 2092 -189 ct 2092 -189 2092 -189 2092 -226 ct +2092 -226 2092 -226 2089 -227 ct 2063 -217 2046 -210 2019 -202 ct 2019 -202 2019 -202 2019 -195 ct +p +2092 -165 m 2092 -180 2119 -197 2141 -197 ct 2177 -197 2201 -160 2201 -103 ct +2201 -48 2177 -11 2142 -11 ct 2120 -11 2092 -29 2092 -44 ct 2092 -44 2092 -44 2092 -165 ct +p ef +2463 -81 m 2439 -43 2418 -29 2387 -29 ct 2360 -29 2339 -43 2325 -72 ct 2316 -90 2313 -107 2312 -137 ct +2312 -137 2312 -137 2461 -137 ct 2457 -169 2452 -183 2440 -199 ct 2426 -217 2403 -227 2378 -227 ct +2354 -227 2331 -218 2313 -201 ct 2290 -181 2277 -146 2277 -106 ct 2277 -37 2312 5 2368 5 ct +2414 5 2450 -24 2470 -78 ct 2470 -78 2470 -78 2463 -81 ct p +2313 -153 m 2318 -191 2335 -209 2364 -209 ct 2394 -209 2405 -196 2412 -153 ct +2412 -153 2412 -153 2313 -153 ct p ef +2683 -81 m 2659 -43 2638 -29 2607 -29 ct 2580 -29 2559 -43 2545 -72 ct 2536 -90 2533 -107 2532 -137 ct +2532 -137 2532 -137 2681 -137 ct 2677 -169 2672 -183 2660 -199 ct 2646 -217 2623 -227 2598 -227 ct +2574 -227 2551 -218 2533 -201 ct 2510 -181 2497 -146 2497 -106 ct 2497 -37 2532 5 2588 5 ct +2634 5 2670 -24 2690 -78 ct 2690 -78 2690 -78 2683 -81 ct p +2533 -153 m 2538 -191 2555 -209 2584 -209 ct 2614 -209 2625 -196 2632 -153 ct +2632 -153 2632 -153 2533 -153 ct p ef +2898 -77 m 2874 -42 2857 -31 2829 -31 ct 2785 -31 2754 -70 2754 -127 ct 2754 -178 2781 -213 2820 -213 ct +2838 -213 2844 -207 2849 -189 ct 2849 -189 2849 -189 2852 -178 ct 2856 -164 2864 -155 2874 -155 ct +2887 -155 2898 -164 2898 -176 ct 2898 -204 2864 -227 2823 -227 ct 2799 -227 2775 -217 2755 -199 ct +2731 -178 2717 -144 2717 -105 ct 2717 -41 2755 5 2809 5 ct 2831 5 2850 -3 2868 -18 ct +2881 -30 2890 -43 2904 -72 ct 2904 -72 2904 -72 2898 -77 ct p ef +3001 -169 m 3021 -192 3036 -200 3055 -200 ct 3079 -200 3091 -182 3091 -148 ct +3091 -148 3091 -148 3091 -50 ct 3091 -16 3086 -10 3058 -7 ct 3058 -7 3058 -7 3058 0 ct +3058 0 3058 0 3161 0 ct 3161 0 3161 0 3161 -7 ct 3135 -12 3132 -16 3132 -50 ct +3132 -50 3132 -50 3132 -148 ct 3132 -200 3111 -227 3072 -227 ct 3044 -227 3023 -215 3001 -185 ct +3001 -185 3001 -185 3001 -336 ct 3001 -336 3001 -336 2999 -337 ct 2982 -331 2970 -327 2943 -319 ct +2943 -319 2943 -319 2930 -315 ct 2930 -315 2930 -315 2930 -308 ct 2932 -308 2933 -308 2936 -308 ct +2956 -308 2960 -304 2960 -283 ct 2960 -283 2960 -283 2960 -50 ct 2960 -15 2957 -11 2929 -7 ct +2929 -7 2929 -7 2929 0 ct 2929 0 2929 0 3034 0 ct 3034 0 3034 0 3034 -7 ct 3006 -10 3001 -16 3001 -50 ct +3001 -50 3001 -50 3001 -169 ct p ef +pom +gr +gs +pum +15519 16745 t +214 -32 m 206 -26 200 -23 193 -23 ct 182 -23 178 -30 178 -52 ct 178 -52 178 -52 178 -148 ct +178 -173 176 -188 168 -200 ct 158 -218 137 -227 108 -227 ct 63 -227 27 -203 27 -171 ct +27 -160 37 -150 48 -150 ct 60 -150 70 -160 70 -171 ct 70 -173 69 -175 69 -179 ct +68 -183 67 -187 67 -191 ct 67 -204 83 -215 102 -215 ct 126 -215 139 -201 139 -174 ct +139 -174 139 -174 139 -144 ct 64 -113 56 -109 35 -90 ct 25 -81 18 -64 18 -48 ct +18 -17 39 5 69 5 ct 90 5 110 -5 139 -31 ct 142 -5 151 5 170 5 ct 187 5 197 -1 214 -20 ct +214 -20 214 -20 214 -32 ct p +139 -61 m 139 -45 137 -41 126 -35 ct 115 -28 101 -24 91 -24 ct 74 -24 61 -40 61 -62 ct +61 -62 61 -62 61 -63 ct 61 -92 80 -110 139 -132 ct 139 -132 139 -132 139 -61 ct +p ef +228 -196 m 231 -198 235 -198 241 -198 ct 254 -198 259 -191 259 -166 ct 259 -166 259 -166 259 -44 ct +259 -15 253 -8 229 -8 ct 229 -8 229 -8 229 0 ct 229 0 229 0 331 0 ct 331 0 331 0 331 -8 ct +307 -8 299 -14 299 -32 ct 299 -32 299 -32 299 -171 ct 323 -194 333 -200 349 -200 ct +373 -200 385 -184 385 -152 ct 385 -152 385 -152 385 -48 ct 385 -17 378 -8 354 -8 ct +354 -8 354 -8 354 0 ct 354 0 354 0 455 0 ct 455 0 455 0 455 -7 ct 431 -10 425 -16 425 -40 ct +425 -40 425 -40 425 -153 ct 425 -199 404 -227 368 -227 ct 346 -227 331 -219 298 -187 ct +298 -187 298 -187 298 -226 ct 298 -226 298 -226 295 -227 ct 271 -218 254 -213 228 -205 ct +228 -205 228 -205 228 -196 ct p ef +637 5 m 637 5 637 5 708 -21 ct 708 -21 708 -21 708 -28 ct 699 -28 698 -28 697 -28 ct +679 -28 675 -33 675 -56 ct 675 -56 675 -56 675 -336 ct 675 -336 675 -336 673 -337 ct +650 -329 633 -324 602 -315 ct 602 -315 602 -315 602 -308 ct 606 -308 608 -308 612 -308 ct +630 -308 635 -303 635 -283 ct 635 -283 635 -283 635 -206 ct 616 -222 603 -227 584 -227 ct +528 -227 483 -171 483 -101 ct 483 -38 519 5 573 5 ct 600 5 618 -5 635 -28 ct 635 -28 635 -28 635 4 ct +635 4 635 4 637 5 ct p +635 -50 m 635 -47 631 -41 626 -35 ct 618 -26 606 -21 592 -21 ct 551 -21 525 -60 525 -121 ct +525 -177 548 -213 585 -213 ct 611 -213 635 -190 635 -164 ct 635 -164 635 -164 635 -50 ct +p ef +850 -196 m 853 -198 857 -198 863 -198 ct 876 -198 881 -191 881 -166 ct 881 -166 881 -166 881 -44 ct +881 -15 875 -8 851 -8 ct 851 -8 851 -8 851 0 ct 851 0 851 0 953 0 ct 953 0 953 0 953 -8 ct +929 -8 921 -14 921 -32 ct 921 -32 921 -32 921 -171 ct 945 -194 955 -200 971 -200 ct +995 -200 1007 -184 1007 -152 ct 1007 -152 1007 -152 1007 -48 ct 1007 -17 1000 -8 976 -8 ct +976 -8 976 -8 976 0 ct 976 0 976 0 1077 0 ct 1077 0 1077 0 1077 -7 ct 1053 -10 1047 -16 1047 -40 ct +1047 -40 1047 -40 1047 -153 ct 1047 -199 1026 -227 990 -227 ct 968 -227 953 -219 920 -187 ct +920 -187 920 -187 920 -226 ct 920 -226 920 -226 917 -227 ct 893 -218 876 -213 850 -205 ct +850 -205 850 -205 850 -196 ct p ef +1213 -227 m 1150 -227 1106 -180 1106 -112 ct 1106 -45 1151 5 1212 5 ct 1273 5 1320 -47 1320 -115 ct +1320 -180 1275 -227 1213 -227 ct p +1207 -213 m 1247 -213 1276 -166 1276 -98 ct 1276 -42 1254 -9 1218 -9 ct 1199 -9 1181 -21 1171 -40 ct +1157 -66 1150 -101 1150 -136 ct 1150 -183 1172 -213 1207 -213 ct p ef +1427 -227 m 1427 -227 1427 -227 1352 -200 ct 1352 -200 1352 -200 1352 -192 ct +1352 -192 1352 -192 1356 -193 ct 1361 -194 1368 -194 1372 -194 ct 1384 -194 1388 -186 1388 -164 ct +1388 -164 1388 -164 1388 -49 ct 1388 -14 1383 -8 1350 -8 ct 1350 -8 1350 -8 1350 0 ct +1350 0 1350 0 1464 0 ct 1464 0 1464 0 1464 -8 ct 1433 -8 1429 -15 1429 -50 ct 1429 -50 1429 -50 1429 -225 ct +1429 -225 1429 -225 1427 -227 ct p +1404 -337 m 1391 -337 1380 -326 1380 -312 ct 1380 -298 1390 -287 1404 -287 ct +1418 -287 1429 -298 1429 -312 ct 1429 -326 1418 -337 1404 -337 ct p ef +1635 -155 m 1635 -155 1635 -155 1633 -222 ct 1633 -222 1633 -222 1627 -222 ct +1627 -222 1627 -222 1626 -221 ct 1622 -218 1621 -217 1619 -217 ct 1617 -217 1612 -218 1606 -221 ct +1596 -225 1585 -227 1573 -227 ct 1534 -227 1507 -202 1507 -166 ct 1507 -138 1522 -118 1563 -95 ct +1563 -95 1563 -95 1591 -78 ct 1608 -69 1617 -57 1617 -41 ct 1617 -20 1601 -6 1576 -6 ct +1560 -6 1545 -12 1536 -23 ct 1526 -35 1521 -47 1515 -75 ct 1515 -75 1515 -75 1507 -75 ct +1507 -75 1507 -75 1507 2 ct 1507 2 1507 2 1513 2 ct 1517 -3 1519 -4 1525 -4 ct +1529 -4 1536 -3 1547 0 ct 1560 3 1574 5 1582 5 ct 1619 5 1650 -24 1650 -58 ct 1650 -83 1639 -99 1610 -117 ct +1610 -117 1610 -117 1558 -148 ct 1544 -156 1537 -169 1537 -182 ct 1537 -202 1552 -216 1574 -216 ct +1602 -216 1616 -199 1627 -155 ct 1627 -155 1627 -155 1635 -155 ct p ef +1874 -81 m 1850 -43 1829 -29 1798 -29 ct 1771 -29 1750 -43 1736 -72 ct 1727 -90 1724 -107 1723 -137 ct +1723 -137 1723 -137 1872 -137 ct 1868 -169 1863 -183 1851 -199 ct 1837 -217 1814 -227 1789 -227 ct +1765 -227 1742 -218 1724 -201 ct 1701 -181 1688 -146 1688 -106 ct 1688 -37 1723 5 1779 5 ct +1825 5 1861 -24 1881 -78 ct 1881 -78 1881 -78 1874 -81 ct p +1724 -153 m 1729 -191 1746 -209 1775 -209 ct 1805 -209 1816 -196 1823 -153 ct +1823 -153 1823 -153 1724 -153 ct p ef +pom +gr +gr +gs +gs +pum +5435 10350 t +150 -222 m 150 -222 150 -222 90 -222 ct 90 -222 90 -222 90 -279 ct 90 -308 99 -323 118 -323 ct +128 -323 135 -318 143 -304 ct 151 -291 157 -286 165 -286 ct 176 -286 185 -295 185 -306 ct +185 -324 164 -337 135 -337 ct 105 -337 79 -324 67 -301 ct 54 -279 50 -261 50 -222 ct +50 -222 50 -222 10 -222 ct 10 -222 10 -222 10 -206 ct 10 -206 10 -206 50 -206 ct +50 -206 50 -206 50 -51 ct 50 -14 45 -8 10 -8 ct 10 -8 10 -8 10 0 ct 10 0 10 0 136 0 ct +136 0 136 0 136 -8 ct 96 -8 91 -13 91 -51 ct 91 -51 91 -51 91 -206 ct 91 -206 91 -206 150 -206 ct +150 -206 150 -206 150 -222 ct p ef +375 -32 m 367 -26 361 -23 354 -23 ct 343 -23 339 -30 339 -52 ct 339 -52 339 -52 339 -148 ct +339 -173 337 -188 329 -200 ct 319 -218 298 -227 269 -227 ct 224 -227 188 -203 188 -171 ct +188 -160 198 -150 209 -150 ct 221 -150 231 -160 231 -171 ct 231 -173 230 -175 230 -179 ct +229 -183 228 -187 228 -191 ct 228 -204 244 -215 263 -215 ct 287 -215 300 -201 300 -174 ct +300 -174 300 -174 300 -144 ct 225 -113 217 -109 196 -90 ct 186 -81 179 -64 179 -48 ct +179 -17 200 5 230 5 ct 251 5 271 -5 300 -31 ct 303 -5 312 5 331 5 ct 348 5 358 -1 375 -20 ct +375 -20 375 -20 375 -32 ct p +300 -61 m 300 -45 298 -41 287 -35 ct 276 -28 262 -24 252 -24 ct 235 -24 222 -40 222 -62 ct +222 -62 222 -62 222 -63 ct 222 -92 241 -110 300 -132 ct 300 -132 300 -132 300 -61 ct +p ef +384 -192 m 391 -194 396 -194 401 -194 ct 413 -194 418 -186 418 -164 ct 418 -164 418 -164 418 -41 ct +418 -17 414 -13 383 -7 ct 383 -7 383 -7 383 0 ct 383 0 383 0 500 0 ct 500 0 500 0 500 -8 ct +467 -8 458 -15 458 -44 ct 458 -44 458 -44 458 -155 ct 458 -171 479 -196 492 -196 ct +495 -196 500 -193 505 -188 ct 513 -182 518 -179 524 -179 ct 536 -179 543 -187 543 -201 ct +543 -217 533 -227 517 -227 ct 496 -227 482 -216 458 -181 ct 458 -181 458 -181 458 -226 ct +458 -226 458 -226 456 -227 ct 430 -216 413 -210 384 -200 ct 384 -200 384 -200 384 -192 ct +p ef +867 -81 m 843 -43 822 -29 791 -29 ct 764 -29 743 -43 729 -72 ct 720 -90 717 -107 716 -137 ct +716 -137 716 -137 865 -137 ct 861 -169 856 -183 844 -199 ct 830 -217 807 -227 782 -227 ct +758 -227 735 -218 717 -201 ct 694 -181 681 -146 681 -106 ct 681 -37 716 5 772 5 ct +818 5 854 -24 874 -78 ct 874 -78 874 -78 867 -81 ct p +717 -153 m 722 -191 739 -209 768 -209 ct 798 -209 809 -196 816 -153 ct 816 -153 816 -153 717 -153 ct +p ef +897 -196 m 900 -198 904 -198 910 -198 ct 923 -198 928 -191 928 -166 ct 928 -166 928 -166 928 -44 ct +928 -15 922 -8 898 -8 ct 898 -8 898 -8 898 0 ct 898 0 898 0 1000 0 ct 1000 0 1000 0 1000 -8 ct +976 -8 968 -14 968 -32 ct 968 -32 968 -32 968 -171 ct 992 -194 1002 -200 1018 -200 ct +1042 -200 1054 -184 1054 -152 ct 1054 -152 1054 -152 1054 -48 ct 1054 -17 1047 -8 1023 -8 ct +1023 -8 1023 -8 1023 0 ct 1023 0 1023 0 1124 0 ct 1124 0 1124 0 1124 -7 ct 1100 -10 1094 -16 1094 -40 ct +1094 -40 1094 -40 1094 -153 ct 1094 -199 1073 -227 1037 -227 ct 1015 -227 1000 -219 967 -187 ct +967 -187 967 -187 967 -226 ct 967 -226 967 -226 964 -227 ct 940 -218 923 -213 897 -205 ct +897 -205 897 -205 897 -196 ct p ef +1306 5 m 1306 5 1306 5 1377 -21 ct 1377 -21 1377 -21 1377 -28 ct 1368 -28 1367 -28 1366 -28 ct +1348 -28 1344 -33 1344 -56 ct 1344 -56 1344 -56 1344 -336 ct 1344 -336 1344 -336 1342 -337 ct +1319 -329 1302 -324 1271 -315 ct 1271 -315 1271 -315 1271 -308 ct 1275 -308 1277 -308 1281 -308 ct +1299 -308 1304 -303 1304 -283 ct 1304 -283 1304 -283 1304 -206 ct 1285 -222 1272 -227 1253 -227 ct +1197 -227 1152 -171 1152 -101 ct 1152 -38 1188 5 1242 5 ct 1269 5 1287 -5 1304 -28 ct +1304 -28 1304 -28 1304 4 ct 1304 4 1304 4 1306 5 ct p +1304 -50 m 1304 -47 1300 -41 1295 -35 ct 1287 -26 1275 -21 1261 -21 ct 1220 -21 1194 -60 1194 -121 ct +1194 -177 1217 -213 1254 -213 ct 1280 -213 1304 -190 1304 -164 ct 1304 -164 1304 -164 1304 -50 ct +p ef +1664 -155 m 1664 -155 1664 -155 1662 -222 ct 1662 -222 1662 -222 1656 -222 ct +1656 -222 1656 -222 1655 -221 ct 1651 -218 1650 -217 1648 -217 ct 1646 -217 1641 -218 1635 -221 ct +1625 -225 1614 -227 1602 -227 ct 1563 -227 1536 -202 1536 -166 ct 1536 -138 1551 -118 1592 -95 ct +1592 -95 1592 -95 1620 -78 ct 1637 -69 1646 -57 1646 -41 ct 1646 -20 1630 -6 1605 -6 ct +1589 -6 1574 -12 1565 -23 ct 1555 -35 1550 -47 1544 -75 ct 1544 -75 1544 -75 1536 -75 ct +1536 -75 1536 -75 1536 2 ct 1536 2 1536 2 1542 2 ct 1546 -3 1548 -4 1554 -4 ct +1558 -4 1565 -3 1576 0 ct 1589 3 1603 5 1611 5 ct 1648 5 1679 -24 1679 -58 ct 1679 -83 1668 -99 1639 -117 ct +1639 -117 1639 -117 1587 -148 ct 1573 -156 1566 -169 1566 -182 ct 1566 -202 1581 -216 1603 -216 ct +1631 -216 1645 -199 1656 -155 ct 1656 -155 1656 -155 1664 -155 ct p ef +1710 -195 m 1715 -195 1718 -195 1722 -195 ct 1739 -195 1742 -190 1742 -167 ct +1742 -167 1742 -167 1742 65 ct 1742 90 1737 96 1708 99 ct 1708 99 1708 99 1708 107 ct +1708 107 1708 107 1826 107 ct 1826 107 1826 107 1826 98 ct 1789 98 1783 93 1783 61 ct +1783 61 1783 61 1783 -16 ct 1800 0 1812 5 1832 5 ct 1889 5 1934 -50 1934 -122 ct +1934 -183 1900 -227 1853 -227 ct 1826 -227 1804 -215 1783 -189 ct 1783 -189 1783 -189 1783 -226 ct +1783 -226 1783 -226 1780 -227 ct 1754 -217 1737 -210 1710 -202 ct 1710 -202 1710 -202 1710 -195 ct +p +1783 -165 m 1783 -180 1810 -197 1832 -197 ct 1868 -197 1892 -160 1892 -103 ct +1892 -48 1868 -11 1833 -11 ct 1811 -11 1783 -29 1783 -44 ct 1783 -44 1783 -44 1783 -165 ct +p ef +2154 -81 m 2130 -43 2109 -29 2078 -29 ct 2051 -29 2030 -43 2016 -72 ct 2007 -90 2004 -107 2003 -137 ct +2003 -137 2003 -137 2152 -137 ct 2148 -169 2143 -183 2131 -199 ct 2117 -217 2094 -227 2069 -227 ct +2045 -227 2022 -218 2004 -201 ct 1981 -181 1968 -146 1968 -106 ct 1968 -37 2003 5 2059 5 ct +2105 5 2141 -24 2161 -78 ct 2161 -78 2161 -78 2154 -81 ct p +2004 -153 m 2009 -191 2026 -209 2055 -209 ct 2085 -209 2096 -196 2103 -153 ct +2103 -153 2103 -153 2004 -153 ct p ef +2374 -81 m 2350 -43 2329 -29 2298 -29 ct 2271 -29 2250 -43 2236 -72 ct 2227 -90 2224 -107 2223 -137 ct +2223 -137 2223 -137 2372 -137 ct 2368 -169 2363 -183 2351 -199 ct 2337 -217 2314 -227 2289 -227 ct +2265 -227 2242 -218 2224 -201 ct 2201 -181 2188 -146 2188 -106 ct 2188 -37 2223 5 2279 5 ct +2325 5 2361 -24 2381 -78 ct 2381 -78 2381 -78 2374 -81 ct p +2224 -153 m 2229 -191 2246 -209 2275 -209 ct 2305 -209 2316 -196 2323 -153 ct +2323 -153 2323 -153 2224 -153 ct p ef +2589 -77 m 2565 -42 2548 -31 2520 -31 ct 2476 -31 2445 -70 2445 -127 ct 2445 -178 2472 -213 2511 -213 ct +2529 -213 2535 -207 2540 -189 ct 2540 -189 2540 -189 2543 -178 ct 2547 -164 2555 -155 2565 -155 ct +2578 -155 2589 -164 2589 -176 ct 2589 -204 2555 -227 2514 -227 ct 2490 -227 2466 -217 2446 -199 ct +2422 -178 2408 -144 2408 -105 ct 2408 -41 2446 5 2500 5 ct 2522 5 2541 -3 2559 -18 ct +2572 -30 2581 -43 2595 -72 ct 2595 -72 2595 -72 2589 -77 ct p ef +2692 -169 m 2712 -192 2727 -200 2746 -200 ct 2770 -200 2782 -182 2782 -148 ct +2782 -148 2782 -148 2782 -50 ct 2782 -16 2777 -10 2749 -7 ct 2749 -7 2749 -7 2749 0 ct +2749 0 2749 0 2852 0 ct 2852 0 2852 0 2852 -7 ct 2826 -12 2823 -16 2823 -50 ct +2823 -50 2823 -50 2823 -148 ct 2823 -200 2802 -227 2763 -227 ct 2735 -227 2714 -215 2692 -185 ct +2692 -185 2692 -185 2692 -336 ct 2692 -336 2692 -336 2690 -337 ct 2673 -331 2661 -327 2634 -319 ct +2634 -319 2634 -319 2621 -315 ct 2621 -315 2621 -315 2621 -308 ct 2623 -308 2624 -308 2627 -308 ct +2647 -308 2651 -304 2651 -283 ct 2651 -283 2651 -283 2651 -50 ct 2651 -15 2648 -11 2620 -7 ct +2620 -7 2620 -7 2620 0 ct 2620 0 2620 0 2725 0 ct 2725 0 2725 0 2725 -7 ct 2697 -10 2692 -16 2692 -50 ct +2692 -50 2692 -50 2692 -169 ct p ef +pom +gr +gr +gs +gs +pum +10779 16488 t +9 -196 m 15 -198 19 -198 25 -198 ct 37 -198 42 -190 42 -166 ct 42 -166 42 -166 42 -41 ct +42 -15 35 -7 8 -7 ct 8 -7 8 -7 8 0 ct 8 0 8 0 115 0 ct 115 0 115 0 115 -8 ct 90 -8 82 -13 82 -33 ct +82 -33 82 -33 82 -172 ct 82 -173 86 -178 90 -181 ct 102 -193 122 -201 139 -201 ct +161 -201 171 -184 171 -149 ct 171 -149 171 -149 171 -42 ct 171 -14 166 -8 138 -8 ct +138 -8 138 -8 138 0 ct 138 0 138 0 247 0 ct 247 0 247 0 247 -7 ct 219 -7 212 -16 212 -46 ct +212 -46 212 -46 212 -171 ct 227 -192 243 -201 265 -201 ct 292 -201 301 -188 301 -147 ct +301 -147 301 -147 301 -43 ct 301 -15 297 -11 269 -7 ct 269 -7 269 -7 269 0 ct 269 0 269 0 375 0 ct +375 0 375 0 375 -8 ct 375 -8 375 -8 363 -8 ct 348 -8 342 -18 342 -37 ct 342 -37 342 -37 342 -139 ct +342 -197 323 -227 286 -227 ct 258 -227 233 -214 207 -185 ct 198 -214 182 -227 155 -227 ct +134 -227 121 -220 80 -189 ct 80 -189 80 -189 80 -226 ct 80 -226 80 -226 77 -227 ct +52 -218 36 -212 9 -205 ct 9 -205 9 -205 9 -196 ct p ef +470 -227 m 470 -227 470 -227 395 -200 ct 395 -200 395 -200 395 -192 ct 395 -192 395 -192 399 -193 ct +404 -194 411 -194 415 -194 ct 427 -194 431 -186 431 -164 ct 431 -164 431 -164 431 -49 ct +431 -14 426 -8 393 -8 ct 393 -8 393 -8 393 0 ct 393 0 393 0 507 0 ct 507 0 507 0 507 -8 ct +476 -8 472 -15 472 -50 ct 472 -50 472 -50 472 -225 ct 472 -225 472 -225 470 -227 ct +p +447 -337 m 434 -337 423 -326 423 -312 ct 423 -298 433 -287 447 -287 ct 461 -287 472 -298 472 -312 ct +472 -326 461 -337 447 -337 ct p ef +718 -77 m 694 -42 677 -31 649 -31 ct 605 -31 574 -70 574 -127 ct 574 -178 601 -213 640 -213 ct +658 -213 664 -207 669 -189 ct 669 -189 669 -189 672 -178 ct 676 -164 684 -155 694 -155 ct +707 -155 718 -164 718 -176 ct 718 -204 684 -227 643 -227 ct 619 -227 595 -217 575 -199 ct +551 -178 537 -144 537 -105 ct 537 -41 575 5 629 5 ct 651 5 670 -3 688 -18 ct 701 -30 710 -43 724 -72 ct +724 -72 724 -72 718 -77 ct p ef +748 -192 m 755 -194 760 -194 765 -194 ct 777 -194 782 -186 782 -164 ct 782 -164 782 -164 782 -41 ct +782 -17 778 -13 747 -7 ct 747 -7 747 -7 747 0 ct 747 0 747 0 864 0 ct 864 0 864 0 864 -8 ct +831 -8 822 -15 822 -44 ct 822 -44 822 -44 822 -155 ct 822 -171 843 -196 856 -196 ct +859 -196 864 -193 869 -188 ct 877 -182 882 -179 888 -179 ct 900 -179 907 -187 907 -201 ct +907 -217 897 -227 881 -227 ct 860 -227 846 -216 822 -181 ct 822 -181 822 -181 822 -226 ct +822 -226 822 -226 820 -227 ct 794 -216 777 -210 748 -200 ct 748 -200 748 -200 748 -192 ct +p ef +1031 -227 m 968 -227 924 -180 924 -112 ct 924 -45 969 5 1030 5 ct 1091 5 1138 -47 1138 -115 ct +1138 -180 1093 -227 1031 -227 ct p +1025 -213 m 1065 -213 1094 -166 1094 -98 ct 1094 -42 1072 -9 1036 -9 ct 1017 -9 999 -21 989 -40 ct +975 -66 968 -101 968 -136 ct 968 -183 990 -213 1025 -213 ct p ef +1164 -195 m 1169 -195 1172 -195 1176 -195 ct 1193 -195 1196 -190 1196 -167 ct +1196 -167 1196 -167 1196 65 ct 1196 90 1191 96 1162 99 ct 1162 99 1162 99 1162 107 ct +1162 107 1162 107 1280 107 ct 1280 107 1280 107 1280 98 ct 1243 98 1237 93 1237 61 ct +1237 61 1237 61 1237 -16 ct 1254 0 1266 5 1286 5 ct 1343 5 1388 -50 1388 -122 ct +1388 -183 1354 -227 1307 -227 ct 1280 -227 1258 -215 1237 -189 ct 1237 -189 1237 -189 1237 -226 ct +1237 -226 1237 -226 1234 -227 ct 1208 -217 1191 -210 1164 -202 ct 1164 -202 1164 -202 1164 -195 ct +p +1237 -165 m 1237 -180 1264 -197 1286 -197 ct 1322 -197 1346 -160 1346 -103 ct +1346 -48 1322 -11 1287 -11 ct 1265 -11 1237 -29 1237 -44 ct 1237 -44 1237 -44 1237 -165 ct +p ef +1486 -169 m 1506 -192 1521 -200 1540 -200 ct 1564 -200 1576 -182 1576 -148 ct +1576 -148 1576 -148 1576 -50 ct 1576 -16 1571 -10 1543 -7 ct 1543 -7 1543 -7 1543 0 ct +1543 0 1543 0 1646 0 ct 1646 0 1646 0 1646 -7 ct 1620 -12 1617 -16 1617 -50 ct +1617 -50 1617 -50 1617 -148 ct 1617 -200 1596 -227 1557 -227 ct 1529 -227 1508 -215 1486 -185 ct +1486 -185 1486 -185 1486 -336 ct 1486 -336 1486 -336 1484 -337 ct 1467 -331 1455 -327 1428 -319 ct +1428 -319 1428 -319 1415 -315 ct 1415 -315 1415 -315 1415 -308 ct 1417 -308 1418 -308 1421 -308 ct +1441 -308 1445 -304 1445 -283 ct 1445 -283 1445 -283 1445 -50 ct 1445 -15 1442 -11 1414 -7 ct +1414 -7 1414 -7 1414 0 ct 1414 0 1414 0 1519 0 ct 1519 0 1519 0 1519 -7 ct 1491 -10 1486 -16 1486 -50 ct +1486 -50 1486 -50 1486 -169 ct p ef +1780 -227 m 1717 -227 1673 -180 1673 -112 ct 1673 -45 1718 5 1779 5 ct 1840 5 1887 -47 1887 -115 ct +1887 -180 1842 -227 1780 -227 ct p +1774 -213 m 1814 -213 1843 -166 1843 -98 ct 1843 -42 1821 -9 1785 -9 ct 1766 -9 1748 -21 1738 -40 ct +1724 -66 1717 -101 1717 -136 ct 1717 -183 1739 -213 1774 -213 ct p ef +1917 -196 m 1920 -198 1924 -198 1930 -198 ct 1943 -198 1948 -191 1948 -166 ct +1948 -166 1948 -166 1948 -44 ct 1948 -15 1942 -8 1918 -8 ct 1918 -8 1918 -8 1918 0 ct +1918 0 1918 0 2020 0 ct 2020 0 2020 0 2020 -8 ct 1996 -8 1988 -14 1988 -32 ct 1988 -32 1988 -32 1988 -171 ct +2012 -194 2022 -200 2038 -200 ct 2062 -200 2074 -184 2074 -152 ct 2074 -152 2074 -152 2074 -48 ct +2074 -17 2067 -8 2043 -8 ct 2043 -8 2043 -8 2043 0 ct 2043 0 2043 0 2144 0 ct 2144 0 2144 0 2144 -7 ct +2120 -10 2114 -16 2114 -40 ct 2114 -40 2114 -40 2114 -153 ct 2114 -199 2093 -227 2057 -227 ct +2035 -227 2020 -219 1987 -187 ct 1987 -187 1987 -187 1987 -226 ct 1987 -226 1987 -226 1984 -227 ct +1960 -218 1943 -213 1917 -205 ct 1917 -205 1917 -205 1917 -196 ct p ef +2357 -81 m 2333 -43 2312 -29 2281 -29 ct 2254 -29 2233 -43 2219 -72 ct 2210 -90 2207 -107 2206 -137 ct +2206 -137 2206 -137 2355 -137 ct 2351 -169 2346 -183 2334 -199 ct 2320 -217 2297 -227 2272 -227 ct +2248 -227 2225 -218 2207 -201 ct 2184 -181 2171 -146 2171 -106 ct 2171 -37 2206 5 2262 5 ct +2308 5 2344 -24 2364 -78 ct 2364 -78 2364 -78 2357 -81 ct p +2207 -153 m 2212 -191 2229 -209 2258 -209 ct 2288 -209 2299 -196 2306 -153 ct +2306 -153 2306 -153 2207 -153 ct p ef +pom +gr +gr +gs +gs +pum +15356 12996 t +3 -192 m 10 -194 15 -194 20 -194 ct 32 -194 37 -186 37 -164 ct 37 -164 37 -164 37 -41 ct +37 -17 33 -13 2 -7 ct 2 -7 2 -7 2 0 ct 2 0 2 0 119 0 ct 119 0 119 0 119 -8 ct 86 -8 77 -15 77 -44 ct +77 -44 77 -44 77 -155 ct 77 -171 98 -196 111 -196 ct 114 -196 119 -193 124 -188 ct +132 -182 137 -179 143 -179 ct 155 -179 162 -187 162 -201 ct 162 -217 152 -227 136 -227 ct +115 -227 101 -216 77 -181 ct 77 -181 77 -181 77 -226 ct 77 -226 77 -226 75 -227 ct +49 -216 32 -210 3 -200 ct 3 -200 3 -200 3 -192 ct p ef +363 -81 m 339 -43 318 -29 287 -29 ct 260 -29 239 -43 225 -72 ct 216 -90 213 -107 212 -137 ct +212 -137 212 -137 361 -137 ct 357 -169 352 -183 340 -199 ct 326 -217 303 -227 278 -227 ct +254 -227 231 -218 213 -201 ct 190 -181 177 -146 177 -106 ct 177 -37 212 5 268 5 ct +314 5 350 -24 370 -78 ct 370 -78 370 -78 363 -81 ct p +213 -153 m 218 -191 235 -209 264 -209 ct 294 -209 305 -196 312 -153 ct 312 -153 312 -153 213 -153 ct +p ef +616 -222 m 616 -222 616 -222 549 -222 ct 549 -222 549 -222 549 -215 ct 564 -213 571 -208 571 -199 ct +571 -194 570 -189 568 -184 ct 568 -184 568 -184 521 -56 ct 521 -56 521 -56 471 -182 ct +468 -189 467 -196 467 -201 ct 467 -210 472 -213 489 -215 ct 489 -215 489 -215 489 -222 ct +489 -222 489 -222 394 -222 ct 394 -222 394 -222 394 -214 ct 413 -214 416 -209 438 -158 ct +438 -158 438 -158 496 -16 ct 497 -13 499 -10 500 -6 ct 503 3 506 7 509 7 ct 512 7 515 1 522 -18 ct +522 -18 522 -18 584 -176 ct 599 -210 601 -213 616 -215 ct 616 -215 616 -215 616 -222 ct +p ef +829 -81 m 805 -43 784 -29 753 -29 ct 726 -29 705 -43 691 -72 ct 682 -90 679 -107 678 -137 ct +678 -137 678 -137 827 -137 ct 823 -169 818 -183 806 -199 ct 792 -217 769 -227 744 -227 ct +720 -227 697 -218 679 -201 ct 656 -181 643 -146 643 -106 ct 643 -37 678 5 734 5 ct +780 5 816 -24 836 -78 ct 836 -78 836 -78 829 -81 ct p +679 -153 m 684 -191 701 -209 730 -209 ct 760 -209 771 -196 778 -153 ct 778 -153 778 -153 679 -153 ct +p ef +854 -192 m 861 -194 866 -194 871 -194 ct 883 -194 888 -186 888 -164 ct 888 -164 888 -164 888 -41 ct +888 -17 884 -13 853 -7 ct 853 -7 853 -7 853 0 ct 853 0 853 0 970 0 ct 970 0 970 0 970 -8 ct +937 -8 928 -15 928 -44 ct 928 -44 928 -44 928 -155 ct 928 -171 949 -196 962 -196 ct +965 -196 970 -193 975 -188 ct 983 -182 988 -179 994 -179 ct 1006 -179 1013 -187 1013 -201 ct +1013 -217 1003 -227 987 -227 ct 966 -227 952 -216 928 -181 ct 928 -181 928 -181 928 -226 ct +928 -226 928 -226 926 -227 ct 900 -216 883 -210 854 -200 ct 854 -200 854 -200 854 -192 ct +p ef +1090 -336 m 1090 -336 1090 -336 1088 -337 ct 1067 -330 1054 -326 1031 -319 ct +1031 -319 1031 -319 1017 -315 ct 1017 -315 1017 -315 1017 -308 ct 1020 -308 1022 -308 1026 -308 ct +1045 -308 1049 -304 1049 -283 ct 1049 -283 1049 -283 1049 -27 ct 1049 -11 1091 5 1129 5 ct +1193 5 1243 -49 1243 -120 ct 1243 -181 1206 -227 1157 -227 ct 1128 -227 1100 -209 1090 -185 ct +1090 -185 1090 -185 1090 -336 ct p +1090 -159 m 1090 -178 1113 -196 1138 -196 ct 1176 -196 1200 -157 1200 -97 ct +1200 -42 1177 -11 1137 -11 ct 1112 -11 1090 -22 1090 -35 ct 1090 -35 1090 -35 1090 -159 ct +p ef +1464 -81 m 1440 -43 1419 -29 1388 -29 ct 1361 -29 1340 -43 1326 -72 ct 1317 -90 1314 -107 1313 -137 ct +1313 -137 1313 -137 1462 -137 ct 1458 -169 1453 -183 1441 -199 ct 1427 -217 1404 -227 1379 -227 ct +1355 -227 1332 -218 1314 -201 ct 1291 -181 1278 -146 1278 -106 ct 1278 -37 1313 5 1369 5 ct +1415 5 1451 -24 1471 -78 ct 1471 -78 1471 -78 1464 -81 ct p +1314 -153 m 1319 -191 1336 -209 1365 -209 ct 1395 -209 1406 -196 1413 -153 ct +1413 -153 1413 -153 1314 -153 ct p ef +1489 -192 m 1496 -194 1501 -194 1506 -194 ct 1518 -194 1523 -186 1523 -164 ct +1523 -164 1523 -164 1523 -41 ct 1523 -17 1519 -13 1488 -7 ct 1488 -7 1488 -7 1488 0 ct +1488 0 1488 0 1605 0 ct 1605 0 1605 0 1605 -8 ct 1572 -8 1563 -15 1563 -44 ct 1563 -44 1563 -44 1563 -155 ct +1563 -171 1584 -196 1597 -196 ct 1600 -196 1605 -193 1610 -188 ct 1618 -182 1623 -179 1629 -179 ct +1641 -179 1648 -187 1648 -201 ct 1648 -217 1638 -227 1622 -227 ct 1601 -227 1587 -216 1563 -181 ct +1563 -181 1563 -181 1563 -226 ct 1563 -226 1563 -226 1561 -227 ct 1535 -216 1518 -210 1489 -200 ct +1489 -200 1489 -200 1489 -192 ct p ef +1865 -32 m 1857 -26 1851 -23 1844 -23 ct 1833 -23 1829 -30 1829 -52 ct 1829 -52 1829 -52 1829 -148 ct +1829 -173 1827 -188 1819 -200 ct 1809 -218 1788 -227 1759 -227 ct 1714 -227 1678 -203 1678 -171 ct +1678 -160 1688 -150 1699 -150 ct 1711 -150 1721 -160 1721 -171 ct 1721 -173 1720 -175 1720 -179 ct +1719 -183 1718 -187 1718 -191 ct 1718 -204 1734 -215 1753 -215 ct 1777 -215 1790 -201 1790 -174 ct +1790 -174 1790 -174 1790 -144 ct 1715 -113 1707 -109 1686 -90 ct 1676 -81 1669 -64 1669 -48 ct +1669 -17 1690 5 1720 5 ct 1741 5 1761 -5 1790 -31 ct 1793 -5 1802 5 1821 5 ct 1838 5 1848 -1 1865 -20 ct +1865 -20 1865 -20 1865 -32 ct p +1790 -61 m 1790 -45 1788 -41 1777 -35 ct 1766 -28 1752 -24 1742 -24 ct 1725 -24 1712 -40 1712 -62 ct +1712 -62 1712 -62 1712 -63 ct 1712 -92 1731 -110 1790 -132 ct 1790 -132 1790 -132 1790 -61 ct +p ef +1994 -222 m 1994 -222 1994 -222 1946 -222 ct 1946 -222 1946 -222 1946 -279 ct +1946 -284 1945 -286 1942 -286 ct 1939 -281 1936 -277 1932 -272 ct 1914 -245 1893 -221 1886 -219 ct +1880 -216 1877 -212 1877 -210 ct 1877 -208 1878 -207 1879 -206 ct 1879 -206 1879 -206 1905 -206 ct +1905 -206 1905 -206 1905 -58 ct 1905 -16 1919 5 1948 5 ct 1972 5 1990 -7 2006 -33 ct +2006 -33 2006 -33 2000 -38 ct 1990 -26 1981 -21 1971 -21 ct 1953 -21 1946 -34 1946 -65 ct +1946 -65 1946 -65 1946 -206 ct 1946 -206 1946 -206 1994 -206 ct 1994 -206 1994 -206 1994 -222 ct +p ef +2096 -227 m 2096 -227 2096 -227 2021 -200 ct 2021 -200 2021 -200 2021 -192 ct +2021 -192 2021 -192 2025 -193 ct 2030 -194 2037 -194 2041 -194 ct 2053 -194 2057 -186 2057 -164 ct +2057 -164 2057 -164 2057 -49 ct 2057 -14 2052 -8 2019 -8 ct 2019 -8 2019 -8 2019 0 ct +2019 0 2019 0 2133 0 ct 2133 0 2133 0 2133 -8 ct 2102 -8 2098 -15 2098 -50 ct 2098 -50 2098 -50 2098 -225 ct +2098 -225 2098 -225 2096 -227 ct p +2073 -337 m 2060 -337 2049 -326 2049 -312 ct 2049 -298 2059 -287 2073 -287 ct +2087 -287 2098 -298 2098 -312 ct 2098 -326 2087 -337 2073 -337 ct p ef +2272 -227 m 2209 -227 2165 -180 2165 -112 ct 2165 -45 2210 5 2271 5 ct 2332 5 2379 -47 2379 -115 ct +2379 -180 2334 -227 2272 -227 ct p +2266 -213 m 2306 -213 2335 -166 2335 -98 ct 2335 -42 2313 -9 2277 -9 ct 2258 -9 2240 -21 2230 -40 ct +2216 -66 2209 -101 2209 -136 ct 2209 -183 2231 -213 2266 -213 ct p ef +2408 -196 m 2411 -198 2415 -198 2421 -198 ct 2434 -198 2439 -191 2439 -166 ct +2439 -166 2439 -166 2439 -44 ct 2439 -15 2433 -8 2409 -8 ct 2409 -8 2409 -8 2409 0 ct +2409 0 2409 0 2511 0 ct 2511 0 2511 0 2511 -8 ct 2487 -8 2479 -14 2479 -32 ct 2479 -32 2479 -32 2479 -171 ct +2503 -194 2513 -200 2529 -200 ct 2553 -200 2565 -184 2565 -152 ct 2565 -152 2565 -152 2565 -48 ct +2565 -17 2558 -8 2534 -8 ct 2534 -8 2534 -8 2534 0 ct 2534 0 2534 0 2635 0 ct 2635 0 2635 0 2635 -7 ct +2611 -10 2605 -16 2605 -40 ct 2605 -40 2605 -40 2605 -153 ct 2605 -199 2584 -227 2548 -227 ct +2526 -227 2511 -219 2478 -187 ct 2478 -187 2478 -187 2478 -226 ct 2478 -226 2478 -226 2475 -227 ct +2451 -218 2434 -213 2408 -205 ct 2408 -205 2408 -205 2408 -196 ct p ef +pom +gr +gr +gs +gs +pum +4561 12996 t +214 -32 m 206 -26 200 -23 193 -23 ct 182 -23 178 -30 178 -52 ct 178 -52 178 -52 178 -148 ct +178 -173 176 -188 168 -200 ct 158 -218 137 -227 108 -227 ct 63 -227 27 -203 27 -171 ct +27 -160 37 -150 48 -150 ct 60 -150 70 -160 70 -171 ct 70 -173 69 -175 69 -179 ct +68 -183 67 -187 67 -191 ct 67 -204 83 -215 102 -215 ct 126 -215 139 -201 139 -174 ct +139 -174 139 -174 139 -144 ct 64 -113 56 -109 35 -90 ct 25 -81 18 -64 18 -48 ct +18 -17 39 5 69 5 ct 90 5 110 -5 139 -31 ct 142 -5 151 5 170 5 ct 187 5 197 -1 214 -20 ct +214 -20 214 -20 214 -32 ct p +139 -61 m 139 -45 137 -41 126 -35 ct 115 -28 101 -24 91 -24 ct 74 -24 61 -40 61 -62 ct +61 -62 61 -62 61 -63 ct 61 -92 80 -110 139 -132 ct 139 -132 139 -132 139 -61 ct +p ef +387 5 m 387 5 387 5 458 -21 ct 458 -21 458 -21 458 -28 ct 449 -28 448 -28 447 -28 ct +429 -28 425 -33 425 -56 ct 425 -56 425 -56 425 -336 ct 425 -336 425 -336 423 -337 ct +400 -329 383 -324 352 -315 ct 352 -315 352 -315 352 -308 ct 356 -308 358 -308 362 -308 ct +380 -308 385 -303 385 -283 ct 385 -283 385 -283 385 -206 ct 366 -222 353 -227 334 -227 ct +278 -227 233 -171 233 -101 ct 233 -38 269 5 323 5 ct 350 5 368 -5 385 -28 ct 385 -28 385 -28 385 4 ct +385 4 385 4 387 5 ct p +385 -50 m 385 -47 381 -41 376 -35 ct 368 -26 356 -21 342 -21 ct 301 -21 275 -60 275 -121 ct +275 -177 298 -213 335 -213 ct 361 -213 385 -190 385 -164 ct 385 -164 385 -164 385 -50 ct +p ef +684 -32 m 676 -26 670 -23 663 -23 ct 652 -23 648 -30 648 -52 ct 648 -52 648 -52 648 -148 ct +648 -173 646 -188 638 -200 ct 628 -218 607 -227 578 -227 ct 533 -227 497 -203 497 -171 ct +497 -160 507 -150 518 -150 ct 530 -150 540 -160 540 -171 ct 540 -173 539 -175 539 -179 ct +538 -183 537 -187 537 -191 ct 537 -204 553 -215 572 -215 ct 596 -215 609 -201 609 -174 ct +609 -174 609 -174 609 -144 ct 534 -113 526 -109 505 -90 ct 495 -81 488 -64 488 -48 ct +488 -17 509 5 539 5 ct 560 5 580 -5 609 -31 ct 612 -5 621 5 640 5 ct 657 5 667 -1 684 -20 ct +684 -20 684 -20 684 -32 ct p +609 -61 m 609 -45 607 -41 596 -35 ct 585 -28 571 -24 561 -24 ct 544 -24 531 -40 531 -62 ct +531 -62 531 -62 531 -63 ct 531 -92 550 -110 609 -132 ct 609 -132 609 -132 609 -61 ct +p ef +694 -195 m 699 -195 702 -195 706 -195 ct 723 -195 726 -190 726 -167 ct 726 -167 726 -167 726 65 ct +726 90 721 96 692 99 ct 692 99 692 99 692 107 ct 692 107 692 107 810 107 ct 810 107 810 107 810 98 ct +773 98 767 93 767 61 ct 767 61 767 61 767 -16 ct 784 0 796 5 816 5 ct 873 5 918 -50 918 -122 ct +918 -183 884 -227 837 -227 ct 810 -227 788 -215 767 -189 ct 767 -189 767 -189 767 -226 ct +767 -226 767 -226 764 -227 ct 738 -217 721 -210 694 -202 ct 694 -202 694 -202 694 -195 ct +p +767 -165 m 767 -180 794 -197 816 -197 ct 852 -197 876 -160 876 -103 ct 876 -48 852 -11 817 -11 ct +795 -11 767 -29 767 -44 ct 767 -44 767 -44 767 -165 ct p ef +1063 -222 m 1063 -222 1063 -222 1015 -222 ct 1015 -222 1015 -222 1015 -279 ct +1015 -284 1014 -286 1011 -286 ct 1008 -281 1005 -277 1001 -272 ct 983 -245 962 -221 955 -219 ct +949 -216 946 -212 946 -210 ct 946 -208 947 -207 948 -206 ct 948 -206 948 -206 974 -206 ct +974 -206 974 -206 974 -58 ct 974 -16 988 5 1017 5 ct 1041 5 1059 -7 1075 -33 ct +1075 -33 1075 -33 1069 -38 ct 1059 -26 1050 -21 1040 -21 ct 1022 -21 1015 -34 1015 -65 ct +1015 -65 1015 -65 1015 -206 ct 1015 -206 1015 -206 1063 -206 ct 1063 -206 1063 -206 1063 -222 ct +p ef +1165 -227 m 1165 -227 1165 -227 1090 -200 ct 1090 -200 1090 -200 1090 -192 ct +1090 -192 1090 -192 1094 -193 ct 1099 -194 1106 -194 1110 -194 ct 1122 -194 1126 -186 1126 -164 ct +1126 -164 1126 -164 1126 -49 ct 1126 -14 1121 -8 1088 -8 ct 1088 -8 1088 -8 1088 0 ct +1088 0 1088 0 1202 0 ct 1202 0 1202 0 1202 -8 ct 1171 -8 1167 -15 1167 -50 ct 1167 -50 1167 -50 1167 -225 ct +1167 -225 1167 -225 1165 -227 ct p +1142 -337 m 1129 -337 1118 -326 1118 -312 ct 1118 -298 1128 -287 1142 -287 ct +1156 -287 1167 -298 1167 -312 ct 1167 -326 1156 -337 1142 -337 ct p ef +1450 -222 m 1450 -222 1450 -222 1383 -222 ct 1383 -222 1383 -222 1383 -215 ct +1398 -213 1405 -208 1405 -199 ct 1405 -194 1404 -189 1402 -184 ct 1402 -184 1402 -184 1355 -56 ct +1355 -56 1355 -56 1305 -182 ct 1302 -189 1301 -196 1301 -201 ct 1301 -210 1306 -213 1323 -215 ct +1323 -215 1323 -215 1323 -222 ct 1323 -222 1323 -222 1228 -222 ct 1228 -222 1228 -222 1228 -214 ct +1247 -214 1250 -209 1272 -158 ct 1272 -158 1272 -158 1330 -16 ct 1331 -13 1333 -10 1334 -6 ct +1337 3 1340 7 1343 7 ct 1346 7 1349 1 1356 -18 ct 1356 -18 1356 -18 1418 -176 ct +1433 -210 1435 -213 1450 -215 ct 1450 -215 1450 -215 1450 -222 ct p ef +1663 -81 m 1639 -43 1618 -29 1587 -29 ct 1560 -29 1539 -43 1525 -72 ct 1516 -90 1513 -107 1512 -137 ct +1512 -137 1512 -137 1661 -137 ct 1657 -169 1652 -183 1640 -199 ct 1626 -217 1603 -227 1578 -227 ct +1554 -227 1531 -218 1513 -201 ct 1490 -181 1477 -146 1477 -106 ct 1477 -37 1512 5 1568 5 ct +1614 5 1650 -24 1670 -78 ct 1670 -78 1670 -78 1663 -81 ct p +1513 -153 m 1518 -191 1535 -209 1564 -209 ct 1594 -209 1605 -196 1612 -153 ct +1612 -153 1612 -153 1513 -153 ct p ef +1958 -222 m 1958 -222 1958 -222 1898 -222 ct 1898 -222 1898 -222 1898 -279 ct +1898 -308 1907 -323 1926 -323 ct 1936 -323 1943 -318 1951 -304 ct 1959 -291 1965 -286 1973 -286 ct +1984 -286 1993 -295 1993 -306 ct 1993 -324 1972 -337 1943 -337 ct 1913 -337 1887 -324 1875 -301 ct +1862 -279 1858 -261 1858 -222 ct 1858 -222 1858 -222 1818 -222 ct 1818 -222 1818 -222 1818 -206 ct +1818 -206 1818 -206 1858 -206 ct 1858 -206 1858 -206 1858 -51 ct 1858 -14 1853 -8 1818 -8 ct +1818 -8 1818 -8 1818 0 ct 1818 0 1818 0 1944 0 ct 1944 0 1944 0 1944 -8 ct 1904 -8 1899 -13 1899 -51 ct +1899 -51 1899 -51 1899 -206 ct 1899 -206 1899 -206 1958 -206 ct 1958 -206 1958 -206 1958 -222 ct +p ef +2054 -227 m 2054 -227 2054 -227 1979 -200 ct 1979 -200 1979 -200 1979 -192 ct +1979 -192 1979 -192 1983 -193 ct 1988 -194 1995 -194 1999 -194 ct 2011 -194 2015 -186 2015 -164 ct +2015 -164 2015 -164 2015 -49 ct 2015 -14 2010 -8 1977 -8 ct 1977 -8 1977 -8 1977 0 ct +1977 0 1977 0 2091 0 ct 2091 0 2091 0 2091 -8 ct 2060 -8 2056 -15 2056 -50 ct 2056 -50 2056 -50 2056 -225 ct +2056 -225 2056 -225 2054 -227 ct p +2031 -337 m 2018 -337 2007 -326 2007 -312 ct 2007 -298 2017 -287 2031 -287 ct +2045 -287 2056 -298 2056 -312 ct 2056 -326 2045 -337 2031 -337 ct p ef +2117 -307 m 2117 -307 2117 -307 2120 -307 ct 2125 -308 2131 -308 2135 -308 ct +2151 -308 2155 -301 2155 -278 ct 2155 -278 2155 -278 2155 -42 ct 2155 -15 2149 -8 2118 -8 ct +2118 -8 2118 -8 2118 0 ct 2118 0 2118 0 2232 0 ct 2232 0 2232 0 2232 -8 ct 2202 -8 2196 -14 2196 -41 ct +2196 -41 2196 -41 2196 -336 ct 2196 -336 2196 -336 2194 -337 ct 2169 -328 2151 -323 2117 -315 ct +2117 -315 2117 -315 2117 -307 ct p ef +2367 -222 m 2367 -222 2367 -222 2319 -222 ct 2319 -222 2319 -222 2319 -279 ct +2319 -284 2318 -286 2315 -286 ct 2312 -281 2309 -277 2305 -272 ct 2287 -245 2266 -221 2259 -219 ct +2253 -216 2250 -212 2250 -210 ct 2250 -208 2251 -207 2252 -206 ct 2252 -206 2252 -206 2278 -206 ct +2278 -206 2278 -206 2278 -58 ct 2278 -16 2292 5 2321 5 ct 2345 5 2363 -7 2379 -33 ct +2379 -33 2379 -33 2373 -38 ct 2363 -26 2354 -21 2344 -21 ct 2326 -21 2319 -34 2319 -65 ct +2319 -65 2319 -65 2319 -206 ct 2319 -206 2319 -206 2367 -206 ct 2367 -206 2367 -206 2367 -222 ct +p ef +2581 -81 m 2557 -43 2536 -29 2505 -29 ct 2478 -29 2457 -43 2443 -72 ct 2434 -90 2431 -107 2430 -137 ct +2430 -137 2430 -137 2579 -137 ct 2575 -169 2570 -183 2558 -199 ct 2544 -217 2521 -227 2496 -227 ct +2472 -227 2449 -218 2431 -201 ct 2408 -181 2395 -146 2395 -106 ct 2395 -37 2430 5 2486 5 ct +2532 5 2568 -24 2588 -78 ct 2588 -78 2588 -78 2581 -81 ct p +2431 -153 m 2436 -191 2453 -209 2482 -209 ct 2512 -209 2523 -196 2530 -153 ct +2530 -153 2530 -153 2431 -153 ct p ef +2607 -192 m 2614 -194 2619 -194 2624 -194 ct 2636 -194 2641 -186 2641 -164 ct +2641 -164 2641 -164 2641 -41 ct 2641 -17 2637 -13 2606 -7 ct 2606 -7 2606 -7 2606 0 ct +2606 0 2606 0 2723 0 ct 2723 0 2723 0 2723 -8 ct 2690 -8 2681 -15 2681 -44 ct 2681 -44 2681 -44 2681 -155 ct +2681 -171 2702 -196 2715 -196 ct 2718 -196 2723 -193 2728 -188 ct 2736 -182 2741 -179 2747 -179 ct +2759 -179 2766 -187 2766 -201 ct 2766 -217 2756 -227 2740 -227 ct 2719 -227 2705 -216 2681 -181 ct +2681 -181 2681 -181 2681 -226 ct 2681 -226 2681 -226 2679 -227 ct 2653 -216 2636 -210 2607 -200 ct +2607 -200 2607 -200 2607 -192 ct p ef +pom +gr +gr +gs +gs +pum +10753 9450 t +9 -307 m 9 -307 9 -307 12 -307 ct 17 -308 23 -308 27 -308 ct 43 -308 47 -301 47 -278 ct +47 -278 47 -278 47 -42 ct 47 -15 41 -8 10 -8 ct 10 -8 10 -8 10 0 ct 10 0 10 0 124 0 ct +124 0 124 0 124 -8 ct 94 -8 88 -14 88 -41 ct 88 -41 88 -41 88 -336 ct 88 -336 88 -336 86 -337 ct +61 -328 43 -323 9 -315 ct 9 -315 9 -315 9 -307 ct p ef +256 -227 m 193 -227 149 -180 149 -112 ct 149 -45 194 5 255 5 ct 316 5 363 -47 363 -115 ct +363 -180 318 -227 256 -227 ct p +250 -213 m 290 -213 319 -166 319 -98 ct 319 -42 297 -9 261 -9 ct 242 -9 224 -21 214 -40 ct +200 -66 193 -101 193 -136 ct 193 -183 215 -213 250 -213 ct p ef +617 -25 m 617 -25 617 -25 614 -25 ct 592 -25 587 -30 587 -53 ct 587 -53 587 -53 587 -222 ct +587 -222 587 -222 510 -222 ct 510 -222 510 -222 510 -213 ct 540 -213 546 -208 546 -183 ct +546 -183 546 -183 546 -67 ct 546 -53 544 -46 537 -41 ct 524 -30 509 -24 494 -24 ct +476 -24 460 -41 460 -61 ct 460 -61 460 -61 460 -222 ct 460 -222 460 -222 389 -222 ct +389 -222 389 -222 389 -214 ct 413 -214 419 -206 419 -184 ct 419 -184 419 -184 419 -59 ct +419 -20 443 5 478 5 ct 496 5 515 -3 528 -16 ct 528 -16 528 -16 549 -38 ct 549 -38 549 -38 549 4 ct +549 4 549 4 551 5 ct 575 -5 592 -11 617 -18 ct 617 -18 617 -18 617 -25 ct p ef +798 5 m 798 5 798 5 869 -21 ct 869 -21 869 -21 869 -28 ct 860 -28 859 -28 858 -28 ct +840 -28 836 -33 836 -56 ct 836 -56 836 -56 836 -336 ct 836 -336 836 -336 834 -337 ct +811 -329 794 -324 763 -315 ct 763 -315 763 -315 763 -308 ct 767 -308 769 -308 773 -308 ct +791 -308 796 -303 796 -283 ct 796 -283 796 -283 796 -206 ct 777 -222 764 -227 745 -227 ct +689 -227 644 -171 644 -101 ct 644 -38 680 5 734 5 ct 761 5 779 -5 796 -28 ct 796 -28 796 -28 796 4 ct +796 4 796 4 798 5 ct p +796 -50 m 796 -47 792 -41 787 -35 ct 779 -26 767 -21 753 -21 ct 712 -21 686 -60 686 -121 ct +686 -177 709 -213 746 -213 ct 772 -213 796 -190 796 -164 ct 796 -164 796 -164 796 -50 ct +p ef +1034 -155 m 1034 -155 1034 -155 1032 -222 ct 1032 -222 1032 -222 1026 -222 ct +1026 -222 1026 -222 1025 -221 ct 1021 -218 1020 -217 1018 -217 ct 1016 -217 1011 -218 1005 -221 ct +995 -225 984 -227 972 -227 ct 933 -227 906 -202 906 -166 ct 906 -138 921 -118 962 -95 ct +962 -95 962 -95 990 -78 ct 1007 -69 1016 -57 1016 -41 ct 1016 -20 1000 -6 975 -6 ct +959 -6 944 -12 935 -23 ct 925 -35 920 -47 914 -75 ct 914 -75 914 -75 906 -75 ct +906 -75 906 -75 906 2 ct 906 2 906 2 912 2 ct 916 -3 918 -4 924 -4 ct 928 -4 935 -3 946 0 ct +959 3 973 5 981 5 ct 1018 5 1049 -24 1049 -58 ct 1049 -83 1038 -99 1009 -117 ct +1009 -117 1009 -117 957 -148 ct 943 -156 936 -169 936 -182 ct 936 -202 951 -216 973 -216 ct +1001 -216 1015 -199 1026 -155 ct 1026 -155 1026 -155 1034 -155 ct p ef +1079 -195 m 1084 -195 1087 -195 1091 -195 ct 1108 -195 1111 -190 1111 -167 ct +1111 -167 1111 -167 1111 65 ct 1111 90 1106 96 1077 99 ct 1077 99 1077 99 1077 107 ct +1077 107 1077 107 1195 107 ct 1195 107 1195 107 1195 98 ct 1158 98 1152 93 1152 61 ct +1152 61 1152 61 1152 -16 ct 1169 0 1181 5 1201 5 ct 1258 5 1303 -50 1303 -122 ct +1303 -183 1269 -227 1222 -227 ct 1195 -227 1173 -215 1152 -189 ct 1152 -189 1152 -189 1152 -226 ct +1152 -226 1152 -226 1149 -227 ct 1123 -217 1106 -210 1079 -202 ct 1079 -202 1079 -202 1079 -195 ct +p +1152 -165 m 1152 -180 1179 -197 1201 -197 ct 1237 -197 1261 -160 1261 -103 ct +1261 -48 1237 -11 1202 -11 ct 1180 -11 1152 -29 1152 -44 ct 1152 -44 1152 -44 1152 -165 ct +p ef +1523 -81 m 1499 -43 1478 -29 1447 -29 ct 1420 -29 1399 -43 1385 -72 ct 1376 -90 1373 -107 1372 -137 ct +1372 -137 1372 -137 1521 -137 ct 1517 -169 1512 -183 1500 -199 ct 1486 -217 1463 -227 1438 -227 ct +1414 -227 1391 -218 1373 -201 ct 1350 -181 1337 -146 1337 -106 ct 1337 -37 1372 5 1428 5 ct +1474 5 1510 -24 1530 -78 ct 1530 -78 1530 -78 1523 -81 ct p +1373 -153 m 1378 -191 1395 -209 1424 -209 ct 1454 -209 1465 -196 1472 -153 ct +1472 -153 1472 -153 1373 -153 ct p ef +1759 -32 m 1751 -26 1745 -23 1738 -23 ct 1727 -23 1723 -30 1723 -52 ct 1723 -52 1723 -52 1723 -148 ct +1723 -173 1721 -188 1713 -200 ct 1703 -218 1682 -227 1653 -227 ct 1608 -227 1572 -203 1572 -171 ct +1572 -160 1582 -150 1593 -150 ct 1605 -150 1615 -160 1615 -171 ct 1615 -173 1614 -175 1614 -179 ct +1613 -183 1612 -187 1612 -191 ct 1612 -204 1628 -215 1647 -215 ct 1671 -215 1684 -201 1684 -174 ct +1684 -174 1684 -174 1684 -144 ct 1609 -113 1601 -109 1580 -90 ct 1570 -81 1563 -64 1563 -48 ct +1563 -17 1584 5 1614 5 ct 1635 5 1655 -5 1684 -31 ct 1687 -5 1696 5 1715 5 ct 1732 5 1742 -1 1759 -20 ct +1759 -20 1759 -20 1759 -32 ct p +1684 -61 m 1684 -45 1682 -41 1671 -35 ct 1660 -28 1646 -24 1636 -24 ct 1619 -24 1606 -40 1606 -62 ct +1606 -62 1606 -62 1606 -63 ct 1606 -92 1625 -110 1684 -132 ct 1684 -132 1684 -132 1684 -61 ct +p ef +1768 -307 m 1775 -307 1779 -308 1784 -308 ct 1800 -308 1805 -302 1805 -278 ct +1805 -278 1805 -278 1805 -40 ct 1805 -15 1803 -13 1768 -7 ct 1768 -7 1768 -7 1768 0 ct +1768 0 1768 0 1882 0 ct 1882 0 1882 0 1882 -8 ct 1882 -8 1882 -8 1872 -8 ct 1853 -8 1845 -15 1845 -32 ct +1845 -32 1845 -32 1845 -124 ct 1845 -124 1845 -124 1913 -32 ct 1913 -32 1913 -32 1915 -30 ct +1916 -28 1917 -27 1918 -25 ct 1922 -20 1923 -17 1923 -15 ct 1923 -10 1919 -7 1913 -7 ct +1913 -7 1913 -7 1904 -7 ct 1904 -7 1904 -7 1904 0 ct 1904 0 1904 0 2009 0 ct 2009 0 2009 0 2009 -8 ct +1988 -8 1973 -18 1953 -43 ct 1953 -43 1953 -43 1879 -139 ct 1879 -139 1879 -139 1893 -152 ct +1927 -185 1957 -208 1971 -212 ct 1979 -214 1985 -215 1994 -215 ct 1994 -215 1994 -215 1997 -215 ct +1997 -215 1997 -215 1997 -222 ct 1997 -222 1997 -222 1899 -222 ct 1899 -222 1899 -222 1899 -215 ct +1918 -215 1923 -213 1923 -206 ct 1923 -202 1918 -195 1912 -189 ct 1912 -189 1912 -189 1845 -129 ct +1845 -129 1845 -129 1845 -336 ct 1845 -336 1845 -336 1843 -337 ct 1825 -331 1811 -327 1783 -319 ct +1783 -319 1783 -319 1768 -315 ct 1768 -315 1768 -315 1768 -307 ct p ef +2217 -81 m 2193 -43 2172 -29 2141 -29 ct 2114 -29 2093 -43 2079 -72 ct 2070 -90 2067 -107 2066 -137 ct +2066 -137 2066 -137 2215 -137 ct 2211 -169 2206 -183 2194 -199 ct 2180 -217 2157 -227 2132 -227 ct +2108 -227 2085 -218 2067 -201 ct 2044 -181 2031 -146 2031 -106 ct 2031 -37 2066 5 2122 5 ct +2168 5 2204 -24 2224 -78 ct 2224 -78 2224 -78 2217 -81 ct p +2067 -153 m 2072 -191 2089 -209 2118 -209 ct 2148 -209 2159 -196 2166 -153 ct +2166 -153 2166 -153 2067 -153 ct p ef +2242 -192 m 2249 -194 2254 -194 2259 -194 ct 2271 -194 2276 -186 2276 -164 ct +2276 -164 2276 -164 2276 -41 ct 2276 -17 2272 -13 2241 -7 ct 2241 -7 2241 -7 2241 0 ct +2241 0 2241 0 2358 0 ct 2358 0 2358 0 2358 -8 ct 2325 -8 2316 -15 2316 -44 ct 2316 -44 2316 -44 2316 -155 ct +2316 -171 2337 -196 2350 -196 ct 2353 -196 2358 -193 2363 -188 ct 2371 -182 2376 -179 2382 -179 ct +2394 -179 2401 -187 2401 -201 ct 2401 -217 2391 -227 2375 -227 ct 2354 -227 2340 -216 2316 -181 ct +2316 -181 2316 -181 2316 -226 ct 2316 -226 2316 -226 2314 -227 ct 2288 -216 2271 -210 2242 -200 ct +2242 -200 2242 -200 2242 -192 ct p ef +pom +gr +gr +gs +gs +pum +4619 16250 t +121 -227 m 58 -227 14 -180 14 -112 ct 14 -45 59 5 120 5 ct 181 5 228 -47 228 -115 ct +228 -180 183 -227 121 -227 ct p +115 -213 m 155 -213 184 -166 184 -98 ct 184 -42 162 -9 126 -9 ct 107 -9 89 -21 79 -40 ct +65 -66 58 -101 58 -136 ct 58 -183 80 -213 115 -213 ct p ef +482 -25 m 482 -25 482 -25 479 -25 ct 457 -25 452 -30 452 -53 ct 452 -53 452 -53 452 -222 ct +452 -222 452 -222 375 -222 ct 375 -222 375 -222 375 -213 ct 405 -213 411 -208 411 -183 ct +411 -183 411 -183 411 -67 ct 411 -53 409 -46 402 -41 ct 389 -30 374 -24 359 -24 ct +341 -24 325 -41 325 -61 ct 325 -61 325 -61 325 -222 ct 325 -222 325 -222 254 -222 ct +254 -222 254 -222 254 -214 ct 278 -214 284 -206 284 -184 ct 284 -184 284 -184 284 -59 ct +284 -20 308 5 343 5 ct 361 5 380 -3 393 -16 ct 393 -16 393 -16 414 -38 ct 414 -38 414 -38 414 4 ct +414 4 414 4 416 5 ct 440 -5 457 -11 482 -18 ct 482 -18 482 -18 482 -25 ct p ef +618 -222 m 618 -222 618 -222 570 -222 ct 570 -222 570 -222 570 -279 ct 570 -284 569 -286 566 -286 ct +563 -281 560 -277 556 -272 ct 538 -245 517 -221 510 -219 ct 504 -216 501 -212 501 -210 ct +501 -208 502 -207 503 -206 ct 503 -206 503 -206 529 -206 ct 529 -206 529 -206 529 -58 ct +529 -16 543 5 572 5 ct 596 5 614 -7 630 -33 ct 630 -33 630 -33 624 -38 ct 614 -26 605 -21 595 -21 ct +577 -21 570 -34 570 -65 ct 570 -65 570 -65 570 -206 ct 570 -206 570 -206 618 -206 ct +618 -206 618 -206 618 -222 ct p ef +639 -195 m 644 -195 647 -195 651 -195 ct 668 -195 671 -190 671 -167 ct 671 -167 671 -167 671 65 ct +671 90 666 96 637 99 ct 637 99 637 99 637 107 ct 637 107 637 107 755 107 ct 755 107 755 107 755 98 ct +718 98 712 93 712 61 ct 712 61 712 61 712 -16 ct 729 0 741 5 761 5 ct 818 5 863 -50 863 -122 ct +863 -183 829 -227 782 -227 ct 755 -227 733 -215 712 -189 ct 712 -189 712 -189 712 -226 ct +712 -226 712 -226 709 -227 ct 683 -217 666 -210 639 -202 ct 639 -202 639 -202 639 -195 ct +p +712 -165 m 712 -180 739 -197 761 -197 ct 797 -197 821 -160 821 -103 ct 821 -48 797 -11 762 -11 ct +740 -11 712 -29 712 -44 ct 712 -44 712 -44 712 -165 ct p ef +1117 -25 m 1117 -25 1117 -25 1114 -25 ct 1092 -25 1087 -30 1087 -53 ct 1087 -53 1087 -53 1087 -222 ct +1087 -222 1087 -222 1010 -222 ct 1010 -222 1010 -222 1010 -213 ct 1040 -213 1046 -208 1046 -183 ct +1046 -183 1046 -183 1046 -67 ct 1046 -53 1044 -46 1037 -41 ct 1024 -30 1009 -24 994 -24 ct +976 -24 960 -41 960 -61 ct 960 -61 960 -61 960 -222 ct 960 -222 960 -222 889 -222 ct +889 -222 889 -222 889 -214 ct 913 -214 919 -206 919 -184 ct 919 -184 919 -184 919 -59 ct +919 -20 943 5 978 5 ct 996 5 1015 -3 1028 -16 ct 1028 -16 1028 -16 1049 -38 ct +1049 -38 1049 -38 1049 4 ct 1049 4 1049 4 1051 5 ct 1075 -5 1092 -11 1117 -18 ct +1117 -18 1117 -18 1117 -25 ct p ef +1253 -222 m 1253 -222 1253 -222 1205 -222 ct 1205 -222 1205 -222 1205 -279 ct +1205 -284 1204 -286 1201 -286 ct 1198 -281 1195 -277 1191 -272 ct 1173 -245 1152 -221 1145 -219 ct +1139 -216 1136 -212 1136 -210 ct 1136 -208 1137 -207 1138 -206 ct 1138 -206 1138 -206 1164 -206 ct +1164 -206 1164 -206 1164 -58 ct 1164 -16 1178 5 1207 5 ct 1231 5 1249 -7 1265 -33 ct +1265 -33 1265 -33 1259 -38 ct 1249 -26 1240 -21 1230 -21 ct 1212 -21 1205 -34 1205 -65 ct +1205 -65 1205 -65 1205 -206 ct 1205 -206 1205 -206 1253 -206 ct 1253 -206 1253 -206 1253 -222 ct +p ef +pom +gr +gs +pum +4138 16851 t +143 -334 m 107 -310 92 -297 75 -274 ct 40 -231 23 -182 23 -124 ct 23 -62 41 -13 84 37 ct +104 61 116 72 141 87 ct 141 87 141 87 147 79 ct 108 48 95 31 82 -6 ct 70 -39 65 -76 65 -126 ct +65 -178 71 -218 84 -249 ct 98 -279 112 -297 147 -326 ct 147 -326 147 -326 143 -334 ct +p ef +288 -222 m 288 -222 288 -222 240 -222 ct 240 -222 240 -222 240 -279 ct 240 -284 239 -286 236 -286 ct +233 -281 230 -277 226 -272 ct 208 -245 187 -221 180 -219 ct 174 -216 171 -212 171 -210 ct +171 -208 172 -207 173 -206 ct 173 -206 173 -206 199 -206 ct 199 -206 199 -206 199 -58 ct +199 -16 213 5 242 5 ct 266 5 284 -7 300 -33 ct 300 -33 300 -33 294 -38 ct 284 -26 275 -21 265 -21 ct +247 -21 240 -34 240 -65 ct 240 -65 240 -65 240 -206 ct 240 -206 240 -206 288 -206 ct +288 -206 288 -206 288 -222 ct p ef +426 -227 m 363 -227 319 -180 319 -112 ct 319 -45 364 5 425 5 ct 486 5 533 -47 533 -115 ct +533 -180 488 -227 426 -227 ct p +420 -213 m 460 -213 489 -166 489 -98 ct 489 -42 467 -9 431 -9 ct 412 -9 394 -21 384 -40 ct +370 -66 363 -101 363 -136 ct 363 -183 385 -213 420 -213 ct p ef +827 -222 m 827 -222 827 -222 767 -222 ct 767 -222 767 -222 767 -279 ct 767 -308 776 -323 795 -323 ct +805 -323 812 -318 820 -304 ct 828 -291 834 -286 842 -286 ct 853 -286 862 -295 862 -306 ct +862 -324 841 -337 812 -337 ct 782 -337 756 -324 744 -301 ct 731 -279 727 -261 727 -222 ct +727 -222 727 -222 687 -222 ct 687 -222 687 -222 687 -206 ct 687 -206 687 -206 727 -206 ct +727 -206 727 -206 727 -51 ct 727 -14 722 -8 687 -8 ct 687 -8 687 -8 687 0 ct 687 0 687 0 813 0 ct +813 0 813 0 813 -8 ct 773 -8 768 -13 768 -51 ct 768 -51 768 -51 768 -206 ct 768 -206 768 -206 827 -206 ct +827 -206 827 -206 827 -222 ct p ef +1052 -32 m 1044 -26 1038 -23 1031 -23 ct 1020 -23 1016 -30 1016 -52 ct 1016 -52 1016 -52 1016 -148 ct +1016 -173 1014 -188 1006 -200 ct 996 -218 975 -227 946 -227 ct 901 -227 865 -203 865 -171 ct +865 -160 875 -150 886 -150 ct 898 -150 908 -160 908 -171 ct 908 -173 907 -175 907 -179 ct +906 -183 905 -187 905 -191 ct 905 -204 921 -215 940 -215 ct 964 -215 977 -201 977 -174 ct +977 -174 977 -174 977 -144 ct 902 -113 894 -109 873 -90 ct 863 -81 856 -64 856 -48 ct +856 -17 877 5 907 5 ct 928 5 948 -5 977 -31 ct 980 -5 989 5 1008 5 ct 1025 5 1035 -1 1052 -20 ct +1052 -20 1052 -20 1052 -32 ct p +977 -61 m 977 -45 975 -41 964 -35 ct 953 -28 939 -24 929 -24 ct 912 -24 899 -40 899 -62 ct +899 -62 899 -62 899 -63 ct 899 -92 918 -110 977 -132 ct 977 -132 977 -132 977 -61 ct +p ef +1061 -192 m 1068 -194 1073 -194 1078 -194 ct 1090 -194 1095 -186 1095 -164 ct +1095 -164 1095 -164 1095 -41 ct 1095 -17 1091 -13 1060 -7 ct 1060 -7 1060 -7 1060 0 ct +1060 0 1060 0 1177 0 ct 1177 0 1177 0 1177 -8 ct 1144 -8 1135 -15 1135 -44 ct 1135 -44 1135 -44 1135 -155 ct +1135 -171 1156 -196 1169 -196 ct 1172 -196 1177 -193 1182 -188 ct 1190 -182 1195 -179 1201 -179 ct +1213 -179 1220 -187 1220 -201 ct 1220 -217 1210 -227 1194 -227 ct 1173 -227 1159 -216 1135 -181 ct +1135 -181 1135 -181 1135 -226 ct 1135 -226 1135 -226 1133 -227 ct 1107 -216 1090 -210 1061 -200 ct +1061 -200 1061 -200 1061 -192 ct p ef +1544 -81 m 1520 -43 1499 -29 1468 -29 ct 1441 -29 1420 -43 1406 -72 ct 1397 -90 1394 -107 1393 -137 ct +1393 -137 1393 -137 1542 -137 ct 1538 -169 1533 -183 1521 -199 ct 1507 -217 1484 -227 1459 -227 ct +1435 -227 1412 -218 1394 -201 ct 1371 -181 1358 -146 1358 -106 ct 1358 -37 1393 5 1449 5 ct +1495 5 1531 -24 1551 -78 ct 1551 -78 1551 -78 1544 -81 ct p +1394 -153 m 1399 -191 1416 -209 1445 -209 ct 1475 -209 1486 -196 1493 -153 ct +1493 -153 1493 -153 1394 -153 ct p ef +1574 -196 m 1577 -198 1581 -198 1587 -198 ct 1600 -198 1605 -191 1605 -166 ct +1605 -166 1605 -166 1605 -44 ct 1605 -15 1599 -8 1575 -8 ct 1575 -8 1575 -8 1575 0 ct +1575 0 1575 0 1677 0 ct 1677 0 1677 0 1677 -8 ct 1653 -8 1645 -14 1645 -32 ct 1645 -32 1645 -32 1645 -171 ct +1669 -194 1679 -200 1695 -200 ct 1719 -200 1731 -184 1731 -152 ct 1731 -152 1731 -152 1731 -48 ct +1731 -17 1724 -8 1700 -8 ct 1700 -8 1700 -8 1700 0 ct 1700 0 1700 0 1801 0 ct 1801 0 1801 0 1801 -7 ct +1777 -10 1771 -16 1771 -40 ct 1771 -40 1771 -40 1771 -153 ct 1771 -199 1750 -227 1714 -227 ct +1692 -227 1677 -219 1644 -187 ct 1644 -187 1644 -187 1644 -226 ct 1644 -226 1644 -226 1641 -227 ct +1617 -218 1600 -213 1574 -205 ct 1574 -205 1574 -205 1574 -196 ct p ef +1983 5 m 1983 5 1983 5 2054 -21 ct 2054 -21 2054 -21 2054 -28 ct 2045 -28 2044 -28 2043 -28 ct +2025 -28 2021 -33 2021 -56 ct 2021 -56 2021 -56 2021 -336 ct 2021 -336 2021 -336 2019 -337 ct +1996 -329 1979 -324 1948 -315 ct 1948 -315 1948 -315 1948 -308 ct 1952 -308 1954 -308 1958 -308 ct +1976 -308 1981 -303 1981 -283 ct 1981 -283 1981 -283 1981 -206 ct 1962 -222 1949 -227 1930 -227 ct +1874 -227 1829 -171 1829 -101 ct 1829 -38 1865 5 1919 5 ct 1946 5 1964 -5 1981 -28 ct +1981 -28 1981 -28 1981 4 ct 1981 4 1981 4 1983 5 ct p +1981 -50 m 1981 -47 1977 -41 1972 -35 ct 1964 -26 1952 -21 1938 -21 ct 1897 -21 1871 -60 1871 -121 ct +1871 -177 1894 -213 1931 -213 ct 1957 -213 1981 -190 1981 -164 ct 1981 -164 1981 -164 1981 -50 ct +p ef +2084 87 m 2120 64 2135 51 2153 28 ct 2187 -15 2204 -64 2204 -122 ct 2204 -185 2186 -233 2143 -283 ct +2124 -307 2111 -318 2086 -334 ct 2086 -334 2086 -334 2080 -326 ct 2119 -295 2132 -277 2145 -240 ct +2157 -207 2162 -170 2162 -120 ct 2162 -69 2156 -28 2143 2 ct 2129 33 2115 51 2080 79 ct +2080 79 2080 79 2084 87 ct p ef +pom +gr +gr +gs +gs +pum +8742 14319 t +7 -199 m 14 -200 17 -201 23 -201 ct 51 -201 58 -188 81 -103 ct 89 -71 101 -13 101 -4 ct +101 4 98 11 91 20 ct 76 41 66 54 60 59 ct 50 70 44 74 38 74 ct 35 74 31 73 26 69 ct +18 63 13 60 7 60 ct -3 60 -12 69 -12 80 ct -12 92 -1 102 13 102 ct 45 102 110 27 163 -71 ct +197 -131 210 -167 210 -191 ct 210 -206 198 -219 183 -219 ct 172 -219 164 -211 164 -200 ct +164 -193 168 -188 178 -181 ct 187 -176 191 -171 191 -164 ct 191 -145 172 -106 130 -36 ct +130 -36 130 -36 121 -94 ct 113 -137 85 -219 78 -219 ct 78 -219 78 -219 76 -219 ct +76 -218 74 -218 72 -218 ct 67 -217 49 -214 23 -209 ct 21 -209 14 -208 7 -207 ct +7 -207 7 -207 7 -199 ct p ef +pom +gr +gs +pum +8962 14319 t +143 -334 m 107 -310 92 -297 75 -274 ct 40 -231 23 -182 23 -124 ct 23 -62 41 -13 84 37 ct +104 61 116 72 141 87 ct 141 87 141 87 147 79 ct 108 48 95 31 82 -6 ct 70 -39 65 -76 65 -126 ct +65 -178 71 -218 84 -249 ct 98 -279 112 -297 147 -326 ct 147 -326 147 -326 143 -334 ct +p ef +pom +gr +gs +pum +9127 14319 t +227 -58 m 227 -58 227 -58 217 -45 ct 203 -27 194 -19 187 -19 ct 183 -19 179 -23 179 -27 ct +179 -31 179 -31 186 -58 ct 186 -58 186 -58 214 -160 ct 216 -170 218 -181 218 -188 ct +218 -206 205 -218 186 -218 ct 154 -218 123 -189 72 -110 ct 72 -110 72 -110 105 -217 ct +105 -217 105 -217 104 -218 ct 77 -213 67 -211 24 -203 ct 24 -203 24 -203 24 -195 ct +49 -195 55 -192 55 -182 ct 55 -179 55 -176 54 -173 ct 54 -173 54 -173 7 0 ct 7 0 7 0 44 0 ct +67 -78 72 -89 93 -123 ct 123 -168 148 -193 166 -193 ct 174 -193 178 -188 178 -179 ct +178 -173 175 -156 171 -141 ct 171 -141 171 -141 150 -60 ct 143 -35 142 -28 142 -23 ct +142 -4 149 4 165 4 ct 187 4 200 -6 234 -52 ct 234 -52 234 -52 227 -58 ct p ef +pom +gr +gs +pum +9377 14319 t +18 87 m 54 64 69 51 87 28 ct 121 -15 138 -64 138 -122 ct 138 -185 120 -233 77 -283 ct +58 -307 45 -318 20 -334 ct 20 -334 20 -334 14 -326 ct 53 -295 66 -277 79 -240 ct +91 -207 96 -170 96 -120 ct 96 -69 90 -28 77 2 ct 63 33 49 51 14 79 ct 14 79 14 79 18 87 ct +p ef +pom +gr +gr +gs +gs +pum +8742 14186 t +45 -147 m 114 -290 l 183 -147 l 216 -147 l 128 -327 l 99 -327 l 12 -147 l +45 -147 l p ef +pom +gr +gr +gs +gs +pum +14351 14292 t +7 -199 m 14 -200 17 -201 23 -201 ct 51 -201 58 -188 81 -103 ct 89 -71 101 -13 101 -4 ct +101 4 98 11 91 20 ct 76 41 66 54 60 59 ct 50 70 44 74 38 74 ct 35 74 31 73 26 69 ct +18 63 13 60 7 60 ct -3 60 -12 69 -12 80 ct -12 92 -1 102 13 102 ct 45 102 110 27 163 -71 ct +197 -131 210 -167 210 -191 ct 210 -206 198 -219 183 -219 ct 172 -219 164 -211 164 -200 ct +164 -193 168 -188 178 -181 ct 187 -176 191 -171 191 -164 ct 191 -145 172 -106 130 -36 ct +130 -36 130 -36 121 -94 ct 113 -137 85 -219 78 -219 ct 78 -219 78 -219 76 -219 ct +76 -218 74 -218 72 -218 ct 67 -217 49 -214 23 -209 ct 21 -209 14 -208 7 -207 ct +7 -207 7 -207 7 -199 ct p ef +pom +gr +gs +pum +14571 14292 t +143 -334 m 107 -310 92 -297 75 -274 ct 40 -231 23 -182 23 -124 ct 23 -62 41 -13 84 37 ct +104 61 116 72 141 87 ct 141 87 141 87 147 79 ct 108 48 95 31 82 -6 ct 70 -39 65 -76 65 -126 ct +65 -178 71 -218 84 -249 ct 98 -279 112 -297 147 -326 ct 147 -326 147 -326 143 -334 ct +p ef +pom +gr +gs +pum +14736 14292 t +227 -58 m 227 -58 227 -58 217 -45 ct 203 -27 194 -19 187 -19 ct 183 -19 179 -23 179 -27 ct +179 -31 179 -31 186 -58 ct 186 -58 186 -58 214 -160 ct 216 -170 218 -181 218 -188 ct +218 -206 205 -218 186 -218 ct 154 -218 123 -189 72 -110 ct 72 -110 72 -110 105 -217 ct +105 -217 105 -217 104 -218 ct 77 -213 67 -211 24 -203 ct 24 -203 24 -203 24 -195 ct +49 -195 55 -192 55 -182 ct 55 -179 55 -176 54 -173 ct 54 -173 54 -173 7 0 ct 7 0 7 0 44 0 ct +67 -78 72 -89 93 -123 ct 123 -168 148 -193 166 -193 ct 174 -193 178 -188 178 -179 ct +178 -173 175 -156 171 -141 ct 171 -141 171 -141 150 -60 ct 143 -35 142 -28 142 -23 ct +142 -4 149 4 165 4 ct 187 4 200 -6 234 -52 ct 234 -52 234 -52 227 -58 ct p ef +pom +gr +gs +pum +14986 14292 t +18 87 m 54 64 69 51 87 28 ct 121 -15 138 -64 138 -122 ct 138 -185 120 -233 77 -283 ct +58 -307 45 -318 20 -334 ct 20 -334 20 -334 14 -326 ct 53 -295 66 -277 79 -240 ct +91 -207 96 -170 96 -120 ct 96 -69 90 -28 77 2 ct 63 33 49 51 14 79 ct 14 79 14 79 18 87 ct +p ef +pom +gr +gr +tm setmatrix +0 0 t +1 1 s +0 8286 t +pom +count op_count sub {pop} repeat countdictstack dict_count sub {end} repeat b4_inc_state restore +%%PageTrailer +%%Trailer +%%EOF diff --git a/doc/echo_path.odg b/doc/echo_path.odg Binary files differnew file mode 100644 index 0000000..460af84 --- /dev/null +++ b/doc/echo_path.odg diff --git a/doc/manual.lyx b/doc/manual.lyx index 8188e41..b0c6a4a 100644 --- a/doc/manual.lyx +++ b/doc/manual.lyx @@ -1,20 +1,24 @@ -#LyX 1.4.2 created this file. For more info see http://www.lyx.org/ +#LyX 1.4.4 created this file. For more info see http://www.lyx.org/ \lyxformat 245 \begin_document \begin_header -\textclass article +\textclass scrbook \language english \inputencoding auto \fontscheme pslatex \graphics default -\paperfontsize default -\spacing onehalf +\paperfontsize 10 +\spacing single \papersize letterpaper -\use_geometry false -\use_amsmath 1 +\use_geometry true +\use_amsmath 2 \cite_engine basic \use_bibtopic false \paperorientation portrait +\leftmargin 2cm +\topmargin 2cm +\rightmargin 2cm +\bottommargin 2cm \secnumdepth 3 \tocdepth 3 \paragraph_separation indent @@ -32,7 +36,7 @@ \begin_layout Title The Speex Codec Manual \newline -(version 1.2-beta1) +For Version 1.2 Beta 2 \end_layout \begin_layout Author @@ -42,7 +46,24 @@ Jean-Marc Valin \begin_layout Standard \newpage -Copyright (c) 2002-2006 Jean-Marc Valin/Xiph.org Foundation + +\end_layout + +\begin_layout Standard +Copyright +\begin_inset ERT +status collapsed + +\begin_layout Standard + + +\backslash +copyright +\end_layout + +\end_inset + + 2002-2007 Jean-Marc Valin/Xiph.org Foundation \end_layout \begin_layout Standard @@ -78,127 +99,130 @@ on License". \end_layout -\begin_layout Section +\begin_layout Chapter Introduction to Speex \end_layout \begin_layout Standard -The Speex project ( +The Speex codec ( \family typewriter http://www.speex.org/ \family default -) has been started because there was a need for a speech codec that was - open-source and free from software patents. - These are essential conditions for being used by any open-source software. - There is already Vorbis that does general audio, but it is not really suitable - for speech. - Also, unlike many other speech codecs, Speex is not targeted at cell phones - but rather at voice over IP (VoIP) and file-based compression. +) exists because there is a need for a speech codec that is open-source + and free from software patent royalties. + These are essential conditions for being usable by any open-source software. + In essence, Speex is to speech what Vorbis is to audio/music. + Unlike many other speech codecs, Speex is not designed for mobile phones + but rather for packet networks and voice over IP (VoIP) application. + File-based compression is of course also supported. \end_layout \begin_layout Standard -As design goals, we wanted to have a codec that would allow both very good - quality speech and low bit-rate (unfortunately not at the same time!), - which led us to developing a codec with multiple bit-rates. - Of course very good quality also meant we had to do wideband (16 kHz sampling - rate) in addition to narrowband (telephone quality, 8 kHz sampling rate). +The Speex codec is designed to be very flexible and support a wide range + of speech quality and bit-rate. + Support for very good quality speech also means that Speex can encode wideband + speech (16 kHz sampling rate) in addition to narrowband speech (telephone + quality, 8 kHz sampling rate). \end_layout \begin_layout Standard -Designing for VoIP instead of cell phone use means that Speex must be robust - to lost packets, but not to corrupted ones since packets either arrive - unaltered or don't arrive at all. - Also, the idea was to have a reasonable complexity and memory requirement - without compromising too much on the efficiency of the codec. +Designing for VoIP instead of mobile phones means that Speex is robust to + lost packets, but not to corrupted ones. + This is based on the assumption that in VoIP, packets either arrive unaltered + or don't arrive at all. + Because Speex is targeted at a wide range of devices, it has modest complexity + (variable) and memory footprint. \end_layout \begin_layout Standard -All this led us to the choice of CELP +All the design goals led to the choice of CELP \begin_inset LatexCommand \index{CELP} \end_inset - as the encoding technique to use for Speex. - One of the main reasons is that CELP has long proved that it could do the - job and scale well to both low bit-rates (think DoD CELP @ 4.8 kbps) and - high bit-rates (think G.728 @ 16 kbps). + as the encoding technique. + One of the main reasons is that CELP has long proved that it could work + reliably and scale well to both low bit-rates (e.g. + DoD CELP @ 4.8 kbps) and high bit-rates (e.g. + G.728 @ 16 kbps). \end_layout -\begin_layout Standard -The main characteristics can be summarized as follows: -\end_layout - -\begin_layout Itemize -Free software/open-source -\begin_inset LatexCommand \index{open-source} +\begin_layout Section +Getting help +\begin_inset LatexCommand \label{sec:Getting-help} \end_inset -, patent -\begin_inset LatexCommand \index{patent} -\end_inset +\end_layout - and royalty-free +\begin_layout Standard +As for many open source projects, there are many ways to get help with Speex. + These include: \end_layout \begin_layout Itemize -Integration of narrowband -\begin_inset LatexCommand \index{narrowband} - -\end_inset - - and wideband -\begin_inset LatexCommand \index{wideband} - -\end_inset - - using an embedded bit-stream +This manual \end_layout \begin_layout Itemize -Wide range of bit-rates available (from 2 kbps to 44 kbps) +Other documentation on the Speex website (http://www.speex.org/) \end_layout \begin_layout Itemize -Dynamic bit-rate switching and Variable Bit-Rate -\begin_inset LatexCommand \index{variable bit-rate} - -\end_inset - - (VBR) +Mailing list: Discuss any Speex-related topic on speex-dev@xiph.org (not + just for developers) \end_layout \begin_layout Itemize -Voice Activity Detection -\begin_inset LatexCommand \index{voice activity detection} - -\end_inset - - (VAD, integrated with VBR) +IRC: The main channel is #speex on irc.freenode.net. + Note that due to time differences, it may take a while to get someone, + so please be patient. \end_layout \begin_layout Itemize -Variable complexity -\begin_inset LatexCommand \index{complexity} - -\end_inset - - +Email the author privately at jean-marc.valin@usherbrooke.ca +\series bold +only +\series default + for private/delicate topics you do not wish to discuss publically. \end_layout -\begin_layout Itemize -Ultra-wideband mode at 32 kHz (up to 48 kHz) +\begin_layout Standard +Before asking for help (mailing list or IRC), +\series bold +it is important to first read this manual +\series default +. + It is generally considered rude to ask on a mailing list about topics that + are clearly detailed in the documentation. + On the other hand, it's perfectly OK (and encouraged) to ask for clarifications + about something covered in the manual. + This manual does not (yet) cover everything about Speex, so everyone is + encouraged to ask questions, send comments, feature requests, or just let + us know how Speex is being used. + \end_layout -\begin_layout Itemize -Intensity stereo encoding option +\begin_layout Standard +Here are some additional guidelines related to the mailing list. + Before reporting bugs in Speex to the list, it is strongly recommended + (if possible) to first test whether these bugs can be reproduced using + the speexenc and speexdec (see Section +\begin_inset LatexCommand \ref{sec:Command-line-encoder/decoder} + +\end_inset + +) command-line utilities. + Bugs reported based on 3rd party code are both harder to find and far too + often caused by errors that have nothing to do with Speex. + \end_layout -\begin_layout Itemize -Fixed-point implementation (work in progress) +\begin_layout Section +About this document \end_layout \begin_layout Standard @@ -208,27 +232,40 @@ This document is divided in the following way. \end_inset - describes the different Speex features and defines some terms that will - be used in later sections. + describes the different Speex features and defines many basic terms that + are used throughout this manual. Section \begin_inset LatexCommand \ref{sec:Command-line-encoder/decoder} \end_inset - provides information about the standard command-line tools, while + documents the standard command-line tools provided in the Speex distribution. + Section \begin_inset LatexCommand \ref{sec:Programming-with-Speex} \end_inset - contains information about programming using the Speex API. + includes detailed instructions about programming using the libspeex +\begin_inset LatexCommand \index{libspeex} + +\end_inset + + API. Section \begin_inset LatexCommand \ref{sec:Formats-and-standards} \end_inset has some information related to Speex and standards. - The three last sections describe the internals of the codec and require - some signal processing knowledge. + +\end_layout + +\begin_layout Standard +The three last sections describe the algorithms used in Speex. + These sections require signal processing knowledge, but are not required + for merely using Speex. + They are intended for people who want to understand how Speex really works + and/or want to do research based on Speex. Section \begin_inset LatexCommand \ref{sec:Introduction-to-CELP} @@ -245,8 +282,6 @@ This document is divided in the following way. \end_inset are specific to Speex. - Note that if you are only interested in using Speex, those three last sections - are not required. \end_layout \begin_layout Standard @@ -255,7 +290,7 @@ This document is divided in the following way. \end_layout -\begin_layout Section +\begin_layout Chapter Codec description \begin_inset LatexCommand \label{sec:Feature-description} @@ -265,17 +300,18 @@ Codec description \end_layout \begin_layout Standard -This section describes the main features provided by Speex. +This section describes Speex and its features into more details. \end_layout -\begin_layout Subsection +\begin_layout Section Concepts \end_layout \begin_layout Standard -Here are some concepts in speech coding that help better understand the - rest of the manual. - Emphasis is placed on the Speex features. +Before introducing all the Speex features, here are some concepts in speech + coding that help better understand the rest of the manual. + Although some are general concepts in speech/audio processing, others are + specific to Speex. \end_layout \begin_layout Subsection* @@ -288,8 +324,25 @@ Sampling rate \end_layout \begin_layout Standard -Speex is mainly designed for 3 different sampling rates: 8 kHz, 16 kHz, - and 32 kHz. +The sampling rate expressed in Hertz (Hz) is the number of samples taken + from a signal per second. + For a sampling rate of +\begin_inset Formula $F_{s}$ +\end_inset + + kHz, the highest frequency that can be represented is equal to +\begin_inset Formula $F_{s}/2$ +\end_inset + + kHz ( +\begin_inset Formula $F_{s}/2$ +\end_inset + + is known as the Nyquist frequency). + This is a fundamental property in signal processing and is described by + the sampling theorem. + Speex is mainly designed for three different sampling rates: 8 kHz, 16 + kHz, and 32 kHz. These are respectively refered to as narrowband \begin_inset LatexCommand \index{narrowband} @@ -306,20 +359,50 @@ Speex is mainly designed for 3 different sampling rates: 8 kHz, 16 kHz, \end_inset . - For a sampling rate of -\begin_inset Formula $F_{s}$ -\end_inset - - kHz, the highest frequency that can be represented is equal to -\begin_inset Formula $F_{s}/2$ -\end_inset + +\end_layout - kHz. - This is a consequence of Nyquist's sampling theorem (and -\begin_inset Formula $F_{s}/2$ -\end_inset +\begin_layout Subsection* +Bit-rate +\end_layout - is known as the Nyquist frequency). +\begin_layout Standard +When encoding a speech signal, the bit-rate is defined as the number of + bits per unit of time required to encode the speech. + It is measured in +\emph on +bits per second +\emph default + (bps), or generally +\emph on +kilobits per second +\emph default +. + It is important to make the distinction between +\emph on +kilo +\series bold +bits +\series default + per second +\emph default + (k +\series bold +b +\series default +ps) and +\emph on +kilo +\series bold +bytes +\series default + per second +\emph default + (k +\series bold +B +\series default +ps). \end_layout \begin_layout Subsection* @@ -328,12 +411,16 @@ Quality \end_inset - + (variable) \end_layout \begin_layout Standard -Speex encoding is controlled most of the time by a quality parameter that - ranges from 0 to 10. +Speex is a lossy codec, which means that it achives compression at the expense + of fidelity of the input speech signal. + Unlike some other speech codecs, it is possible to control the tradeoff + made between quality and bit-rate. + The Speex encoding process is controlled most of the time by a quality + parameter that ranges from 0 to 10. In constant bit-rate \begin_inset LatexCommand \index{constant bit-rate} @@ -480,15 +567,16 @@ Perceptual enhancement \end_layout \begin_layout Standard -Perceptual enhancement is a part of the decoder which, when turned on, tries - to reduce (the perception of) the noise produced by the coding/decoding - process. - In most cases, perceptual enhancement make the sound further from the original - +Perceptual enhancement is a part of the decoder which, when turned on, attempts + to reduce the perception of the noise/distortion produced by the encoding/decod +ing process. + In most cases, perceptual enhancement brings the sound further from the + original \emph on objectively \emph default - (if you use SNR), but in the end it still + (e.g. + considering only SNR), but in the end it still \emph on sounds \emph default @@ -496,7 +584,7 @@ sounds \end_layout \begin_layout Subsection* -Algorithmic delay +Latency and algorithmic delay \begin_inset LatexCommand \index{algorithmic delay} \end_inset @@ -521,11 +609,90 @@ look-ahead the frames. \end_layout -\begin_layout Subsection +\begin_layout Section Codec \end_layout -\begin_layout Subsection +\begin_layout Standard +The main characteristics of Speex can be summarized as follows: +\end_layout + +\begin_layout Itemize +Free software/open-source +\begin_inset LatexCommand \index{open-source} + +\end_inset + +, patent +\begin_inset LatexCommand \index{patent} + +\end_inset + + and royalty-free +\end_layout + +\begin_layout Itemize +Integration of narrowband +\begin_inset LatexCommand \index{narrowband} + +\end_inset + + and wideband +\begin_inset LatexCommand \index{wideband} + +\end_inset + + using an embedded bit-stream +\end_layout + +\begin_layout Itemize +Wide range of bit-rates available (from 2.15 kbps to 44 kbps) +\end_layout + +\begin_layout Itemize +Dynamic bit-rate switching (AMR) and Variable Bit-Rate +\begin_inset LatexCommand \index{variable bit-rate} + +\end_inset + + (VBR) operation +\end_layout + +\begin_layout Itemize +Voice Activity Detection +\begin_inset LatexCommand \index{voice activity detection} + +\end_inset + + (VAD, integrated with VBR) and discontinuous transmission (DTX) +\end_layout + +\begin_layout Itemize +Variable complexity +\begin_inset LatexCommand \index{complexity} + +\end_inset + + +\end_layout + +\begin_layout Itemize +Embedded wideband structure (scalable sampling rate) +\end_layout + +\begin_layout Itemize +Ultra-wideband mode at 32 kHz +\end_layout + +\begin_layout Itemize +Intensity stereo encoding option +\end_layout + +\begin_layout Itemize +Fixed-point implementation +\end_layout + +\begin_layout Section Preprocessor \end_layout @@ -540,7 +707,7 @@ before \end_layout \begin_layout Itemize -denoising +noise suppression \end_layout \begin_layout Itemize @@ -579,26 +746,112 @@ The voice activity detector (VAD) provided by the preprocessor is more advanced \end_layout -\begin_layout Subsection +\begin_layout Section Adaptive Jitter Buffer \end_layout -\begin_layout Subsection +\begin_layout Standard +When transmitting voice (or any content for that matter) over UDP or RTP, + packet may be lost, arrive with different delay, or even out of order. + The purpose of a jitter buffer is to reorder packets and buffer them long + enough (but no longer than necessary) so they can be sent to be decoded. + +\end_layout + +\begin_layout Section Acoustic Echo Canceller \end_layout \begin_layout Standard +In any hands-free communication system (Fig. + +\begin_inset LatexCommand \ref{fig:Acoustic-echo-model} + +\end_inset + +), speech from the remote end is played in the local loudspeaker, propagates + in the room and is captured by the microphone. + If the audio captured from the microphone is sent directly to the remote + end, then the remove user hears an echo of his voice. + An acoustic echo canceller is designed to remove the acoustic echo before + it is sent to the remote end. + It is important to understand that the echo canceller is meant to improve + the quality on the +\series bold +remote +\series default + end. +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Standard +\begin_inset ERT +status collapsed + +\begin_layout Standard + + +\backslash +begin{center} +\end_layout + +\end_inset + + +\begin_inset Graphics + filename echo_path.eps + width 10cm + +\end_inset + + +\begin_inset ERT +status collapsed + +\begin_layout Standard + + +\backslash +end{center} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Caption +Acoustic echo model +\begin_inset LatexCommand \label{fig:Acoustic-echo-model} + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard \newpage \end_layout -\begin_layout Section +\begin_layout Chapter Compiling \end_layout \begin_layout Standard -Compiling Speex under UNIX or any platform supported by autoconf (e.g. +Compiling Speex under UNIX/Linux or any other platform supported by autoconf + (e.g. Win32/cygwin) is as easy as typing: \end_layout @@ -619,7 +872,8 @@ The options supported by the Speex configure script are: \end_layout \begin_layout Description ---prefix=<path> Specifies where to install Speex +--prefix=<path> Specifies the base path for installing Speex (e.g. + /usr) \end_layout \begin_layout Description @@ -631,13 +885,13 @@ The options supported by the Speex configure script are: \end_layout \begin_layout Description ---disable-wideband Disable the wideband part of Speex (typically to same +--disable-wideband Disable the wideband part of Speex (typically to save space) \end_layout \begin_layout Description ---enable-valgrind Enable extra information when (and only when) running - with valgrind +--enable-valgrind Enable extra hits for valgrind for debugging purposes + (do not use by default) \end_layout \begin_layout Description @@ -688,8 +942,94 @@ The options supported by the Speex configure script are: \end_layout \begin_layout Description ---enable-16bit-precision Reduces precision to 16 bits in time-critical areas - (fixed-point only) +--enable-vorbis-psycho Make the encoder use the Vorbis psycho-acoustic model. + This is very experimental and may be removed in the future. +\end_layout + +\begin_layout Section +Platforms +\end_layout + +\begin_layout Standard +Speex is known to compile and work on a large number of architectures, both + floating-point and fixed-point. + In general, any architecture that can natively compute the multiplication + of two signed 16-bit numbers (32-bit result) and runs at a sufficient clock + rate (architecture-dependent) is capable of running Speex. + Architectures that are +\series bold +known +\series default + to be supported (it probably works on many others) are: +\end_layout + +\begin_layout Itemize +x86 & x86-64 +\end_layout + +\begin_layout Itemize +Power +\end_layout + +\begin_layout Itemize +SPARC +\end_layout + +\begin_layout Itemize +ARM +\end_layout + +\begin_layout Itemize +Blackfin +\end_layout + +\begin_layout Itemize +TI C54xx & C55xx +\end_layout + +\begin_layout Itemize +TI C6xxx +\end_layout + +\begin_layout Itemize +TriMedia (experimental) +\end_layout + +\begin_layout Standard +Operating systems on top of which Speex is known to work include (it probably + works on many others): +\end_layout + +\begin_layout Itemize +Linux +\end_layout + +\begin_layout Itemize +\begin_inset Formula $\mu$ +\end_inset + +Clinux +\end_layout + +\begin_layout Itemize +MacOS X +\end_layout + +\begin_layout Itemize +BSD +\end_layout + +\begin_layout Itemize +Other UNIX/POSIX variants +\end_layout + +\begin_layout Itemize +Symbian +\end_layout + +\begin_layout Standard +The source code directory include additional information for compiling on + certain architectures or operating systems in README.xxx files. \end_layout \begin_layout Standard @@ -698,7 +1038,7 @@ The options supported by the Speex configure script are: \end_layout -\begin_layout Section +\begin_layout Chapter Command-line encoder/decoder \begin_inset LatexCommand \label{sec:Command-line-encoder/decoder} @@ -720,7 +1060,7 @@ speexdec This section describes how to use these tools. \end_layout -\begin_layout Subsection +\begin_layout Section \emph on speexenc @@ -826,7 +1166,7 @@ n Set encoding speed/quality tradeoff. (-v) Print version information \end_layout -\begin_layout Subsubsection* +\begin_layout Subsection* Speex comments \end_layout @@ -846,7 +1186,7 @@ Speex comments \end_layout -\begin_layout Subsubsection* +\begin_layout Subsection* Raw input options \end_layout @@ -875,7 +1215,7 @@ n Sampling rate for raw input --16bit Raw input is 16-bit signed \end_layout -\begin_layout Subsection +\begin_layout Section \emph on speexdec @@ -963,7 +1303,7 @@ n Simulate n % random packet loss \end_layout -\begin_layout Section +\begin_layout Chapter Programming with Speex (the libspeex \begin_inset LatexCommand \index{libspeex} @@ -984,15 +1324,16 @@ Programming with Speex (the libspeex \begin_layout Standard This section explains how to use the Speex API. - Examples of code can also be found in appendix + Examples of code can also be found in Appendix \begin_inset LatexCommand \ref{sec:Sample-code} \end_inset -. + and the complete API documentation is included in the Documentation section + of the Speex website (http://www.speex.org/). \end_layout -\begin_layout Subsection +\begin_layout Section Encoding \begin_inset LatexCommand \label{sub:Encoding} @@ -1002,7 +1343,7 @@ Encoding \end_layout \begin_layout Standard -In order to encode speech using Speex, you first need to: +In order to encode speech using Speex, one first needs to: \end_layout \begin_layout LyX-Code @@ -1010,7 +1351,7 @@ In order to encode speech using Speex, you first need to: \end_layout \begin_layout Standard -You then need to declare a Speex bit-packing struct +Then a Speex bit-packing struct must be declared as: \end_layout \begin_layout LyX-Code @@ -1018,7 +1359,7 @@ SpeexBits bits; \end_layout \begin_layout Standard -and a Speex encoder state +along with a Speex encoder state \end_layout \begin_layout LyX-Code @@ -1053,7 +1394,11 @@ speex_wb_mode \emph on frame_size \emph default - variable with: + variable (expressed in +\series bold +samples +\series default +, not bytes) with: \end_layout \begin_layout LyX-Code @@ -1066,6 +1411,29 @@ In practice, frame_size \emph default will correspond to 20 ms when using 8, 16, or 32 kHz sampling rate. + There are many parameters that can be set for the Speex encoder, but the + most useful one is the quality parameter that controls the quality vs bit-rate + tradeoff. + This is set by: +\end_layout + +\begin_layout LyX-Code +speex_encoder_ctl(enc_state,SPEEX_SET_QUALITY,&quality); +\end_layout + +\begin_layout Standard +where +\emph on +quality +\emph default + is an integer value ranging from 0 to 10 (inclusively). + The mapping between quality and bit-rate is described in Fig. + +\begin_inset LatexCommand \ref{cap:quality_vs_bps} + +\end_inset + + for narrowband. \end_layout \begin_layout Standard @@ -1172,7 +1540,7 @@ That's about it for the encoder. \end_layout -\begin_layout Subsection +\begin_layout Section Decoding \begin_inset LatexCommand \label{sub:Decoding} @@ -1232,7 +1600,11 @@ speex_wb_mode \emph on frame_size \emph default - variable with: + variable (expressed in +\series bold +samples +\series default +, not bytes) with: \end_layout \begin_layout LyX-Code @@ -1288,7 +1660,7 @@ output_frame (short *) \emph default and points to the area where the decoded speech frame will be written. - A NULL value as the first argument indicates that we don't have the bits + A NULL value as the second argument indicates that we don't have the bits for the current frame. When a frame is lost, the Speex decoder will do its best to "guess" the correct signal. @@ -1318,7 +1690,7 @@ speex_bits_destroy(&bits); speex_decoder_destroy(dec_state); \end_layout -\begin_layout Subsection +\begin_layout Section Preprocessor \begin_inset LatexCommand \label{sub:Preprocessor} @@ -1366,7 +1738,7 @@ For each input frame, you need to call: \end_layout \begin_layout LyX-Code -speex_preprocess(preprocess_state, audio_frame, echo_residue); +speex_preprocess_run(preprocess_state, audio_frame); \end_layout \begin_layout Standard @@ -1374,12 +1746,7 @@ where \family typewriter audio_frame \family default - is used both as input and output and -\family typewriter -echo_residue -\family default - is either an array filled by the echo canceller, or NULL if the preprocessor - is used without the echo canceller. + is used both as input and output. \end_layout \begin_layout Standard @@ -1388,7 +1755,7 @@ In cases where the output audio is not useful for a certain frame, it is \end_layout \begin_layout LyX-Code -speex_preprocess_estimate_update(preprocess_state, audio_frame, echo_residue); +speex_preprocess_estimate_update(preprocess_state, audio_frame); \end_layout \begin_layout Standard @@ -1417,7 +1784,7 @@ The preprocessor state can be destroyed using: speex_preprocess_state_destroy(preprocess_state); \end_layout -\begin_layout Subsection +\begin_layout Section Echo Cancellation \begin_inset LatexCommand \label{sub:Echo-Cancellation} @@ -1488,7 +1855,7 @@ Once the echo canceller state is created, audio can be processed by: \end_layout \begin_layout LyX-Code -speex_echo_cancel(echo_state, input_frame, echo_frame, output_frame, residue); +speex_echo_cancellation(echo_state, input_frame, echo_frame, output_frame); \end_layout \begin_layout Standard @@ -1506,13 +1873,6 @@ echo_frame output_frame \family default is the signal with echo removed. - The -\family typewriter -residue -\family default - parameter is optional (you can set it to NULL) and is used to return the - estimated power spectrum of the echo residue so it can be removed by the - preprocessor (if you with to use it). \end_layout @@ -1549,32 +1909,38 @@ read_from_soundcard(input_frame, frame_size); \end_layout \begin_layout LyX-Code -speex_echo_cancel(echo_state, input_frame, echo_frame, output_frame, residue); +speex_echo_cancellation(echo_state, input_frame, echo_frame, output_frame); \end_layout \begin_layout Standard -As stated above, if you wish to further reduce the echo present in the signal, - you can do so by passing -\family typewriter -residue -\family default - as the last parameter of +If you wish to further reduce the echo present in the signal, you can do + so by \family typewriter -speex_preprocess() +associating the echo canceller to the preprocessor \family default - function (see Section + (see Section \begin_inset LatexCommand \ref{sub:Preprocessor} \end_inset ). + This is done by calling: +\end_layout + +\begin_layout LyX-Code +speex_preprocess_ctl(preprocess_state, SPEEX_PREPROCESS_SET_ECHO_STATE, + echo_state); +\end_layout + +\begin_layout Standard +in the initialisation. \end_layout \begin_layout Standard -As of version 1.2-beta1, there is an alternative, simpler API that can be +As of version 1.2-beta2, there is an alternative, simpler API that can be used instead of \emph on -speex_echo_cancel() +speex_echo_cancellation() \emph default . When audio capture and playback are handled asynchronously (e.g. @@ -1601,7 +1967,7 @@ every time an audio frame is played. \end_layout \begin_layout LyX-Code -speex_echo_capture(echo_state, input_frame, output_frame, residue); +speex_echo_capture(echo_state, input_frame, output_frame); \end_layout \begin_layout Standard @@ -1619,12 +1985,13 @@ speex_echo_capture() speex_echo_cancel() \emph default . - When capture and playback are done synchronously, + A side effect of using this alternate API is that the playback audio is + delayed by two frames, which is the normal delay caused by the soundcard. + When capture and playback are already synchronised, \emph on -speex_echo_cancel() +speex_echo_cancellation() \emph default - is still prefered since it gives better control on the exact input/echo - timing. + is preferable since it gives better control on the exact input/echo timing. \end_layout \begin_layout Standard @@ -1644,7 +2011,7 @@ It is also possible to reset the state of the echo canceller so it can be speex_echo_state_reset(echo_state); \end_layout -\begin_layout Subsubsection +\begin_layout Subsection Troubleshooting \end_layout @@ -1730,7 +2097,139 @@ http://www.embeddedstar.com/articles/2003/7/article20030720-1.html same. \end_layout +\begin_layout Standard +As of version 1.2beta2, a new +\family typewriter +echo_diagnostic.m +\family default + tool is included in the source distribution. + The first step is to define DUMP_ECHO_CANCEL_DATA during the build. + This causes the echo canceller to automatically save the near-end, far-end + and output signals to files (aec_rec.sw aec_play.sw and aec_out.sw). + These are exactly what the AEC receives and outputs. + From there, it is necessary to start Octave and type: +\end_layout + +\begin_layout LyX-Code +echo_diagnostic('aec_rec.sw', 'aec_play.sw', 'aec_diagnostic.sw', 1024); +\end_layout + +\begin_layout Standard +The value of 1024 is the filter length and can be changed. + There will be some (hopefully) useful messages printed and echo cancelled + audio will be saved to aec_diagnostic.sw . + If even that output is bad (almost no cancellation) then there is probably + problem with the playback or recording process. +\end_layout + +\begin_layout Section +Jitter Buffer +\end_layout + +\begin_layout Standard +There are two jitter buffers. + Both can be enabled by including: +\end_layout + +\begin_layout LyX-Code +#include <speex/speex_jitter.c> +\end_layout + +\begin_layout Subsection +Generic Jitter Buffer +\end_layout + \begin_layout Subsection +Speex Jitter Buffer +\end_layout + +\begin_layout Section +Resampler +\end_layout + +\begin_layout Standard +As of version 1.2beta2, Speex includes a resampling modules. + To make use of the resampler, it is necessary to include its header file: +\end_layout + +\begin_layout LyX-Code +#include <speex/speex_resampler.h> +\end_layout + +\begin_layout Standard +For each stream that is to be resampled, it is necessary to create a resampler + state with: +\end_layout + +\begin_layout LyX-Code +SpeexResamplerState *resampler; +\end_layout + +\begin_layout LyX-Code +resampler = speex_resampler_init(nb_channels, input_rate, output_rate, quality, + &err); +\end_layout + +\begin_layout Standard +where nb_channels is the number of channels that will be used (either interleave +d or non-interleaved), input_rate is the sampling rate of the input stream, + output_rate is the sampling rate of the output stream and quality is the + requested quality setting (0 to 10). + The quality parameter is useful for controlling the quality/complexity/latency + tradeoff. + Using a higher quality setting means less noise/aliasing, a higher complexity + and a higher latency. + Usually, a quality of 3 is acceptable for most desktop uses and quality + 10 is mostly recommended for pro audio work. + Quality 0 usually has a decent sound (certainly better than using linear + interpolation resampling), but artifacts may be heard. +\end_layout + +\begin_layout Standard +The actual resampling is performed using +\end_layout + +\begin_layout LyX-Code +err = speex_resampler_process_int(resampler, channelID, in, &in_length, + out, &out_length); +\end_layout + +\begin_layout Standard +where channelID is the ID of the channel to be processed. + For a mono stream, use 0. + The +\emph on +in +\emph default + pointer points to the first sample of the input buffer for the selected + channel and +\emph on +out +\emph default + points to the first sample of the output. + The size of the input and output buffers are specified by +\emph on +in_length +\emph default + and +\emph on +out_length +\emph default + respectively. + Upon completion, these values are replaced by the number of samples read + and written by the resampler. + Unless an error occurs, either all input samples will be read or all output + samples will be written to (or both). + For floating-point samples, the function speex_resampler_process_float() + behaves similarly. +\end_layout + +\begin_layout Standard +It is also possible to process multiple channels at once. + +\end_layout + +\begin_layout Section Codec Options (speex_*_ctl) \begin_inset LatexCommand \label{sub:Codec-Options} @@ -1739,6 +2238,20 @@ Codec Options (speex_*_ctl) \end_layout +\begin_layout Quote +\align center + +\emph on +Entities should not be multiplied beyond necessity -- William of Ockham. +\end_layout + +\begin_layout Quote +\align center + +\emph on +Just because there's an option doesn't mean you have to use it -- me. +\end_layout + \begin_layout Standard The Speex encoder and decoder support many options and requests that can be accessed through the @@ -1750,6 +2263,13 @@ speex_encoder_ctl speex_decoder_ctl \emph default functions. + Despite that, the defaults are good for many applications and +\series bold +optional settings should only be used when one understands them and knows + that they are needed +\series default +. + A common error is to attempt to set many unnecessary settings. These functions are similar to the \emph on ioctl @@ -1784,7 +2304,8 @@ SPEEX_GET_ENH** Get perceptual enhancer status (integer) \end_layout \begin_layout Description -SPEEX_GET_FRAME_SIZE Get the frame size used for the current mode (integer) +SPEEX_GET_FRAME_SIZE Get the number of samples per frame for the current + mode (integer) \end_layout \begin_layout Description @@ -1962,7 +2483,7 @@ SPEEX_GET_PLC_TUNING* Get the current tuning of the encoder for PLC (integer normally only used internally \end_layout -\begin_layout Subsection +\begin_layout Section Mode queries \begin_inset LatexCommand \label{sub:Mode-queries} @@ -2006,7 +2527,7 @@ ptr \end_layout -\begin_layout Subsection +\begin_layout Section Preprocessor options \begin_inset LatexCommand \label{sub:Preprocessor-options} @@ -2074,7 +2595,62 @@ SPEEX_PREPROCESS_SET_DEREVERB_DECAY SPEEX_PREPROCESS_GET_DEREVERB_DECAY \end_layout -\begin_layout Subsection +\begin_layout Description +SPEEX_PREPROCESS_SET_PROB_START +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_GET_PROB_START +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_SET_PROB_CONTINUE +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_GET_PROB_CONTINUE +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_SET_NOISE_SUPPRESS Set maximum attenuation of the noise + in dB (negative number) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_GET_NOISE_SUPPRESS Get maximum attenuation of the noise + in dB (negative number) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_SET_ECHO_SUPPRESS Set maximum attenuation of the residual + echo in dB (negative number) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_GET_ECHO_SUPPRESS Set maximum attenuation of the residual + echo in dB (negative number) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE Set maximum attenuation of the + echo in dB when near end is active (negative number) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE Set maximum attenuation of the + echo in dB when near end is active (negative number) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_SET_ECHO_STATE Set the associated echo canceller for residual + echo suppression (NULL for no residual echo suppression) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_GET_ECHO_STATE Get the associated echo canceller +\end_layout + +\begin_layout Section Packing and in-band signalling \begin_inset LatexCommand \index{in-band signalling} @@ -2145,6 +2721,19 @@ sideways false status open \begin_layout Standard +\begin_inset ERT +status collapsed + +\begin_layout Standard + + +\backslash +begin{center} +\end_layout + +\end_inset + + \begin_inset Tabular <lyxtabular version="3" rows="17" columns="3"> <features> @@ -2657,6 +3246,19 @@ reserved \end_inset +\begin_inset ERT +status collapsed + +\begin_layout Standard + + +\backslash +end{center} +\end_layout + +\end_inset + + \end_layout \begin_layout Caption @@ -2685,7 +3287,7 @@ Finally, applications may define custom in-band messages using mode 13. \end_layout -\begin_layout Section +\begin_layout Chapter Formats and standards \begin_inset LatexCommand \index{standards} @@ -2744,7 +3346,7 @@ For encoders, at least one narrowband or wideband mode MUST be supported. some modes. \end_layout -\begin_layout Subsection +\begin_layout Section RTP \begin_inset LatexCommand \index{RTP} @@ -2770,7 +3372,7 @@ The RTP payload draft is included in appendix \end_layout -\begin_layout Subsection +\begin_layout Section MIME Type \end_layout @@ -2783,7 +3385,7 @@ audio/speex in the near future. \end_layout -\begin_layout Subsection +\begin_layout Section Ogg \begin_inset LatexCommand \index{Ogg} @@ -3427,7 +4029,7 @@ clearpage \end_layout -\begin_layout Section +\begin_layout Chapter Introduction to CELP Coding \begin_inset LatexCommand \index{CELP} @@ -3441,6 +4043,14 @@ Introduction to CELP Coding \end_layout +\begin_layout Quote +\align center + +\emph on +Do not meddle in the affairs of poles, for they are subtle and quick to + leave the unit circle. +\end_layout + \begin_layout Standard Speex is based on CELP, which stands for Code Excited Linear Prediction. This section attempts to introduce the principles behind CELP, so if you @@ -3479,7 +4089,7 @@ This section describes the basic ideas behind CELP. This is still a work in progress. \end_layout -\begin_layout Subsection +\begin_layout Section Source-Filter Model of Speech Prediction \end_layout @@ -3572,7 +4182,7 @@ The CELP model of speech synthesis (decoder) \end_layout -\begin_layout Subsection +\begin_layout Section Linear Prediction (LPC) \begin_inset LatexCommand \index{linear prediction} @@ -3742,7 +4352,7 @@ Because to filtering in the frequency domain, reducing sharp resonances. \end_layout -\begin_layout Subsection +\begin_layout Section Pitch Prediction \begin_inset LatexCommand \index{pitch} @@ -3792,7 +4402,7 @@ where . \end_layout -\begin_layout Subsection +\begin_layout Section Innovation Codebook \end_layout @@ -3847,7 +4457,7 @@ X(z)=\frac{C(z)}{A(z)\left(1-\beta z^{-T}\right)}\] \end_layout -\begin_layout Subsection +\begin_layout Section Noise Weighting \begin_inset LatexCommand \index{error weighting} @@ -4034,7 +4644,7 @@ Standard noise shaping in CELP. \end_layout -\begin_layout Subsection +\begin_layout Section Analysis-by-Synthesis \end_layout @@ -4070,7 +4680,7 @@ In order to achieve real-time encoding using limited computing resources, \end_layout -\begin_layout Section +\begin_layout Chapter Speex narrowband mode \begin_inset LatexCommand \label{sec:Speex-narrowband-mode} @@ -4115,7 +4725,7 @@ Dynamically-selectable codebooks (LSP, pitch and innovation) sub-vector fixed (innovation) codebooks \end_layout -\begin_layout Subsection +\begin_layout Section Whole-Frame Analysis \begin_inset LatexCommand \index{linear prediction} @@ -4239,7 +4849,7 @@ Frame open-loop analysis \end_layout -\begin_layout Subsection +\begin_layout Section Sub-Frame Analysis-by-Synthesis \end_layout @@ -4407,7 +5017,7 @@ n (fixed codebook) signal instead of an algebraic codebook. \end_layout -\begin_layout Subsection +\begin_layout Section Bit allocation \end_layout @@ -4448,6 +5058,19 @@ sideways false status open \begin_layout Standard +\begin_inset ERT +status collapsed + +\begin_layout Standard + + +\backslash +begin{center} +\end_layout + +\end_inset + + \begin_inset Tabular <lyxtabular version="3" rows="12" columns="11"> <features> @@ -5679,6 +6302,19 @@ frame \end_inset +\begin_inset ERT +status collapsed + +\begin_layout Standard + + +\backslash +end{center} +\end_layout + +\end_inset + + \end_layout \begin_layout Caption @@ -5731,12 +6367,26 @@ sideways false status open \begin_layout Standard +\begin_inset ERT +status collapsed + +\begin_layout Standard + + +\backslash +begin{center} +\end_layout + +\end_inset + + \begin_inset Tabular -<lyxtabular version="3" rows="17" columns="4"> +<lyxtabular version="3" rows="17" columns="5"> <features> <column alignment="center" valignment="top" leftline="true" width="0pt"> <column alignment="center" valignment="top" leftline="true" width="0pt"> <column alignment="center" valignment="top" leftline="true" width="0pt"> +<column alignment="center" valignment="top" leftline="true" width="0pt"> <column alignment="center" valignment="top" leftline="true" rightline="true" width="0pt"> <row topline="true" bottomline="true"> <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none"> @@ -5752,6 +6402,15 @@ Mode \begin_inset Text \begin_layout Standard +Quality +\end_layout + +\end_inset +</cell> +<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none"> +\begin_inset Text + +\begin_layout Standard Bit-rate \begin_inset LatexCommand \index{bit-rate} @@ -5800,6 +6459,15 @@ Quality/description \begin_inset Text \begin_layout Standard +- +\end_layout + +\end_inset +</cell> +<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none"> +\begin_inset Text + +\begin_layout Standard 250 \end_layout @@ -5809,7 +6477,7 @@ Quality/description \begin_inset Text \begin_layout Standard -N/A +0 \end_layout \end_inset @@ -5838,6 +6506,15 @@ No transmission (DTX) \begin_inset Text \begin_layout Standard +0 +\end_layout + +\end_inset +</cell> +<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none"> +\begin_inset Text + +\begin_layout Standard 2,150 \end_layout @@ -5876,6 +6553,15 @@ Vocoder (mostly for comfort noise) \begin_inset Text \begin_layout Standard +2 +\end_layout + +\end_inset +</cell> +<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none"> +\begin_inset Text + +\begin_layout Standard 5,950 \end_layout @@ -5914,6 +6600,15 @@ Very noticeable artifacts/noise, good intelligibility \begin_inset Text \begin_layout Standard +3-4 +\end_layout + +\end_inset +</cell> +<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none"> +\begin_inset Text + +\begin_layout Standard 8,000 \end_layout @@ -5952,6 +6647,15 @@ Artifacts/noise sometimes noticeable \begin_inset Text \begin_layout Standard +5-6 +\end_layout + +\end_inset +</cell> +<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none"> +\begin_inset Text + +\begin_layout Standard 11,000 \end_layout @@ -5990,6 +6694,15 @@ Artifacts usually noticeable only with headphones \begin_inset Text \begin_layout Standard +7-8 +\end_layout + +\end_inset +</cell> +<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none"> +\begin_inset Text + +\begin_layout Standard 15,000 \end_layout @@ -6028,6 +6741,15 @@ Need good headphones to tell the difference \begin_inset Text \begin_layout Standard +9 +\end_layout + +\end_inset +</cell> +<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none"> +\begin_inset Text + +\begin_layout Standard 18,200 \end_layout @@ -6066,6 +6788,15 @@ Hard to tell the difference even with good headphones \begin_inset Text \begin_layout Standard +10 +\end_layout + +\end_inset +</cell> +<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none"> +\begin_inset Text + +\begin_layout Standard 24,600 \end_layout @@ -6104,6 +6835,15 @@ Completely transparent for voice, good quality music \begin_inset Text \begin_layout Standard +1 +\end_layout + +\end_inset +</cell> +<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none"> +\begin_inset Text + +\begin_layout Standard 3,950 \end_layout @@ -6142,7 +6882,7 @@ Very noticeable artifacts/noise, good intelligibility \begin_inset Text \begin_layout Standard -N/A +- \end_layout \end_inset @@ -6151,7 +6891,16 @@ N/A \begin_inset Text \begin_layout Standard -N/A +- +\end_layout + +\end_inset +</cell> +<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none"> +\begin_inset Text + +\begin_layout Standard +- \end_layout \end_inset @@ -6180,7 +6929,7 @@ reserved \begin_inset Text \begin_layout Standard -N/A +- \end_layout \end_inset @@ -6189,7 +6938,16 @@ N/A \begin_inset Text \begin_layout Standard -N/A +- +\end_layout + +\end_inset +</cell> +<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none"> +\begin_inset Text + +\begin_layout Standard +- \end_layout \end_inset @@ -6218,7 +6976,16 @@ reserved \begin_inset Text \begin_layout Standard -N/A +- +\end_layout + +\end_inset +</cell> +<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none"> +\begin_inset Text + +\begin_layout Standard +- \end_layout \end_inset @@ -6227,7 +6994,7 @@ N/A \begin_inset Text \begin_layout Standard -N/A +- \end_layout \end_inset @@ -6256,7 +7023,7 @@ reserved \begin_inset Text \begin_layout Standard -N/A +- \end_layout \end_inset @@ -6265,7 +7032,16 @@ N/A \begin_inset Text \begin_layout Standard -N/A +- +\end_layout + +\end_inset +</cell> +<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none"> +\begin_inset Text + +\begin_layout Standard +- \end_layout \end_inset @@ -6294,7 +7070,16 @@ reserved \begin_inset Text \begin_layout Standard -N/A +- +\end_layout + +\end_inset +</cell> +<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none"> +\begin_inset Text + +\begin_layout Standard +- \end_layout \end_inset @@ -6303,7 +7088,7 @@ N/A \begin_inset Text \begin_layout Standard -N/A +- \end_layout \end_inset @@ -6332,7 +7117,7 @@ Application-defined, interpreted by callback or skipped \begin_inset Text \begin_layout Standard -N/A +- \end_layout \end_inset @@ -6341,7 +7126,16 @@ N/A \begin_inset Text \begin_layout Standard -N/A +- +\end_layout + +\end_inset +</cell> +<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none"> +\begin_inset Text + +\begin_layout Standard +- \end_layout \end_inset @@ -6370,7 +7164,7 @@ Speex in-band signaling \begin_inset Text \begin_layout Standard -N/A +- \end_layout \end_inset @@ -6379,7 +7173,16 @@ N/A \begin_inset Text \begin_layout Standard -N/A +- +\end_layout + +\end_inset +</cell> +<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none"> +\begin_inset Text + +\begin_layout Standard +- \end_layout \end_inset @@ -6399,6 +7202,19 @@ Terminator code \end_inset +\begin_inset ERT +status collapsed + +\begin_layout Standard + + +\backslash +end{center} +\end_layout + +\end_inset + + \end_layout \begin_layout Caption @@ -6415,7 +7231,7 @@ Quality versus bit-rate \end_layout -\begin_layout Subsection +\begin_layout Section Perceptual enhancement \begin_inset LatexCommand \index{perceptual enhancement} @@ -6476,7 +7292,7 @@ where \end_layout -\begin_layout Section +\begin_layout Chapter Speex wideband mode (sub-band CELP) \begin_inset LatexCommand \index{wideband} @@ -6529,7 +7345,7 @@ embedded narrowband bit-stream encoding is described in this section. \end_layout -\begin_layout Subsection +\begin_layout Section Linear Prediction \end_layout @@ -6542,7 +7358,7 @@ The linear prediction part used for the high-band is very similar to what is then quantized using 6 bits, too. \end_layout -\begin_layout Subsection +\begin_layout Section Pitch Prediction \end_layout @@ -6557,7 +7373,7 @@ That part is easy: there's no pitch prediction for the high-band. (pitch). \end_layout -\begin_layout Subsection +\begin_layout Section Excitation Quantization \end_layout @@ -6566,7 +7382,7 @@ The high-band excitation is coded in the same way as for narrowband. \end_layout -\begin_layout Subsection +\begin_layout Section Bit allocation \end_layout @@ -6599,6 +7415,19 @@ sideways false status open \begin_layout Standard +\begin_inset ERT +status collapsed + +\begin_layout Standard + + +\backslash +begin{center} +\end_layout + +\end_inset + + \begin_inset Tabular <lyxtabular version="3" rows="7" columns="7"> <features> @@ -7069,6 +7898,19 @@ frame \end_inset +\begin_inset ERT +status collapsed + +\begin_layout Standard + + +\backslash +end{center} +\end_layout + +\end_inset + + \end_layout \begin_layout Caption @@ -7117,7 +7959,7 @@ clearpage \end_layout -\begin_layout Section +\begin_layout Chapter \start_of_appendix FAQ \end_layout @@ -7458,7 +8300,7 @@ d as a sum of unit pulses, thus making the codebook search much more efficient. \end_layout -\begin_layout Section +\begin_layout Chapter Sample code \begin_inset LatexCommand \label{sec:Sample-code} @@ -7482,7 +8324,7 @@ where both files are raw (no header) files encoded at 16 bits per sample (in the machine natural endianness). \end_layout -\begin_layout Subsection +\begin_layout Section sampleenc.c \end_layout @@ -7501,7 +8343,7 @@ preview false \end_layout -\begin_layout Subsection +\begin_layout Section sampledec.c \end_layout @@ -7526,7 +8368,7 @@ preview false \end_layout -\begin_layout Section +\begin_layout Chapter IETF RTP Profile \begin_inset LatexCommand \label{sec:IETF-draft} @@ -7550,7 +8392,7 @@ preview false \end_layout -\begin_layout Section +\begin_layout Chapter Speex License \begin_inset LatexCommand \label{sec:Speex-License} @@ -7602,7 +8444,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS \end_layout -\begin_layout Section +\begin_layout Chapter GNU Free Documentation License \end_layout @@ -7618,7 +8460,7 @@ Copyright (C) 2000 Free Software Foundation, Inc. \end_layout -\begin_layout Subsection* +\begin_layout Section* 0. PREAMBLE \end_layout @@ -7652,7 +8494,7 @@ We have designed this License in order to use it for manuals for free software, \end_layout -\begin_layout Subsection* +\begin_layout Section* 1. APPLICABILITY AND DEFINITIONS \end_layout @@ -7730,7 +8572,7 @@ The "Title Page" means, for a printed book, the title page itself, plus preceding the beginning of the body of the text. \end_layout -\begin_layout Subsection* +\begin_layout Section* 2. VERBATIM COPYING \end_layout @@ -7753,7 +8595,7 @@ You may also lend copies, under the same conditions stated above, and you may publicly display copies. \end_layout -\begin_layout Subsection* +\begin_layout Section* 3. COPYING IN QUANTITY \end_layout @@ -7802,7 +8644,7 @@ It is requested, but not required, that you contact the authors of the Document \end_layout -\begin_layout Subsection* +\begin_layout Section* 4. MODIFICATIONS \end_layout @@ -7954,7 +8796,7 @@ nt of any Modified Version. \end_layout -\begin_layout Subsection* +\begin_layout Section* 5. COMBINING DOCUMENTS \end_layout @@ -7986,7 +8828,7 @@ In the combination, you must combine any sections entitled "History" in You must delete all sections entitled "Endorsements." \end_layout -\begin_layout Subsection* +\begin_layout Section* 6. COLLECTIONS OF DOCUMENTS \end_layout @@ -8007,7 +8849,7 @@ You may extract a single document from such a collection, and distribute \end_layout -\begin_layout Subsection* +\begin_layout Section* 7. AGGREGATION WITH INDEPENDENT WORKS \end_layout @@ -8031,7 +8873,7 @@ If the Cover Text requirement of section 3 is applicable to these copies Otherwise they must appear on covers around the whole aggregate. \end_layout -\begin_layout Subsection* +\begin_layout Section* 8. TRANSLATION \end_layout @@ -8049,7 +8891,7 @@ Translation is considered a kind of modification, so you may distribute version of this License, the original English version will prevail. \end_layout -\begin_layout Subsection* +\begin_layout Section* 9. TERMINATION \end_layout @@ -8065,7 +8907,7 @@ You may not copy, modify, sublicense, or distribute the Document except \end_layout -\begin_layout Subsection* +\begin_layout Section* 10. FUTURE REVISIONS OF THIS LICENSE \end_layout diff --git a/include/speex/Makefile.am b/include/speex/Makefile.am index f7b65fa..08cd88b 100644 --- a/include/speex/Makefile.am +++ b/include/speex/Makefile.am @@ -11,5 +11,6 @@ pkginclude_HEADERS = speex.h \ speex_stereo.h \ speex_preprocess.h \ speex_jitter.h \ - speex_echo.h + speex_echo.h \ + speex_resampler.h diff --git a/include/speex/speex.h b/include/speex/speex.h index 7f8afa6..f17fa19 100644 --- a/include/speex/speex.h +++ b/include/speex/speex.h @@ -35,6 +35,10 @@ #ifndef SPEEX_H #define SPEEX_H +/** @defgroup Codec Speex encoder and decoder + * This is the Speex codec itself. + * @{ + */ #include "speex/speex_bits.h" #include "speex/speex_types.h" @@ -151,20 +155,6 @@ extern "C" { /** Get status of input/output high-pass filtering */ #define SPEEX_GET_HIGHPASS 45 -/* Used internally, NOT TO BE USED in applications */ -/** Used internally*/ -#define SPEEX_GET_PI_GAIN 100 -/** Used internally*/ -#define SPEEX_GET_EXC 101 -/** Used internally*/ -#define SPEEX_GET_INNOV 102 -/** Used internally*/ -#define SPEEX_GET_DTX_STATUS 103 -/** Used internally*/ -#define SPEEX_SET_INNOVATION_SAVE 104 -/** Used internally*/ -#define SPEEX_SET_WIDEBAND 105 - /* Preserving compatibility:*/ /** Equivalent to SPEEX_SET_ENH */ @@ -307,7 +297,7 @@ typedef struct SpeexMode { * encode, you need one state per channel. * * @param mode The mode to use (either speex_nb_mode or speex_wb.mode) - * @return A newly created encoder + * @return A newly created encoder state or NULL if state allocation fails */ void *speex_encoder_init(const SpeexMode *mode); @@ -318,7 +308,9 @@ void speex_encoder_destroy(void *state); /** Uses an existing encoder state to encode one frame of speech pointed to by "in". The encoded bit-stream is saved in "bits". @param state Encoder state - @param in Frame that will be encoded with a +-2^15 range + @param in Frame that will be encoded with a +-2^15 range. This data MAY be + overwritten by the encoder and should be considered uninitialised + after the call. @param bits Bit-stream where the data will be written @return 0 if frame needs not be transmitted (DTX only), 1 otherwise */ @@ -338,7 +330,7 @@ int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits); * @param state Encoder state * @param request ioctl-type request (one of the SPEEX_* macros) * @param ptr Data exchanged to-from function - * @return 0 if no error, -1 if request in unknown + * @return 0 if no error, -1 if request in unknown, -2 for invalid parameter */ int speex_encoder_ctl(void *state, int request, void *ptr); @@ -349,7 +341,7 @@ int speex_encoder_ctl(void *state, int request, void *ptr); * decode, you need one state per channel. * * @param mode Speex mode (one of speex_nb_mode or speex_wb_mode) - * @return A newly created decoder state + * @return A newly created decoder state or NULL if state allocation fails */ void *speex_decoder_init(const SpeexMode *mode); @@ -384,7 +376,7 @@ int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out); * @param state Decoder state * @param request ioctl-type request (one of the SPEEX_* macros) * @param ptr Data exchanged to-from function - * @return 0 if no error, -1 if request in unknown + * @return 0 if no error, -1 if request in unknown, -2 for invalid parameter */ int speex_decoder_ctl(void *state, int request, void *ptr); @@ -394,12 +386,14 @@ int speex_decoder_ctl(void *state, int request, void *ptr); * @param mode Speex mode * @param request ioctl-type request (one of the SPEEX_* macros) * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown, -2 for invalid parameter */ int speex_mode_query(const SpeexMode *mode, int request, void *ptr); /** Functions for controlling the behavior of libspeex * @param request ioctl-type request (one of the SPEEX_LIB_* macros) * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown, -2 for invalid parameter */ int speex_lib_ctl(int request, void *ptr); @@ -427,5 +421,5 @@ const SpeexMode * speex_lib_get_mode (int mode); } #endif - +/** @}*/ #endif diff --git a/include/speex/speex_bits.h b/include/speex/speex_bits.h index b77202f..88334c4 100644 --- a/include/speex/speex_bits.h +++ b/include/speex/speex_bits.h @@ -35,6 +35,11 @@ #ifndef BITS_H #define BITS_H +/** @defgroup SpeexBits SpeexBits: Bit-stream manipulations + * This is the structure that holds the bit-stream when encoding or decoding + * with Speex. It allows some manipulations as well. + * @{ + */ #ifdef __cplusplus extern "C" { @@ -72,13 +77,20 @@ void speex_bits_rewind(SpeexBits *bits); void speex_bits_read_from(SpeexBits *bits, char *bytes, int len); /** Append bytes to the bit-stream + * * @param bits Bit-stream to operate on * @param bytes pointer to the bytes what will be appended * @param len Number of bytes of append */ void speex_bits_read_whole_bytes(SpeexBits *bits, char *bytes, int len); -/** Write the content of a bit-stream to an area of memory */ +/** Write the content of a bit-stream to an area of memory + * + * @param bits Bit-stream to operate on + * @param bytes Memory location where to write the bits + * @param max_len Maximum number of bytes to write (i.e. size of the "bytes" buffer) + * @return Number of bytes written to the "bytes" buffer +*/ int speex_bits_write(SpeexBits *bits, char *bytes, int max_len); /** Like speex_bits_write, but writes only the complete bytes in the stream. Also removes the written bytes from the stream */ @@ -114,13 +126,19 @@ unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits); */ int speex_bits_nbytes(SpeexBits *bits); -/** Same as speex_bits_unpack_unsigned, but without modifying the cursor position */ +/** Same as speex_bits_unpack_unsigned, but without modifying the cursor position + * + * @param bits Bit-stream to operate on + * @param nbBits Number of bits to look for + * @return Value of the bits peeked, interpreted as unsigned + */ unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits); /** Get the value of the next bit in the stream, without modifying the * "cursor" position * * @param bits Bit-stream to operate on + * @return Value of the bit peeked (one bit only) */ int speex_bits_peek(SpeexBits *bits); @@ -134,6 +152,7 @@ void speex_bits_advance(SpeexBits *bits, int n); /** Returns the number of bits remaining to be read in a stream * * @param bits Bit-stream to operate on + * @return Number of bits that can still be read from the stream */ int speex_bits_remaining(SpeexBits *bits); @@ -148,4 +167,5 @@ void speex_bits_insert_terminator(SpeexBits *bits); } #endif +/* @} */ #endif diff --git a/include/speex/speex_callbacks.h b/include/speex/speex_callbacks.h index f6334f2..7892e2f 100644 --- a/include/speex/speex_callbacks.h +++ b/include/speex/speex_callbacks.h @@ -35,6 +35,9 @@ #ifndef SPEEX_CALLBACKS_H #define SPEEX_CALLBACKS_H +/** @defgroup SpeexCallbacks Various definitions for Speex callbacks supported by the decoder. + * @{ + */ #include "speex.h" @@ -110,13 +113,16 @@ int speex_default_user_handler(SpeexBits *bits, void *state, void *data); - +/** Standard handler for low mode request (change low mode, no questions asked) */ int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data); +/** Standard handler for VBR request (Set VBR, no questions asked) */ int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data); +/** Standard handler for enhancer request (Turn ehnancer on/off, no questions asked) */ int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data); +/** Standard handler for VBR quality request (Set VBR quality, no questions asked) */ int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data); @@ -124,5 +130,5 @@ int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *da } #endif - +/** @} */ #endif diff --git a/include/speex/speex_echo.h b/include/speex/speex_echo.h index 2bf8e3f..f5e4b89 100644 --- a/include/speex/speex_echo.h +++ b/include/speex/speex_echo.h @@ -55,16 +55,19 @@ struct SpeexEchoState_; typedef struct SpeexEchoState_ SpeexEchoState; /** Creates a new echo canceller state */ -SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length, int nb_mic, int nb_speakers); +SpeexEchoState *mc_echo_state_init(int frame_size, int filter_length, int nb_mic, int nb_speakers); /** Destroys an echo canceller state */ void mc_echo_state_destroy(SpeexEchoState *st); /** Performs echo cancellation a frame */ +void mc_echo_cancellation(SpeexEchoState *st, const spx_int16_t *rec, const spx_int16_t *play, spx_int16_t *out); + +/** Performs echo cancellation a frame */ void mc_echo_cancel(SpeexEchoState *st, const spx_int16_t *rec, const spx_int16_t *play, spx_int16_t *out, spx_int32_t *Yout); /** Perform echo cancellation using internal playback buffer */ -void mc_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out, spx_int32_t *Yout); +void mc_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out); /** Let the echo canceller know that a frame was just played */ void mc_echo_playback(SpeexEchoState *st, const spx_int16_t *play); diff --git a/include/speex/speex_header.h b/include/speex/speex_header.h index 32fb81f..5416459 100644 --- a/include/speex/speex_header.h +++ b/include/speex/speex_header.h @@ -36,6 +36,10 @@ #ifndef SPEEX_HEADER_H #define SPEEX_HEADER_H +/** @defgroup SpeexHeader SpeexHeader: Makes it easy to write/parse an Ogg/Speex header + * This is the Speex header for the Ogg encapsulation. You don't need that if you just use RTP. + * @{ + */ #include "speex/speex_types.h" @@ -45,6 +49,7 @@ extern "C" { struct SpeexMode; +/** Length of the Speex header identifier */ #define SPEEX_HEADER_STRING_LENGTH 8 /** Maximum number of characters for encoding the Speex version number in the header */ @@ -82,5 +87,5 @@ SpeexHeader *speex_packet_to_header(char *packet, int size); } #endif - +/** @} */ #endif diff --git a/include/speex/speex_jitter.h b/include/speex/speex_jitter.h index 34043b3..570e22b 100644 --- a/include/speex/speex_jitter.h +++ b/include/speex/speex_jitter.h @@ -35,6 +35,11 @@ #ifndef SPEEX_JITTER_H #define SPEEX_JITTER_H +/** @defgroup JitterBuffer JitterBuffer: Adaptive jitter buffer + * This is the jitter buffer that reorders UDP/RTP packets and adjusts the buffer size + * to maintain good quality and low latency. + * @{ + */ #include "speex.h" #include "speex_bits.h" @@ -43,58 +48,128 @@ extern "C" { #endif +/** Generic adaptive jitter buffer state */ struct JitterBuffer_; +/** Generic adaptive jitter buffer state */ typedef struct JitterBuffer_ JitterBuffer; +/** Definition of an incoming packet */ typedef struct _JitterBufferPacket JitterBufferPacket; +/** Definition of an incoming packet */ struct _JitterBufferPacket { - char *data; - spx_uint32_t len; - spx_uint32_t timestamp; - spx_uint32_t span; + char *data; /**< Data bytes contained in the packet */ + spx_uint32_t len; /**< Length of the packet in bytes */ + spx_uint32_t timestamp; /**< Timestamp for the packet */ + spx_uint32_t span; /**< Time covered by the packet (same units as timestamp) */ }; - +/** Packet has been retrieved */ #define JITTER_BUFFER_OK 0 +/** Packet is missing */ #define JITTER_BUFFER_MISSING 1 +/** Packet is incomplete (does not cover the entive tick */ #define JITTER_BUFFER_INCOMPLETE 2 +/** There was an error in the jitter buffer */ #define JITTER_BUFFER_INTERNAL_ERROR -1 +/** Invalid argument */ #define JITTER_BUFFER_BAD_ARGUMENT -2 -/** Initialise jitter buffer */ + +/** Set minimum amount of extra buffering required (margin) */ +#define JITTER_BUFFER_SET_MARGIN 0 +/** Get minimum amount of extra buffering required (margin) */ +#define JITTER_BUFFER_GET_MARGIN 1 +/* JITTER_BUFFER_SET_AVALIABLE_COUNT wouldn't make sense */ +/** Get the amount of avaliable packets currently buffered */ +#define JITTER_BUFFER_GET_AVALIABLE_COUNT 3 + +#define JITTER_BUFFER_ADJUST_INTERPOLATE -1 +#define JITTER_BUFFER_ADJUST_OK 0 +#define JITTER_BUFFER_ADJUST_DROP 1 + +/** Initialises jitter buffer + * + * @param tick Number of samples per "tick", i.e. the time period of the elements that will be retrieved + * @return Newly created jitter buffer state + */ JitterBuffer *jitter_buffer_init(int tick); -/** Reset jitter buffer */ +/** Restores jitter buffer to its original state + * + * @param jitter Jitter buffer state + */ void jitter_buffer_reset(JitterBuffer *jitter); -/** Destroy jitter buffer */ +/** Destroys jitter buffer + * + * @param jitter Jitter buffer state + */ void jitter_buffer_destroy(JitterBuffer *jitter); -/** Put one packet into the jitter buffer */ +/** Put one packet into the jitter buffer + * + * @param jitter Jitter buffer state + * @param packet Incoming packet +*/ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet); -/** Get one packet from the jitter buffer */ -int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint32_t *current_timestamp); +/** Get one packet from the jitter buffer + * + * @param jitter Jitter buffer state + * @param packet Returned packet + * @param current_timestamp Timestamp for the returned packet +*/ +int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset); -/** Get pointer timestamp of jitter buffer */ +/** Get pointer timestamp of jitter buffer + * + * @param jitter Jitter buffer state +*/ int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter); -/** Advance by one tick */ +/** Advance by one tick + * + * @param jitter Jitter buffer state +*/ void jitter_buffer_tick(JitterBuffer *jitter); +/** Used like the ioctl function to control the jitter buffer parameters + * + * @param jitter Jitter buffer state + * @param request ioctl-type request (one of the JITTER_BUFFER_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown +*/ +int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr); + +int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset); + +/* @} */ -/** Speex jitter-buffer state. */ +/** @defgroup SpeexJitter SpeexJitter: Adaptive jitter buffer specifically for Speex + * This is the jitter buffer that reorders UDP/RTP packets and adjusts the buffer size + * to maintain good quality and low latency. This is a simplified version that works only + * with Speex, but is much easier to use. + * @{ +*/ + +/** Speex jitter-buffer state. Never use it directly! */ typedef struct SpeexJitter { - SpeexBits current_packet; /**< Current Speex packet */ - int valid_bits; /**< True if Speex bits are valid */ - JitterBuffer *packets; - void *dec; /**< Pointer to Speex decoder */ - int frame_size; /**< Frame size of Speex decoder */ + SpeexBits current_packet; /**< Current Speex packet */ + int valid_bits; /**< True if Speex bits are valid */ + JitterBuffer *packets; /**< Generic jitter buffer state */ + void *dec; /**< Pointer to Speex decoder */ + spx_int32_t frame_size; /**< Frame size of Speex decoder */ } SpeexJitter; -/** Initialise jitter buffer */ +/** Initialise jitter buffer + * + * @param jitter State of the Speex jitter buffer + * @param decoder Speex decoder to call + * @param sampling_rate Sampling rate used by the decoder +*/ void speex_jitter_init(SpeexJitter *jitter, void *decoder, int sampling_rate); /** Destroy jitter buffer */ @@ -113,5 +188,5 @@ int speex_jitter_get_pointer_timestamp(SpeexJitter *jitter); } #endif - +/* @} */ #endif diff --git a/include/speex/speex_preprocess.h b/include/speex/speex_preprocess.h index 5bb3a2c..59b0aab 100644 --- a/include/speex/speex_preprocess.h +++ b/include/speex/speex_preprocess.h @@ -1,8 +1,10 @@ /* Copyright (C) 2003 Epic Games Written by Jean-Marc Valin */ /** - @file speex_preprocess.h - @brief Speex preprocessor + * @file speex_preprocess.h + * @brief Speex preprocessor. The preprocess can do noise suppression, + * residual echo suppression (after using the echo canceller), automatic + * gain control (AGC) and voice activity detection (VAD). */ /* Redistribution and use in source and binary forms, with or without @@ -34,91 +36,61 @@ #ifndef SPEEX_PREPROCESS_H #define SPEEX_PREPROCESS_H +/** @defgroup SpeexPreprocessState SpeexPreprocessState: The Speex preprocessor + * This is the Speex preprocessor. The preprocess can do noise suppression, + * residual echo suppression (after using the echo canceller), automatic + * gain control (AGC) and voice activity detection (VAD). + * @{ + */ #include "speex/speex_types.h" #ifdef __cplusplus extern "C" { #endif + +/** State of the preprocessor (one per channel). Should never be accessed directly. */ +struct SpeexPreprocessState_; -struct drft_lookup; +/** State of the preprocessor (one per channel). Should never be accessed directly. */ +typedef struct SpeexPreprocessState_ SpeexPreprocessState; -/** Speex pre-processor state. */ -typedef struct SpeexPreprocessState { - int frame_size; /**< Number of samples processed each time */ - int ps_size; /**< Number of points in the power spectrum */ - int sampling_rate; /**< Sampling rate of the input/output */ - - /* parameters */ - int denoise_enabled; - int agc_enabled; - float agc_level; - int vad_enabled; - int dereverb_enabled; - float reverb_decay; - float reverb_level; - float speech_prob_start; - float speech_prob_continue; - - float *frame; /**< Processing frame (2*ps_size) */ - float *ps; /**< Current power spectrum */ - float *gain2; /**< Adjusted gains */ - float *window; /**< Analysis/Synthesis window */ - float *noise; /**< Noise estimate */ - float *reverb_estimate; /**< Estimate of reverb energy */ - float *old_ps; /**< Power spectrum for last frame */ - float *gain; /**< Ephraim Malah gain */ - float *prior; /**< A-priori SNR */ - float *post; /**< A-posteriori SNR */ - - float *S; /**< Smoothed power spectrum */ - float *Smin; /**< See Cohen paper */ - float *Stmp; /**< See Cohen paper */ - float *update_prob; /**< Propability of speech presence for noise update */ - - float *zeta; /**< Smoothed a priori SNR */ - float Zpeak; - float Zlast; - - float *loudness_weight; /**< Perceptual loudness curve */ - - float *echo_noise; - - float *noise_bands; - float *noise_bands2; - int noise_bandsN; - float *speech_bands; - float *speech_bands2; - int speech_bandsN; - - float *inbuf; /**< Input buffer (overlapped analysis) */ - float *outbuf; /**< Output buffer (for overlap and add) */ - - float speech_prob; - int last_speech; - float loudness; /**< loudness estimate */ - float loudness2; /**< loudness estimate */ - int nb_adapt; /**< Number of frames used for adaptation so far */ - int nb_loudness_adapt; /**< Number of frames used for loudness adaptation so far */ - int consec_noise; /**< Number of consecutive noise frames */ - int nb_preprocess; /**< Number of frames processed so far */ - struct drft_lookup *fft_lookup; /**< Lookup table for the FFT */ - -} SpeexPreprocessState; - -/** Creates a new preprocessing state */ + +/** Creates a new preprocessing state. You MUST create one state per channel processed. + * @param frame_size Number of samples to process at one time (should correspond to 10-20 ms). Must be + * the same value as that used for the echo canceller for residual echo cancellation to work. + * @param sampling_rate Sampling rate used for the input. + * @return Newly created preprocessor state +*/ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate); -/** Destroys a denoising state */ +/** Destroys a preprocessor state + * @param st Preprocessor state to destroy +*/ void speex_preprocess_state_destroy(SpeexPreprocessState *st); -/** Preprocess a frame */ +/** Preprocess a frame + * @param st Preprocessor state + * @param x Audio sample vector (in and out). Must be same size as specified in speex_preprocess_state_init(). + * @return Bool value for voice activity (1 for speech, 0 for noise/silence), ONLY if VAD turned on. +*/ +int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x); + +/** Preprocess a frame (deprecated, use speex_preprocess_run() instead)*/ int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo); -/** Preprocess a frame */ -void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo); +/** Update preprocessor state, but do not compute the output + * @param st Preprocessor state + * @param x Audio sample vector (in only). Must be same size as specified in speex_preprocess_state_init(). +*/ +void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x); -/** Used like the ioctl function to control the preprocessor parameters */ +/** Used like the ioctl function to control the preprocessor parameters + * @param st Preprocessor state + * @param request ioctl-type request (one of the SPEEX_PREPROCESS_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown +*/ int speex_preprocess_ctl(SpeexPreprocessState *st, int request, void *ptr); @@ -158,14 +130,57 @@ int speex_preprocess_ctl(SpeexPreprocessState *st, int request, void *ptr); /** Get preprocessor dereverb decay */ #define SPEEX_PREPROCESS_GET_DEREVERB_DECAY 13 +/** Set probability required for the VAD to go from silence to voice */ #define SPEEX_PREPROCESS_SET_PROB_START 14 +/** Get probability required for the VAD to go from silence to voice */ #define SPEEX_PREPROCESS_GET_PROB_START 15 +/** Set probability required for the VAD to stay in the voice state (integer percent) */ #define SPEEX_PREPROCESS_SET_PROB_CONTINUE 16 +/** Get probability required for the VAD to stay in the voice state (integer percent) */ #define SPEEX_PREPROCESS_GET_PROB_CONTINUE 17 +/** Set maximum attenuation of the noise in dB (negative number) */ +#define SPEEX_PREPROCESS_SET_NOISE_SUPPRESS 18 +/** Get maximum attenuation of the noise in dB (negative number) */ +#define SPEEX_PREPROCESS_GET_NOISE_SUPPRESS 19 + +/** Set maximum attenuation of the residual echo in dB (negative number) */ +#define SPEEX_PREPROCESS_SET_ECHO_SUPPRESS 20 +/** Get maximum attenuation of the residual echo in dB (negative number) */ +#define SPEEX_PREPROCESS_GET_ECHO_SUPPRESS 21 + +/** Set maximum attenuation of the residual echo in dB when near end is active (negative number) */ +#define SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE 22 +/** Get maximum attenuation of the residual echo in dB when near end is active (negative number) */ +#define SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE 23 + +/** Set the corresponding echo canceller state so that residual echo suppression can be performed (NULL for no residual echo suppression) */ +#define SPEEX_PREPROCESS_SET_ECHO_STATE 24 +/** Get the corresponding echo canceller state */ +#define SPEEX_PREPROCESS_GET_ECHO_STATE 25 + +/** Set maximal gain increase in dB/second (int32) */ +#define SPEEX_PREPROCESS_SET_AGC_INCREMENT 26 + +/** Get maximal gain increase in dB/second (int32) */ +#define SPEEX_PREPROCESS_GET_AGC_INCREMENT 27 + +/** Set maximal gain decrease in dB/second (int32) */ +#define SPEEX_PREPROCESS_SET_AGC_DECREMENT 28 + +/** Get maximal gain decrease in dB/second (int32) */ +#define SPEEX_PREPROCESS_GET_AGC_DECREMENT 29 + +/** Set maximal gain in dB (int32) */ +#define SPEEX_PREPROCESS_SET_AGC_MAX_GAIN 30 + +/** Get maximal gain in dB (int32) */ +#define SPEEX_PREPROCESS_GET_AGC_MAX_GAIN 31 + #ifdef __cplusplus } #endif +/** @}*/ #endif diff --git a/include/speex/speex_resampler.h b/include/speex/speex_resampler.h new file mode 100644 index 0000000..c44fbcd --- /dev/null +++ b/include/speex/speex_resampler.h @@ -0,0 +1,328 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: speex_resampler.h + Resampling code + + The design goals of this code are: + - Very fast algorithm + - Low memory requirement + - Good *perceptual* quality (and not best SNR) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 SPEEX_RESAMPLER_H +#define SPEEX_RESAMPLER_H + +#ifdef OUTSIDE_SPEEX + +/********* WARNING: MENTAL SANITY ENDS HERE *************/ + +/* If the resampler is defined outside of Speex, we change the symbol names so that + there won't be any clash if linking with Speex later on. */ + +/* #define RANDOM_PREFIX your software name here */ +#ifndef RANDOM_PREFIX +#error "Please define RANDOM_PREFIX (above) to something specific to your project to prevent symbol name clashes" +#endif + +#define CAT_PREFIX2(a,b) a ## b +#define CAT_PREFIX(a,b) CAT_PREFIX2(a, b) + +#define speex_resampler_init CAT_PREFIX(RANDOM_PREFIX,_resampler_init) +#define speex_resampler_init_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_init_frac) +#define speex_resampler_destroy CAT_PREFIX(RANDOM_PREFIX,_resampler_destroy) +#define speex_resampler_process_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_float) +#define speex_resampler_process_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_int) +#define speex_resampler_process_interleaved_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_float) +#define speex_resampler_process_interleaved_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_int) +#define speex_resampler_set_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate) +#define speex_resampler_get_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_get_rate) +#define speex_resampler_set_rate_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate_frac) +#define speex_resampler_get_ratio CAT_PREFIX(RANDOM_PREFIX,_resampler_get_ratio) +#define speex_resampler_set_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_set_quality) +#define speex_resampler_get_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_get_quality) +#define speex_resampler_set_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_input_stride) +#define speex_resampler_get_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_stride) +#define speex_resampler_set_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_output_stride) +#define speex_resampler_get_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_stride) +#define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros) +#define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem) +#define speex_resampler_strerror CAT_PREFIX(RANDOM_PREFIX,_resampler_strerror) + +#define spx_int16_t short +#define spx_int32_t int +#define spx_uint16_t unsigned short +#define spx_uint32_t unsigned int + +#else /* OUTSIDE_SPEEX */ + +#include "speex/speex_types.h" + +#endif /* OUTSIDE_SPEEX */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define SPEEX_RESAMPLER_QUALITY_MAX 10 +#define SPEEX_RESAMPLER_QUALITY_MIN 0 +#define SPEEX_RESAMPLER_QUALITY_DEFAULT 4 +#define SPEEX_RESAMPLER_QUALITY_VOIP 3 +#define SPEEX_RESAMPLER_QUALITY_DESKTOP 5 + +enum { + RESAMPLER_ERR_SUCCESS = 0, + RESAMPLER_ERR_ALLOC_FAILED = 1, + RESAMPLER_ERR_BAD_STATE = 2, + RESAMPLER_ERR_INVALID_ARG = 3, + RESAMPLER_ERR_PTR_OVERLAP = 4, + + RESAMPLER_ERR_MAX_ERROR +}; + +struct SpeexResamplerState_; +typedef struct SpeexResamplerState_ SpeexResamplerState; + +/** Create a new resampler with integer input and output rates. + * @param nb_channels Number of channels to be processed + * @param in_rate Input sampling rate (integer number of Hz). + * @param out_rate Output sampling rate (integer number of Hz). + * @param quality Resampling quality between 0 and 10, where 0 has poor quality + * and 10 has very high quality. + * @return Newly created resampler state + * @retval NULL Error: not enough memory + */ +SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, + spx_uint32_t in_rate, + spx_uint32_t out_rate, + int quality, + int *err); + +/** Create a new resampler with fractional input/output rates. The sampling + * rate ratio is an arbitrary rational number with both the numerator and + * denominator being 32-bit integers. + * @param nb_channels Number of channels to be processed + * @param ratio_num Numerator of the sampling rate ratio + * @param ratio_den Denominator of the sampling rate ratio + * @param in_rate Input sampling rate rounded to the nearest integer (in Hz). + * @param out_rate Output sampling rate rounded to the nearest integer (in Hz). + * @param quality Resampling quality between 0 and 10, where 0 has poor quality + * and 10 has very high quality. + * @return Newly created resampler state + * @retval NULL Error: not enough memory + */ +SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, + spx_uint32_t ratio_num, + spx_uint32_t ratio_den, + spx_uint32_t in_rate, + spx_uint32_t out_rate, + int quality, + int *err); + +/** Destroy a resampler state. + * @param st Resampler state + */ +void speex_resampler_destroy(SpeexResamplerState *st); + +/** Resample a float array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param channel_index Index of the channel to process for the multi-channel + * base (0 otherwise) + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the + * number of samples processed + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written + */ +int speex_resampler_process_float(SpeexResamplerState *st, + spx_uint32_t channel_index, + const float *in, + spx_uint32_t *in_len, + float *out, + spx_uint32_t *out_len); + +/** Resample an int array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param channel_index Index of the channel to process for the multi-channel + * base (0 otherwise) + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the number + * of samples processed + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written + */ +int speex_resampler_process_int(SpeexResamplerState *st, + spx_uint32_t channel_index, + const spx_int16_t *in, + spx_uint32_t *in_len, + spx_int16_t *out, + spx_uint32_t *out_len); + +/** Resample an interleaved float array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the number + * of samples processed. This is all per-channel. + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written. + * This is all per-channel. + */ +int speex_resampler_process_interleaved_float(SpeexResamplerState *st, + const float *in, + spx_uint32_t *in_len, + float *out, + spx_uint32_t *out_len); + +/** Resample an interleaved int array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the number + * of samples processed. This is all per-channel. + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written. + * This is all per-channel. + */ +int speex_resampler_process_interleaved_int(SpeexResamplerState *st, + const spx_int16_t *in, + spx_uint32_t *in_len, + spx_int16_t *out, + spx_uint32_t *out_len); + +/** Set (change) the input/output sampling rates (integer value). + * @param st Resampler state + * @param in_rate Input sampling rate (integer number of Hz). + * @param out_rate Output sampling rate (integer number of Hz). + */ +int speex_resampler_set_rate(SpeexResamplerState *st, + spx_uint32_t in_rate, + spx_uint32_t out_rate); + +/** Get the current input/output sampling rates (integer value). + * @param st Resampler state + * @param in_rate Input sampling rate (integer number of Hz) copied. + * @param out_rate Output sampling rate (integer number of Hz) copied. + */ +void speex_resampler_get_rate(SpeexResamplerState *st, + spx_uint32_t *in_rate, + spx_uint32_t *out_rate); + +/** Set (change) the input/output sampling rates and resampling ratio + * (fractional values in Hz supported). + * @param st Resampler state + * @param ratio_num Numerator of the sampling rate ratio + * @param ratio_den Denominator of the sampling rate ratio + * @param in_rate Input sampling rate rounded to the nearest integer (in Hz). + * @param out_rate Output sampling rate rounded to the nearest integer (in Hz). + */ +int speex_resampler_set_rate_frac(SpeexResamplerState *st, + spx_uint32_t ratio_num, + spx_uint32_t ratio_den, + spx_uint32_t in_rate, + spx_uint32_t out_rate); + +/** Get the current resampling ratio. This will be reduced to the least + * common denominator. + * @param st Resampler state + * @param ratio_num Numerator of the sampling rate ratio copied + * @param ratio_den Denominator of the sampling rate ratio copied + */ +void speex_resampler_get_ratio(SpeexResamplerState *st, + spx_uint32_t *ratio_num, + spx_uint32_t *ratio_den); + +/** Set (change) the conversion quality. + * @param st Resampler state + * @param quality Resampling quality between 0 and 10, where 0 has poor + * quality and 10 has very high quality. + */ +int speex_resampler_set_quality(SpeexResamplerState *st, + int quality); + +/** Get the conversion quality. + * @param st Resampler state + * @param quality Resampling quality between 0 and 10, where 0 has poor + * quality and 10 has very high quality. + */ +void speex_resampler_get_quality(SpeexResamplerState *st, + int *quality); + +/** Set (change) the input stride. + * @param st Resampler state + * @param stride Input stride + */ +void speex_resampler_set_input_stride(SpeexResamplerState *st, + spx_uint32_t stride); + +/** Get the input stride. + * @param st Resampler state + * @param stride Input stride copied + */ +void speex_resampler_get_input_stride(SpeexResamplerState *st, + spx_uint32_t *stride); + +/** Set (change) the output stride. + * @param st Resampler state + * @param stride Output stride + */ +void speex_resampler_set_output_stride(SpeexResamplerState *st, + spx_uint32_t stride); + +/** Get the output stride. + * @param st Resampler state copied + * @param stride Output stride + */ +void speex_resampler_get_output_stride(SpeexResamplerState *st, + spx_uint32_t *stride); + +/** Make sure that the first samples to go out of the resamplers don't have + * leading zeros. This is only useful before starting to use a newly created + * resampler. It is recommended to use that when resampling an audio file, as + * it will generate a file with the same length. For real-time processing, + * it is probably easier not to use this call (so that the output duration + * is the same for the first frame). + * @param st Resampler state + */ +int speex_resampler_skip_zeros(SpeexResamplerState *st); + +/** Reset a resampler so a new (unrelated) stream can be processed. + * @param st Resampler state + */ +int speex_resampler_reset_mem(SpeexResamplerState *st); + +/** Returns the English meaning for an error code + * @param err Error code + * @return English string + */ +const char *speex_resampler_strerror(int err); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/speex/speex_stereo.h b/include/speex/speex_stereo.h index 6ccaa31..45da338 100644 --- a/include/speex/speex_stereo.h +++ b/include/speex/speex_stereo.h @@ -34,6 +34,10 @@ #ifndef STEREO_H #define STEREO_H +/** @defgroup SpeexStereoState SpeexStereoState: Handling Speex stereo files + * This describes the Speex intensity stereo encoding/decoding + * @{ + */ #include "speex/speex_types.h" #include "speex/speex_bits.h" @@ -74,5 +78,5 @@ int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data); } #endif - +/** @} */ #endif diff --git a/libspeex/Makefile.am b/libspeex/Makefile.am index a784002..ff6d4bc 100644 --- a/libspeex/Makefile.am +++ b/libspeex/Makefile.am @@ -2,7 +2,7 @@ #AUTOMAKE_OPTIONS = no-dependencies -EXTRA_DIST=testenc.c testenc_wb.c testenc_uwb.c testdenoise.c testecho.c +EXTRA_DIST=echo_diagnostic.m INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_builddir) @OGG_CFLAGS@ @@ -16,7 +16,7 @@ libspeex_la_SOURCES = nb_celp.c sb_celp.c lpc.c ltp.c lsp.c quant_lsp.c \ exc_10_16_table.c exc_20_32_table.c hexc_10_32_table.c misc.c speex_header.c \ speex_callbacks.c math_approx.c stereo.c preprocess.c smallft.c lbr_48k_tables.c \ jitter.c mdf.c vorbis_psy.c fftwrap.c kiss_fft.c _kiss_fft_guts.h kiss_fft.h \ - kiss_fftr.c kiss_fftr.h window.c + kiss_fftr.c kiss_fftr.h window.c filterbank.c resample.c noinst_HEADERS = lsp.h nb_celp.h lpc.h lpc_bfin.h ltp.h quant_lsp.h \ cb_search.h filters.h stack_alloc.h vq.h vq_sse.h vq_arm4.h vq_bfin.h \ @@ -24,19 +24,19 @@ noinst_HEADERS = lsp.h nb_celp.h lpc.h lpc_bfin.h ltp.h quant_lsp.h \ ltp_bfin.h filters_sse.h filters_arm4.h filters_bfin.h math_approx.h \ smallft.h arch.h fixed_arm4.h fixed_arm5e.h fixed_bfin.h fixed_debug.h \ fixed_generic.h cb_search_sse.h cb_search_arm4.h cb_search_bfin.h vorbis_psy.h \ - fftwrap.h pseudofloat.h lsp_bfin.h quant_lsp_bfin.h + fftwrap.h pseudofloat.h lsp_bfin.h quant_lsp_bfin.h filterbank.h libspeex_la_LDFLAGS = -no-undefined -version-info @SPEEX_LT_CURRENT@:@SPEEX_LT_REVISION@:@SPEEX_LT_AGE@ noinst_PROGRAMS = testenc testenc_wb testenc_uwb testdenoise testecho testenc_SOURCES = testenc.c -testenc_LDADD = $(top_builddir)/libspeex/libspeex.la +testenc_LDADD = libspeex.la testenc_wb_SOURCES = testenc_wb.c -testenc_wb_LDADD = $(top_builddir)/libspeex/libspeex.la +testenc_wb_LDADD = libspeex.la testenc_uwb_SOURCES = testenc_uwb.c -testenc_uwb_LDADD = $(top_builddir)/libspeex/libspeex.la +testenc_uwb_LDADD = libspeex.la testdenoise_SOURCES = testdenoise.c -testdenoise_LDADD = $(top_builddir)/libspeex/libspeex.la +testdenoise_LDADD = libspeex.la testecho_SOURCES = testecho.c -testecho_LDADD = $(top_builddir)/libspeex/libspeex.la +testecho_LDADD = libspeex.la diff --git a/libspeex/_kiss_fft_guts.h b/libspeex/_kiss_fft_guts.h index 72acee1..526a73b 100644 --- a/libspeex/_kiss_fft_guts.h +++ b/libspeex/_kiss_fft_guts.h @@ -20,6 +20,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND and defines typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */ #include "kiss_fft.h" +#include "math_approx.h" #define MAXFACTORS 32 /* e.g. an fft of length 128 has 4 factors @@ -67,6 +68,10 @@ struct kiss_fft_state{ do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \ (m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0) +# define C_MUL4(m,a,b) \ + do{ (m).r = PSHR32( smul((a).r,(b).r) - smul((a).i,(b).i),17 ); \ + (m).i = PSHR32( smul((a).r,(b).i) + smul((a).i,(b).r),17 ); }while(0) + # define DIVSCALAR(x,k) \ (x) = sround( smul( x, SAMP_MAX/k ) ) @@ -84,6 +89,9 @@ struct kiss_fft_state{ #define C_MUL(m,a,b) \ do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ (m).i = (a).r*(b).i + (a).i*(b).r; }while(0) + +#define C_MUL4(m,a,b) C_MUL(m,a,b) + # define C_FIXDIV(c,div) /* NOOP */ # define C_MULBYSCALAR( c, s ) \ do{ (c).r *= (s);\ @@ -140,6 +148,11 @@ struct kiss_fft_state{ (x)->r = KISS_FFT_COS(phase);\ (x)->i = KISS_FFT_SIN(phase);\ }while(0) +#define kf_cexp2(x,phase) \ + do{ \ + (x)->r = spx_cos_norm((phase));\ + (x)->i = spx_cos_norm((phase)-32768);\ +}while(0) /* a debugging function */ diff --git a/libspeex/arch.h b/libspeex/arch.h index 0500437..e2d731a 100644 --- a/libspeex/arch.h +++ b/libspeex/arch.h @@ -35,12 +35,16 @@ #ifndef ARCH_H #define ARCH_H +#ifndef OUTSIDE_SPEEX #include "speex/speex_types.h" +#endif #define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */ #define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */ +#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 16-bit value. */ #define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */ #define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */ +#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 32-bit value. */ #define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */ #ifdef FIXED_POINT @@ -68,6 +72,7 @@ typedef spx_word32_t spx_sig_t; #define VERY_SMALL 0 #define VERY_LARGE32 ((spx_word32_t)2147483647) #define VERY_LARGE16 ((spx_word16_t)32767) +#define Q15_ONE ((spx_word16_t)32767) #ifdef FIXED_DEBUG @@ -113,6 +118,7 @@ typedef float spx_word32_t; #define VERY_SMALL 1e-15f #define VERY_LARGE32 1e15f #define VERY_LARGE16 1e15f +#define Q15_ONE ((spx_word16_t)1.f) #define QCONST16(x,bits) (x) #define QCONST32(x,bits) (x) @@ -127,6 +133,7 @@ typedef float spx_word32_t; #define SHL32(a,shift) (a) #define PSHR16(a,shift) (a) #define PSHR32(a,shift) (a) +#define VSHR32(a,shift) (a) #define SATURATE16(x,a) (x) #define SATURATE32(x,a) (x) @@ -147,6 +154,7 @@ typedef float spx_word32_t; #define MULT16_32_Q13(a,b) ((a)*(b)) #define MULT16_32_Q14(a,b) ((a)*(b)) #define MULT16_32_Q15(a,b) ((a)*(b)) +#define MULT16_32_P15(a,b) ((a)*(b)) #define MAC16_32_Q11(c,a,b) ((c)+(a)*(b)) #define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) diff --git a/libspeex/bits.c b/libspeex/bits.c index 376e804..5c4cb0e 100644 --- a/libspeex/bits.c +++ b/libspeex/bits.c @@ -76,6 +76,7 @@ void speex_bits_destroy(SpeexBits *bits) void speex_bits_reset(SpeexBits *bits) { + /* We only need to clear the first byte now */ bits->chars[0]=0; bits->nbBits=0; bits->charPtr=0; @@ -96,7 +97,7 @@ void speex_bits_read_from(SpeexBits *bits, char *chars, int len) int nchars = len / BYTES_PER_CHAR; if (nchars > bits->buf_size) { - speex_warning_int("Packet is larger than allocated buffer: ", len); + speex_notify("Packet is larger than allocated buffer"); if (bits->owner) { char *tmp = (char*)speex_realloc(bits->chars, nchars); @@ -109,7 +110,7 @@ void speex_bits_read_from(SpeexBits *bits, char *chars, int len) speex_warning("Could not resize input buffer: truncating input"); } } else { - speex_warning("Do not own input buffer: truncating input"); + speex_warning("Do not own input buffer: truncating oversize input"); nchars=bits->buf_size; } } @@ -158,10 +159,10 @@ void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes) bits->chars=tmp; } else { nchars=bits->buf_size-(bits->nbBits>>LOG2_BITS_PER_CHAR)-1; - speex_warning("Could not resize input buffer: truncating input"); + speex_warning("Could not resize input buffer: truncating oversize input"); } } else { - speex_warning("Do not own input buffer: truncating input"); + speex_warning("Do not own input buffer: truncating oversize input"); nchars=bits->buf_size; } } @@ -222,14 +223,13 @@ void speex_bits_pack(SpeexBits *bits, int data, int nbBits) if (bits->charPtr+((nbBits+bits->bitPtr)>>LOG2_BITS_PER_CHAR) >= bits->buf_size) { - speex_warning("Buffer too small to pack bits"); + speex_notify("Buffer too small to pack bits"); if (bits->owner) { - int new_nchars = ((bits->buf_size+5)*3)>>1; + int new_nchars = ((bits->buf_size+5)*3)>>1; char *tmp = (char*)speex_realloc(bits->chars, new_nchars); if (tmp) { - speex_memset_bytes(tmp, 0, new_nchars); bits->buf_size=new_nchars; bits->chars=tmp; } else { diff --git a/libspeex/cb_search.c b/libspeex/cb_search.c index 5c68826..cab2b71 100644 --- a/libspeex/cb_search.c +++ b/libspeex/cb_search.c @@ -181,7 +181,7 @@ int update_target t[subvect_size*i+m] = ADD16(t[subvect_size*i+m], res[m]); #ifdef FIXED_POINT - if (sign) + if (sign==1) { for (j=0;j<subvect_size;j++) e[subvect_size*i+j]=SHL32(EXTEND32(shape_cb[rind*subvect_size+j]),SIG_SHIFT-5); @@ -226,11 +226,13 @@ int update_target /* Update target: only update target if necessary */ if (update_target) { - VARDECL(spx_sig_t *r2); - ALLOC(r2, nsf, spx_sig_t); - syn_percep_zero(e, ak, awk1, awk2, r2, nsf,p, stack); + VARDECL(spx_word16_t *r2); + ALLOC(r2, nsf, spx_word16_t); for (j=0;j<nsf;j++) - target[j]=SUB16(target[j],EXTRACT16(PSHR32(r2[j],8))); + r2[j] = EXTRACT16(PSHR32(e[j] ,6)); + syn_percep_zero16(r2, ak, awk1, awk2, r2, nsf,p, stack); + for (j=0;j<nsf;j++) + target[j]=SUB16(target[j],PSHR16(r2[j],2)); } } @@ -263,7 +265,6 @@ int update_target #endif VARDECL(spx_word16_t *t); VARDECL(spx_sig_t *e); - VARDECL(spx_sig_t *r2); VARDECL(spx_word16_t *tmp); VARDECL(spx_word32_t *ndist); VARDECL(spx_word32_t *odist); @@ -316,7 +317,6 @@ int update_target #endif ALLOC(t, nsf, spx_word16_t); ALLOC(e, nsf, spx_sig_t); - ALLOC(r2, nsf, spx_sig_t); ALLOC(ind, nb_subvect, int); ALLOC(tmp, 2*N*nsf, spx_word16_t); @@ -495,9 +495,13 @@ int update_target /* Update target: only update target if necessary */ if (update_target) { - syn_percep_zero(e, ak, awk1, awk2, r2, nsf,p, stack); + VARDECL(spx_word16_t *r2); + ALLOC(r2, nsf, spx_word16_t); + for (j=0;j<nsf;j++) + r2[j] = EXTRACT16(PSHR32(e[j] ,6)); + syn_percep_zero16(r2, ak, awk1, awk2, r2, nsf,p, stack); for (j=0;j<nsf;j++) - target[j]=SUB16(target[j],EXTRACT16(PSHR32(r2[j],8))); + target[j]=SUB16(target[j],PSHR16(r2[j],2)); } } @@ -577,14 +581,12 @@ int update_target ) { int i; - VARDECL(spx_sig_t *tmp); - ALLOC(tmp, nsf, spx_sig_t); - for (i=0;i<nsf;i++) - tmp[i]=PSHR32(EXTEND32(target[i]),SIG_SHIFT); - residue_percep_zero(tmp, ak, awk1, awk2, tmp, nsf, p, stack); + VARDECL(spx_word16_t *tmp); + ALLOC(tmp, nsf, spx_word16_t); + residue_percep_zero16(target, ak, awk1, awk2, tmp, nsf, p, stack); for (i=0;i<nsf;i++) - exc[i]+=tmp[i]; + exc[i]+=SHL32(EXTEND32(tmp[i]),8); for (i=0;i<nsf;i++) target[i]=0; } diff --git a/libspeex/cb_search_bfin.h b/libspeex/cb_search_bfin.h index 52cc4b3..ae9cf83 100644 --- a/libspeex/cb_search_bfin.h +++ b/libspeex/cb_search_bfin.h @@ -73,7 +73,10 @@ void compute_weighted_codebook(const signed char *shape_cb, const spx_word16_t * : : "m" (subvect_size), "m" (shape_cb), "m" (r), "m" (resp), "m" (E) : "A0", "P0", "P1", "P2", "P3", "P4", "R0", "R1", "R2", "I0", "I1", "L0", - "L1", "A0", "A1", "memory", "LC0", "LC1" + "L1", "A0", "A1", "memory" +#if !(__GNUC__ == 3) + , "LC0", "LC1" /* gcc 3.4 doesn't know about LC registers */ +#endif ); shape_cb += subvect_size; resp += subvect_size; diff --git a/libspeex/echo_diagnostic.m b/libspeex/echo_diagnostic.m new file mode 100644 index 0000000..aebf390 --- /dev/null +++ b/libspeex/echo_diagnostic.m @@ -0,0 +1,72 @@ +% Attempts to diagnose AEC problems from recorded samples +% +% out = echo_diagnostic(rec_file, play_file, out_file, tail_length) +% +% Computes the full matrix inversion to cancel echo from the +% recording 'rec_file' using the far end signal 'play_file' using +% a filter length of 'tail_length'. The output is saved to 'out_file'. +function out = echo_diagnostic(rec_file, play_file, out_file, tail_length) + +F=fopen(rec_file,'rb'); +rec=fread(F,Inf,'short'); +fclose (F); +F=fopen(play_file,'rb'); +play=fread(F,Inf,'short'); +fclose (F); + +rec = [rec; zeros(1024,1)]; +play = [play; zeros(1024,1)]; + +N = length(rec); +corr = real(ifft(fft(rec).*conj(fft(play)))); +acorr = real(ifft(fft(play).*conj(fft(play)))); + +[a,b] = max(corr); + +if b > N/2 + b = b-N; +end +printf ("Far end to near end delay is %d samples\n", b); +if (b > .3*tail_length) + printf ('This is too much delay, try delaying the far-end signal a bit\n'); +else if (b < 0) + printf ('You have a negative delay, the echo canceller has no chance to cancel anything!\n'); + else + printf ('Delay looks OK.\n'); + end + end +end +N2 = round(N/2); +corr1 = real(ifft(fft(rec(1:N2)).*conj(fft(play(1:N2))))); +corr2 = real(ifft(fft(rec(N2+1:end)).*conj(fft(play(N2+1:end))))); + +[a,b1] = max(corr1); +if b1 > N2/2 + b1 = b1-N2; +end +[a,b2] = max(corr2); +if b2 > N2/2 + b2 = b2-N2; +end +drift = (b1-b2)/N2; +printf ('Drift estimate is %f%% (%d samples)\n', 100*drift, b1-b2); +if abs(b1-b2) < 10 + printf ('A drift of a few (+-10) samples is normal.\n'); +else + if abs(b1-b2) < 30 + printf ('There may be (not sure) excessive clock drift. Is the capture and playback done on the same soundcard?\n'); + else + printf ('Your clock is drifting! No way the AEC will be able to do anything with that. Most likely, you''re doing capture and playback from two different cards.\n'); + end + end +end +acorr(1) = .001+1.00001*acorr(1); +AtA = toeplitz(acorr(1:tail_length)); +bb = corr(1:tail_length); +h = AtA\bb; + +out = (rec - filter(h, 1, play)); + +F=fopen(out_file,'w'); +fwrite(F,out,'short'); +fclose (F); diff --git a/libspeex/fftwrap.c b/libspeex/fftwrap.c index 43a9b18..35e2d05 100644 --- a/libspeex/fftwrap.c +++ b/libspeex/fftwrap.c @@ -64,7 +64,7 @@ static int maximize_range(spx_word16_t *in, spx_word16_t *out, spx_word16_t boun } for (i=0;i<len;i++) { - out[i] = in[i] << shift; + out[i] = SHL16(in[i], shift); } return shift; } @@ -74,7 +74,7 @@ static void renorm_range(spx_word16_t *in, spx_word16_t *out, int shift, int len int i; for (i=0;i<len;i++) { - out[i] = (in[i] + (1<<(shift-1))) >> shift; + out[i] = PSHR16(in[i], shift); } } #endif @@ -103,8 +103,8 @@ void spx_fft(void *table, float *in, float *out) if (in==out) { int i; - speex_warning("FFT should not be done in-place"); float scale = 1./((struct drft_lookup *)table)->n; + speex_warning("FFT should not be done in-place"); for (i=0;i<((struct drft_lookup *)table)->n;i++) out[i] = scale*in[i]; } else { @@ -120,7 +120,6 @@ void spx_ifft(void *table, float *in, float *out) { if (in==out) { - int i; speex_warning("FFT should not be done in-place"); } else { int i; @@ -138,7 +137,6 @@ void spx_ifft(void *table, float *in, float *out) struct kiss_config { kiss_fftr_cfg forward; kiss_fftr_cfg backward; - kiss_fft_cpx *freq_data; int N; }; @@ -146,7 +144,6 @@ void *spx_fft_init(int size) { struct kiss_config *table; table = (struct kiss_config*)speex_alloc(sizeof(struct kiss_config)); - table->freq_data = (kiss_fft_cpx*)speex_alloc(sizeof(kiss_fft_cpx)*((size>>1)+1)); table->forward = kiss_fftr_alloc(size,0,NULL,NULL); table->backward = kiss_fftr_alloc(size,1,NULL,NULL); table->N = size; @@ -158,7 +155,6 @@ void spx_fft_destroy(void *table) struct kiss_config *t = (struct kiss_config *)table; kiss_fftr_free(t->forward); kiss_fftr_free(t->backward); - speex_free(t->freq_data); speex_free(table); } @@ -166,18 +162,10 @@ void spx_fft_destroy(void *table) void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) { - int i; int shift; struct kiss_config *t = (struct kiss_config *)table; shift = maximize_range(in, in, 32000, t->N); - kiss_fftr(t->forward, in, t->freq_data); - out[0] = t->freq_data[0].r; - for (i=1;i<t->N>>1;i++) - { - out[(i<<1)-1] = t->freq_data[i].r; - out[(i<<1)] = t->freq_data[i].i; - } - out[(i<<1)-1] = t->freq_data[i].r; + kiss_fftr2(t->forward, in, out); renorm_range(in, in, shift, t->N); renorm_range(out, out, shift, t->N); } @@ -190,32 +178,16 @@ void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) float scale; struct kiss_config *t = (struct kiss_config *)table; scale = 1./t->N; - kiss_fftr(t->forward, in, t->freq_data); - out[0] = scale*t->freq_data[0].r; - for (i=1;i<t->N>>1;i++) - { - out[(i<<1)-1] = scale*t->freq_data[i].r; - out[(i<<1)] = scale*t->freq_data[i].i; - } - out[(i<<1)-1] = scale*t->freq_data[i].r; + kiss_fftr2(t->forward, in, out); + for (i=0;i<t->N;i++) + out[i] *= scale; } #endif void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out) { - int i; struct kiss_config *t = (struct kiss_config *)table; - t->freq_data[0].r = in[0]; - t->freq_data[0].i = 0; - for (i=1;i<t->N>>1;i++) - { - t->freq_data[i].r = in[(i<<1)-1]; - t->freq_data[i].i = in[(i<<1)]; - } - t->freq_data[i].r = in[(i<<1)-1]; - t->freq_data[i].i = 0; - - kiss_fftri(t->backward, t->freq_data, out); + kiss_fftri2(t->backward, in, out); } diff --git a/libspeex/filterbank.c b/libspeex/filterbank.c new file mode 100644 index 0000000..187d5ee --- /dev/null +++ b/libspeex/filterbank.c @@ -0,0 +1,226 @@ +/* Copyright (C) 2006 Jean-Marc Valin */ +/** + @file filterbank.c + @brief Converting between psd and filterbank + */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "filterbank.h" +#include "misc.h" +#include <math.h> +#include "math_approx.h" + +#ifdef FIXED_POINT + +#define toBARK(n) (MULT16_16(26829,spx_atan(SHR32(MULT16_16(97,n),2))) + MULT16_16(4588,spx_atan(MULT16_32_Q15(20,MULT16_16(n,n)))) + MULT16_16(3355,n)) + +#else +#define toBARK(n) (13.1f*atan(.00074f*(n))+2.24f*atan((n)*(n)*1.85e-8f)+1e-4f*(n)) +#endif + +#define toMEL(n) (2595.f*log10(1.f+(n)/700.f)) + +FilterBank *filterbank_new(int banks, spx_word32_t sampling, int len, int type) +{ + FilterBank *bank; + spx_word32_t df; + spx_word32_t max_mel, mel_interval; + int i; + int id1; + int id2; + df = DIV32(SHL32(sampling,15),MULT16_16(2,len)); + max_mel = toBARK(EXTRACT16(MULT16_16_Q15(QCONST16(.5f,15),sampling))); + mel_interval = PDIV32(max_mel,banks-1); + + bank = (FilterBank*)speex_alloc(sizeof(FilterBank)); + bank->nb_banks = banks; + bank->len = len; + bank->bank_left = (int*)speex_alloc(len*sizeof(int)); + bank->bank_right = (int*)speex_alloc(len*sizeof(int)); + bank->filter_left = (spx_word16_t*)speex_alloc(len*sizeof(spx_word16_t)); + bank->filter_right = (spx_word16_t*)speex_alloc(len*sizeof(spx_word16_t)); + /* Think I can safely disable normalisation that for fixed-point (and probably float as well) */ +#ifndef FIXED_POINT + bank->scaling = (float*)speex_alloc(banks*sizeof(float)); +#endif + for (i=0;i<len;i++) + { + spx_word16_t curr_freq; + spx_word32_t mel; + spx_word16_t val; + curr_freq = EXTRACT16(MULT16_32_P15(i,df)); + mel = toBARK(curr_freq); + if (mel > max_mel) + break; +#ifdef FIXED_POINT + id1 = DIV32(mel,mel_interval); +#else + id1 = (int)(floor(mel/mel_interval)); +#endif + if (id1>banks-2) + { + id1 = banks-2; + val = Q15_ONE; + } else { + val = DIV32_16(mel - id1*mel_interval,EXTRACT16(PSHR32(mel_interval,15))); + } + id2 = id1+1; + bank->bank_left[i] = id1; + bank->filter_left[i] = SUB16(Q15_ONE,val); + bank->bank_right[i] = id2; + bank->filter_right[i] = val; + } + + /* Think I can safely disable normalisation for fixed-point (and probably float as well) */ +#ifndef FIXED_POINT + for (i=0;i<bank->nb_banks;i++) + bank->scaling[i] = 0; + for (i=0;i<bank->len;i++) + { + int id = bank->bank_left[i]; + bank->scaling[id] += bank->filter_left[i]; + id = bank->bank_right[i]; + bank->scaling[id] += bank->filter_right[i]; + } + for (i=0;i<bank->nb_banks;i++) + bank->scaling[i] = Q15_ONE/(bank->scaling[i]); +#endif + return bank; +} + +void filterbank_destroy(FilterBank *bank) +{ + speex_free(bank->bank_left); + speex_free(bank->bank_right); + speex_free(bank->filter_left); + speex_free(bank->filter_right); +#ifndef FIXED_POINT + speex_free(bank->scaling); +#endif + speex_free(bank); +} + +void filterbank_compute_bank32(FilterBank *bank, spx_word32_t *ps, spx_word32_t *mel) +{ + int i; + for (i=0;i<bank->nb_banks;i++) + mel[i] = 0; + + for (i=0;i<bank->len;i++) + { + int id; + id = bank->bank_left[i]; + mel[id] += MULT16_32_P15(bank->filter_left[i],ps[i]); + id = bank->bank_right[i]; + mel[id] += MULT16_32_P15(bank->filter_right[i],ps[i]); + } + /* Think I can safely disable normalisation that for fixed-point (and probably float as well) */ +#ifndef FIXED_POINT + /*for (i=0;i<bank->nb_banks;i++) + mel[i] = MULT16_32_P15(Q15(bank->scaling[i]),mel[i]); + */ +#endif +} + +void filterbank_compute_psd16(FilterBank *bank, spx_word16_t *mel, spx_word16_t *ps) +{ + int i; + for (i=0;i<bank->len;i++) + { + spx_word32_t tmp; + int id1, id2; + id1 = bank->bank_left[i]; + id2 = bank->bank_right[i]; + tmp = MULT16_16(mel[id1],bank->filter_left[i]); + tmp += MULT16_16(mel[id2],bank->filter_right[i]); + ps[i] = EXTRACT16(PSHR32(tmp,15)); + } +} + + +#ifndef FIXED_POINT +void filterbank_compute_bank(FilterBank *bank, float *ps, float *mel) +{ + int i; + for (i=0;i<bank->nb_banks;i++) + mel[i] = 0; + + for (i=0;i<bank->len;i++) + { + int id = bank->bank_left[i]; + mel[id] += bank->filter_left[i]*ps[i]; + id = bank->bank_right[i]; + mel[id] += bank->filter_right[i]*ps[i]; + } + for (i=0;i<bank->nb_banks;i++) + mel[i] *= bank->scaling[i]; +} + +void filterbank_compute_psd(FilterBank *bank, float *mel, float *ps) +{ + int i; + for (i=0;i<bank->len;i++) + { + int id = bank->bank_left[i]; + ps[i] = mel[id]*bank->filter_left[i]; + id = bank->bank_right[i]; + ps[i] += mel[id]*bank->filter_right[i]; + } +} + +void filterbank_psy_smooth(FilterBank *bank, float *ps, float *mask) +{ + /* Low freq slope: 14 dB/Bark*/ + /* High freq slope: 9 dB/Bark*/ + /* Noise vs tone: 5 dB difference */ + /* FIXME: Temporary kludge */ + float bark[100]; + int i; + /* Assumes 1/3 Bark resolution */ + float decay_low = 0.34145f; + float decay_high = 0.50119f; + filterbank_compute_bank(bank, ps, bark); + for (i=1;i<bank->nb_banks;i++) + { + /*float decay_high = 13-1.6*log10(bark[i-1]); + decay_high = pow(10,(-decay_high/30.f));*/ + bark[i] = bark[i] + decay_high*bark[i-1]; + } + for (i=bank->nb_banks-2;i>=0;i--) + { + bark[i] = bark[i] + decay_low*bark[i+1]; + } + filterbank_compute_psd(bank, bark, mask); +} + +#endif diff --git a/libspeex/filterbank.h b/libspeex/filterbank.h new file mode 100644 index 0000000..5ded6b9 --- /dev/null +++ b/libspeex/filterbank.h @@ -0,0 +1,66 @@ +/* Copyright (C) 2006 Jean-Marc Valin */ +/** + @file filterbank.h + @brief Converting between psd and filterbank + */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 FILTERBANK_H +#define FILTERBANK_H + +#include "misc.h" + +typedef struct { + int *bank_left; + int *bank_right; + spx_word16_t *filter_left; + spx_word16_t *filter_right; +#ifndef FIXED_POINT + float *scaling; +#endif + int nb_banks; + int len; +} FilterBank; + + +FilterBank *filterbank_new(int banks, spx_word32_t sampling, int len, int type); + +void filterbank_destroy(FilterBank *bank); + +void filterbank_compute_bank32(FilterBank *bank, spx_word32_t *ps, spx_word32_t *mel); + +void filterbank_compute_psd16(FilterBank *bank, spx_word16_t *mel, spx_word16_t *psd); + +#ifndef FIXED_POINT +void filterbank_compute_bank(FilterBank *bank, float *psd, float *mel); +void filterbank_compute_psd(FilterBank *bank, float *mel, float *psd); +#endif + + +#endif diff --git a/libspeex/filters.c b/libspeex/filters.c index a1111ee..48b4753 100644 --- a/libspeex/filters.c +++ b/libspeex/filters.c @@ -62,6 +62,24 @@ void bw_lpc(spx_word16_t gamma, const spx_coef_t *lpc_in, spx_coef_t *lpc_out, i } } +void sanitize_values32(spx_word32_t *vec, spx_word32_t min_val, spx_word32_t max_val, int len) +{ + int i; + for (i=0;i<len;i++) + { + /* It's important we do the test that way so we can catch NaNs, which are neither greater nor smaller */ + if (!(vec[i]>=min_val && vec[i] <= max_val)) + { + if (vec[i] < min_val) + vec[i] = min_val; + else if (vec[i] > max_val) + vec[i] = max_val; + else /* Has to be NaN */ + vec[i] = 0; + } + } +} + void highpass(const spx_word16_t *x, spx_word16_t *y, int len, int filtID, spx_mem_t *mem) { int i; @@ -83,8 +101,8 @@ void highpass(const spx_word16_t *x, spx_word16_t *y, int len, int filtID, spx_m spx_word16_t yi; spx_word32_t vout = ADD32(MULT16_16(num[0], x[i]),mem[0]); yi = EXTRACT16(SATURATE(PSHR32(vout,14),32767)); - mem[0] = ADD32(MAC16_16(mem[1], num[1],x[i]), MULT16_32_Q14(-den[1],vout)); - mem[1] = ADD32(MULT16_16(num[2],x[i]), MULT16_32_Q14(-den[2],vout)); + mem[0] = ADD32(MAC16_16(mem[1], num[1],x[i]), SHL32(MULT16_32_Q15(-den[1],vout),1)); + mem[1] = ADD32(MULT16_16(num[2],x[i]), SHL32(MULT16_32_Q15(-den[2],vout),1)); y[i] = yi; } } @@ -218,10 +236,10 @@ spx_word16_t compute_rms16(const spx_word16_t *x, int len) for (i=0;i<len;i+=4) { spx_word32_t sum2=0; - sum2 = MAC16_16(sum2,PSHR16(x[i],1),PSHR16(x[i],1)); - sum2 = MAC16_16(sum2,PSHR16(x[i+1],1),PSHR16(x[i+1],1)); - sum2 = MAC16_16(sum2,PSHR16(x[i+2],1),PSHR16(x[i+2],1)); - sum2 = MAC16_16(sum2,PSHR16(x[i+3],1),PSHR16(x[i+3],1)); + sum2 = MAC16_16(sum2,SHR16(x[i],1),SHR16(x[i],1)); + sum2 = MAC16_16(sum2,SHR16(x[i+1],1),SHR16(x[i+1],1)); + sum2 = MAC16_16(sum2,SHR16(x[i+2],1),SHR16(x[i+2],1)); + sum2 = MAC16_16(sum2,SHR16(x[i+3],1),SHR16(x[i+3],1)); sum = ADD32(sum,SHR32(sum2,6)); } return SHL16(spx_sqrt(DIV32(sum,len)),4); @@ -297,53 +315,6 @@ spx_word16_t compute_rms16(const spx_word16_t *x, int len) -#ifndef OVERRIDE_FILTER_MEM2 -#ifdef PRECISION16 -void filter_mem2(const spx_sig_t *x, const spx_coef_t *num, const spx_coef_t *den, spx_sig_t *y, int N, int ord, spx_mem_t *mem) -{ - int i,j; - spx_word16_t xi,yi,nyi; - - for (i=0;i<N;i++) - { - xi= EXTRACT16(PSHR32(SATURATE(x[i],536870911),SIG_SHIFT)); - yi = EXTRACT16(PSHR32(SATURATE(ADD32(x[i], SHL32(mem[0],1)),536870911),SIG_SHIFT)); - nyi = NEG16(yi); - for (j=0;j<ord-1;j++) - { - mem[j] = MAC16_16(MAC16_16(mem[j+1], num[j],xi), den[j],nyi); - } - mem[ord-1] = ADD32(MULT16_16(num[ord-1],xi), MULT16_16(den[ord-1],nyi)); - y[i] = SHL32(EXTEND32(yi),SIG_SHIFT); - } -} -#else -void filter_mem2(const spx_sig_t *x, const spx_coef_t *num, const spx_coef_t *den, spx_sig_t *y, int N, int ord, spx_mem_t *mem) -{ - int i,j; - spx_sig_t xi,yi,nyi; - - for (i=0;i<ord;i++) - mem[i] = SHR32(mem[i],1); - for (i=0;i<N;i++) - { - xi=SATURATE(x[i],805306368); - yi = SATURATE(ADD32(xi, SHL32(mem[0],2)),805306368); - nyi = NEG32(yi); - for (j=0;j<ord-1;j++) - { - mem[j] = MAC16_32_Q15(MAC16_32_Q15(mem[j+1], num[j],xi), den[j],nyi); - } - mem[ord-1] = SUB32(MULT16_32_Q15(num[ord-1],xi), MULT16_32_Q15(den[ord-1],yi)); - y[i] = yi; - } - for (i=0;i<ord;i++) - mem[i] = SHL32(mem[i],1); -} -#endif -#endif - -#ifdef FIXED_POINT #ifndef OVERRIDE_FILTER_MEM16 void filter_mem16(const spx_word16_t *x, const spx_coef_t *num, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack) { @@ -363,60 +334,7 @@ void filter_mem16(const spx_word16_t *x, const spx_coef_t *num, const spx_coef_t } } #endif -#else -void filter_mem16(const spx_word16_t *x, const spx_coef_t *num, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack) -{ - filter_mem2(x, num, den, y, N, ord, mem); -} -#endif - - -#ifndef OVERRIDE_IIR_MEM2 -#ifdef PRECISION16 -void iir_mem2(const spx_sig_t *x, const spx_coef_t *den, spx_sig_t *y, int N, int ord, spx_mem_t *mem) -{ - int i,j; - spx_word16_t yi,nyi; - - for (i=0;i<N;i++) - { - yi = EXTRACT16(PSHR32(SATURATE(x[i] + SHL32(mem[0],1),536870911),SIG_SHIFT)); - nyi = NEG16(yi); - for (j=0;j<ord-1;j++) - { - mem[j] = MAC16_16(mem[j+1],den[j],nyi); - } - mem[ord-1] = MULT16_16(den[ord-1],nyi); - y[i] = SHL32(EXTEND32(yi),SIG_SHIFT); - } -} -#else -void iir_mem2(const spx_sig_t *x, const spx_coef_t *den, spx_sig_t *y, int N, int ord, spx_mem_t *mem) -{ - int i,j; - spx_word32_t xi,yi,nyi; - - for (i=0;i<ord;i++) - mem[i] = SHR32(mem[i],1); - for (i=0;i<N;i++) - { - xi=SATURATE(x[i],805306368); - yi = SATURATE(xi + SHL32(mem[0],2),805306368); - nyi = NEG32(yi); - for (j=0;j<ord-1;j++) - { - mem[j] = MAC16_32_Q15(mem[j+1],den[j],nyi); - } - mem[ord-1] = MULT16_32_Q15(den[ord-1],nyi); - y[i] = yi; - } - for (i=0;i<ord;i++) - mem[i] = SHL32(mem[i],1); -} -#endif -#endif -#ifdef FIXED_POINT #ifndef OVERRIDE_IIR_MEM16 void iir_mem16(const spx_word16_t *x, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack) { @@ -436,59 +354,7 @@ void iir_mem16(const spx_word16_t *x, const spx_coef_t *den, spx_word16_t *y, in } } #endif -#else -void iir_mem16(const spx_word16_t *x, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack) -{ - iir_mem2(x, den, y, N, ord, mem); -} -#endif - - -#ifndef OVERRIDE_FIR_MEM2 -#ifdef PRECISION16 -void fir_mem2(const spx_sig_t *x, const spx_coef_t *num, spx_sig_t *y, int N, int ord, spx_mem_t *mem) -{ - int i,j; - spx_word16_t xi,yi; - - for (i=0;i<N;i++) - { - xi= EXTRACT16(PSHR32(SATURATE(x[i],536870911),SIG_SHIFT)); - yi = EXTRACT16(PSHR32(SATURATE(x[i] + SHL32(mem[0],1),536870911),SIG_SHIFT)); - for (j=0;j<ord-1;j++) - { - mem[j] = MAC16_16(mem[j+1], num[j],xi); - } - mem[ord-1] = MULT16_16(num[ord-1],xi); - y[i] = SHL32(EXTEND32(yi),SIG_SHIFT); - } -} -#else -void fir_mem2(const spx_sig_t *x, const spx_coef_t *num, spx_sig_t *y, int N, int ord, spx_mem_t *mem) -{ - int i,j; - spx_word32_t xi,yi; - - for (i=0;i<ord;i++) - mem[i] = SHR32(mem[i],1); - for (i=0;i<N;i++) - { - xi=SATURATE(x[i],805306368); - yi = xi + SHL32(mem[0],2); - for (j=0;j<ord-1;j++) - { - mem[j] = MAC16_32_Q15(mem[j+1], num[j],xi); - } - mem[ord-1] = MULT16_32_Q15(num[ord-1],xi); - y[i] = SATURATE(yi,805306368); - } - for (i=0;i<ord;i++) - mem[i] = SHL32(mem[i],1); -} -#endif -#endif -#ifdef FIXED_POINT #ifndef OVERRIDE_FIR_MEM16 void fir_mem16(const spx_word16_t *x, const spx_coef_t *num, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack) { @@ -508,44 +374,34 @@ void fir_mem16(const spx_word16_t *x, const spx_coef_t *num, spx_word16_t *y, in } } #endif -#else -void fir_mem16(const spx_word16_t *x, const spx_coef_t *num, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack) -{ - fir_mem2(x, num, y, N, ord, mem); -} -#endif - - - - -void syn_percep_zero(const spx_sig_t *xx, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_sig_t *y, int N, int ord, char *stack) +void syn_percep_zero16(const spx_word16_t *xx, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack) { int i; VARDECL(spx_mem_t *mem); ALLOC(mem, ord, spx_mem_t); for (i=0;i<ord;i++) - mem[i]=0; - iir_mem2(xx, ak, y, N, ord, mem); + mem[i]=0; + iir_mem16(xx, ak, y, N, ord, mem, stack); for (i=0;i<ord;i++) mem[i]=0; - filter_mem2(y, awk1, awk2, y, N, ord, mem); + filter_mem16(y, awk1, awk2, y, N, ord, mem, stack); } - -void residue_percep_zero(const spx_sig_t *xx, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_sig_t *y, int N, int ord, char *stack) +void residue_percep_zero16(const spx_word16_t *xx, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack) { int i; VARDECL(spx_mem_t *mem); ALLOC(mem, ord, spx_mem_t); for (i=0;i<ord;i++) mem[i]=0; - filter_mem2(xx, ak, awk1, y, N, ord, mem); + filter_mem16(xx, ak, awk1, y, N, ord, mem, stack); for (i=0;i<ord;i++) - mem[i]=0; - fir_mem2(y, awk2, y, N, ord, mem); + mem[i]=0; + fir_mem16(y, awk2, y, N, ord, mem, stack); } + #ifndef OVERRIDE_COMPUTE_IMPULSE_RESPONSE void compute_impulse_response(const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack) { @@ -581,7 +437,8 @@ void compute_impulse_response(const spx_coef_t *ak, const spx_coef_t *awk1, cons } #endif -void qmf_decomp(const spx_word16_t *xx, const spx_word16_t *aa, spx_sig_t *y1, spx_sig_t *y2, int N, int M, spx_word16_t *mem, char *stack) +/* Decomposes a signal into low-band and high-band using a QMF */ +void qmf_decomp(const spx_word16_t *xx, const spx_word16_t *aa, spx_word16_t *y1, spx_word16_t *y2, int N, int M, spx_word16_t *mem, char *stack) { int i,j,k,M2; VARDECL(spx_word16_t *a); @@ -594,105 +451,139 @@ void qmf_decomp(const spx_word16_t *xx, const spx_word16_t *aa, spx_sig_t *y1, s M2=M>>1; for (i=0;i<M;i++) a[M-i-1]= aa[i]; - for (i=0;i<M-1;i++) x[i]=mem[M-i-2]; for (i=0;i<N;i++) - x[i+M-1]=SATURATE(PSHR(xx[i],1),16383); + x[i+M-1]=SHR16(xx[i],1); + for (i=0;i<M-1;i++) + mem[i]=SHR16(xx[N-i-1],1); for (i=0,k=0;i<N;i+=2,k++) { - y1[k]=0; - y2[k]=0; + spx_word32_t y1k=0, y2k=0; for (j=0;j<M2;j++) { - y1[k]=ADD32(y1[k],MULT16_16(a[j],ADD16(x[i+j],x2[i-j]))); - y2[k]=SUB32(y2[k],MULT16_16(a[j],SUB16(x[i+j],x2[i-j]))); + y1k=ADD32(y1k,MULT16_16(a[j],ADD16(x[i+j],x2[i-j]))); + y2k=SUB32(y2k,MULT16_16(a[j],SUB16(x[i+j],x2[i-j]))); j++; - y1[k]=ADD32(y1[k],MULT16_16(a[j],ADD16(x[i+j],x2[i-j]))); - y2[k]=ADD32(y2[k],MULT16_16(a[j],SUB16(x[i+j],x2[i-j]))); + y1k=ADD32(y1k,MULT16_16(a[j],ADD16(x[i+j],x2[i-j]))); + y2k=ADD32(y2k,MULT16_16(a[j],SUB16(x[i+j],x2[i-j]))); } - y1[k] = SHR32(y1[k],1); - y2[k] = SHR32(y2[k],1); + y1[k] = EXTRACT16(SATURATE(PSHR32(y1k,15),32767)); + y2[k] = EXTRACT16(SATURATE(PSHR32(y2k,15),32767)); } - for (i=0;i<M-1;i++) - mem[i]=SATURATE(PSHR(xx[N-i-1],1),16383); } - -/* By segher */ -void fir_mem_up(const spx_sig_t *x, const spx_word16_t *a, spx_sig_t *y, int N, int M, spx_word32_t *mem, char *stack) +/* Re-synthesised a signal from the QMF low-band and high-band signals */ +void qmf_synth(const spx_word16_t *x1, const spx_word16_t *x2, const spx_word16_t *a, spx_word16_t *y, int N, int M, spx_word32_t *mem1, spx_word32_t *mem2, char *stack) /* assumptions: all odd x[i] are zero -- well, actually they are left out of the array now N and M are multiples of 4 */ { int i, j; - VARDECL(spx_word16_t *xx); + int M2, N2; + VARDECL(spx_word16_t *xx1); + VARDECL(spx_word16_t *xx2); - ALLOC(xx, M+N-1, spx_word16_t); - - for (i = 0; i < N/2; i++) - xx[2*i] = PSHR32(x[N/2-1-i],SIG_SHIFT); - for (i = 0; i < M - 1; i += 2) - xx[N+i] = mem[i+1]; - - for (i = 0; i < N; i += 4) { + M2 = M>>1; + N2 = N>>1; + ALLOC(xx1, M2+N2, spx_word16_t); + ALLOC(xx2, M2+N2, spx_word16_t); + + for (i = 0; i < N2; i++) + xx1[i] = x1[N2-1-i]; + for (i = 0; i < M2; i++) + xx1[N2+i] = mem1[2*i+1]; + for (i = 0; i < N2; i++) + xx2[i] = x2[N2-1-i]; + for (i = 0; i < M2; i++) + xx2[N2+i] = mem2[2*i+1]; + + for (i = 0; i < N2; i += 2) { spx_sig_t y0, y1, y2, y3; - spx_word16_t x0; + spx_word16_t x10, x20; y0 = y1 = y2 = y3 = 0; - x0 = xx[N-4-i]; + x10 = xx1[N2-2-i]; + x20 = xx2[N2-2-i]; - for (j = 0; j < M; j += 4) { - spx_word16_t x1; + for (j = 0; j < M2; j += 2) { + spx_word16_t x11, x21; spx_word16_t a0, a1; - a0 = a[j]; - a1 = a[j+1]; - x1 = xx[N-2+j-i]; - - y0 = ADD32(y0,SHR(MULT16_16(a0, x1),2)); - y1 = ADD32(y1,SHR(MULT16_16(a1, x1),2)); - y2 = ADD32(y2,SHR(MULT16_16(a0, x0),2)); - y3 = ADD32(y3,SHR(MULT16_16(a1, x0),2)); + a0 = a[2*j]; + a1 = a[2*j+1]; + x11 = xx1[N2-1+j-i]; + x21 = xx2[N2-1+j-i]; - a0 = a[j+2]; - a1 = a[j+3]; - x0 = xx[N+j-i]; +#ifdef FIXED_POINT + /* We multiply twice by the same coef to avoid overflows */ + y0 = MAC16_16(MAC16_16(y0, a0, x11), NEG16(a0), x21); + y1 = MAC16_16(MAC16_16(y1, a1, x11), a1, x21); + y2 = MAC16_16(MAC16_16(y2, a0, x10), NEG16(a0), x20); + y3 = MAC16_16(MAC16_16(y3, a1, x10), a1, x20); +#else + y0 = ADD32(y0,MULT16_16(a0, x11-x21)); + y1 = ADD32(y1,MULT16_16(a1, x11+x21)); + y2 = ADD32(y2,MULT16_16(a0, x10-x20)); + y3 = ADD32(y3,MULT16_16(a1, x10+x20)); +#endif + a0 = a[2*j+2]; + a1 = a[2*j+3]; + x10 = xx1[N2+j-i]; + x20 = xx2[N2+j-i]; - y0 = ADD32(y0,SHR(MULT16_16(a0, x0),2)); - y1 = ADD32(y1,SHR(MULT16_16(a1, x0),2)); - y2 = ADD32(y2,SHR(MULT16_16(a0, x1),2)); - y3 = ADD32(y3,SHR(MULT16_16(a1, x1),2)); +#ifdef FIXED_POINT + /* We multiply twice by the same coef to avoid overflows */ + y0 = MAC16_16(MAC16_16(y0, a0, x10), NEG16(a0), x20); + y1 = MAC16_16(MAC16_16(y1, a1, x10), a1, x20); + y2 = MAC16_16(MAC16_16(y2, a0, x11), NEG16(a0), x21); + y3 = MAC16_16(MAC16_16(y3, a1, x11), a1, x21); +#else + y0 = ADD32(y0,MULT16_16(a0, x10-x20)); + y1 = ADD32(y1,MULT16_16(a1, x10+x20)); + y2 = ADD32(y2,MULT16_16(a0, x11-x21)); + y3 = ADD32(y3,MULT16_16(a1, x11+x21)); +#endif } - y[i] = y0; - y[i+1] = y1; - y[i+2] = y2; - y[i+3] = y3; +#ifdef FIXED_POINT + y[2*i] = EXTRACT16(SATURATE32(PSHR32(y0,15),32767)); + y[2*i+1] = EXTRACT16(SATURATE32(PSHR32(y1,15),32767)); + y[2*i+2] = EXTRACT16(SATURATE32(PSHR32(y2,15),32767)); + y[2*i+3] = EXTRACT16(SATURATE32(PSHR32(y3,15),32767)); +#else + /* Normalize up explicitly if we're in float */ + y[2*i] = 2.f*y0; + y[2*i+1] = 2.f*y1; + y[2*i+2] = 2.f*y2; + y[2*i+3] = 2.f*y3; +#endif } - for (i = 0; i < M - 1; i += 2) - mem[i+1] = xx[i]; + for (i = 0; i < M2; i++) + mem1[2*i+1] = xx1[i]; + for (i = 0; i < M2; i++) + mem2[2*i+1] = xx2[i]; } #ifdef FIXED_POINT #if 0 -spx_word16_t shift_filt[3][7] = {{-33, 1043, -4551, 19959, 19959, -4551, 1043}, +const spx_word16_t shift_filt[3][7] = {{-33, 1043, -4551, 19959, 19959, -4551, 1043}, {-98, 1133, -4425, 29179, 8895, -2328, 444}, {444, -2328, 8895, 29179, -4425, 1133, -98}}; #else -spx_word16_t shift_filt[3][7] = {{-390, 1540, -4993, 20123, 20123, -4993, 1540}, +const spx_word16_t shift_filt[3][7] = {{-390, 1540, -4993, 20123, 20123, -4993, 1540}, {-1064, 2817, -6694, 31589, 6837, -990, -209}, {-209, -990, 6837, 31589, -6694, 2817, -1064}}; #endif #else #if 0 -float shift_filt[3][7] = {{-9.9369e-04, 3.1831e-02, -1.3889e-01, 6.0910e-01, 6.0910e-01, -1.3889e-01, 3.1831e-02}, +const float shift_filt[3][7] = {{-9.9369e-04, 3.1831e-02, -1.3889e-01, 6.0910e-01, 6.0910e-01, -1.3889e-01, 3.1831e-02}, {-0.0029937, 0.0345613, -0.1350474, 0.8904793, 0.2714479, -0.0710304, 0.0135403}, {0.0135403, -0.0710304, 0.2714479, 0.8904793, -0.1350474, 0.0345613, -0.0029937}}; #else -float shift_filt[3][7] = {{-0.011915, 0.046995, -0.152373, 0.614108, 0.614108, -0.152373, 0.046995}, - {-0.0324855, 0.0859768, -0.2042986, 0.9640297, 0.2086420, -0.0302054, -0.0063646}, - {-0.0063646, -0.0302054, 0.2086420, 0.9640297, -0.2042986, 0.0859768, -0.0324855}}; +const float shift_filt[3][7] = {{-0.011915f, 0.046995f, -0.152373f, 0.614108f, 0.614108f, -0.152373f, 0.046995f}, + {-0.0324855f, 0.0859768f, -0.2042986f, 0.9640297f, 0.2086420f, -0.0302054f, -0.0063646f}, + {-0.0063646f, -0.0302054f, 0.2086420f, 0.9640297f, -0.2042986f, 0.0859768f, -0.0324855f}}; #endif #endif @@ -784,7 +675,9 @@ char *stack spx_word16_t g1, g2; spx_word16_t ngain; spx_word16_t gg1, gg2; - +#ifdef FIXED_POINT + int scaledown=0; +#endif #if 0 /* Set to 1 to enable full pitch search */ int nol_pitch[6]; spx_word16_t nol_pitch_coef[6]; @@ -819,6 +712,23 @@ char *stack else interp_pitch(exc, iexc+nsf, -corr_pitch, 80); +#ifdef FIXED_POINT + for (i=0;i<nsf;i++) + { + if (ABS16(exc[i])>16383) + { + scaledown = 1; + break; + } + } + if (scaledown) + { + for (i=0;i<nsf;i++) + exc[i] = SHR16(exc[i],1); + for (i=0;i<2*nsf;i++) + iexc[i] = SHR16(iexc[i],1); + } +#endif /*interp_pitch(exc, iexc+2*nsf, 2*corr_pitch, 80);*/ /*printf ("%d %d %f\n", pitch, corr_pitch, max_corr*ener_1);*/ @@ -898,5 +808,14 @@ char *stack for (i=0;i<nsf;i++) new_exc[i] = MULT16_16_Q14(ngain, new_exc[i]); +#ifdef FIXED_POINT + if (scaledown) + { + for (i=0;i<nsf;i++) + exc[i] = SHL16(exc[i],1); + for (i=0;i<nsf;i++) + new_exc[i] = SHL16(SATURATE16(new_exc[i],16383),1); + } +#endif } diff --git a/libspeex/filters.h b/libspeex/filters.h index b29aa21..b363a9a 100644 --- a/libspeex/filters.h +++ b/libspeex/filters.h @@ -58,13 +58,8 @@ int normalize16(const spx_sig_t *x, spx_word16_t *y, spx_sig_t max_scale, int le void highpass(const spx_word16_t *x, spx_word16_t *y, int len, int filtID, spx_mem_t *mem); -void qmf_decomp(const spx_word16_t *xx, const spx_word16_t *aa, spx_sig_t *, spx_sig_t *y2, int N, int M, spx_word16_t *mem, char *stack); -void fir_mem_up(const spx_sig_t *x, const spx_word16_t *a, spx_sig_t *y, int N, int M, spx_word32_t *mem, char *stack); - - -void filter_mem2(const spx_sig_t *x, const spx_coef_t *num, const spx_coef_t *den, spx_sig_t *y, int N, int ord, spx_mem_t *mem); -void fir_mem2(const spx_sig_t *x, const spx_coef_t *num, spx_sig_t *y, int N, int ord, spx_mem_t *mem); -void iir_mem2(const spx_sig_t *x, const spx_coef_t *den, spx_sig_t *y, int N, int ord, spx_mem_t *mem); +void qmf_decomp(const spx_word16_t *xx, const spx_word16_t *aa, spx_word16_t *, spx_word16_t *y2, int N, int M, spx_word16_t *mem, char *stack); +void qmf_synth(const spx_word16_t *x1, const spx_word16_t *x2, const spx_word16_t *a, spx_word16_t *y, int N, int M, spx_word32_t *mem1, spx_word32_t *mem2, char *stack); void filter_mem16(const spx_word16_t *x, const spx_coef_t *num, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack); void iir_mem16(const spx_word16_t *x, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack); @@ -72,12 +67,11 @@ void fir_mem16(const spx_word16_t *x, const spx_coef_t *num, spx_word16_t *y, in /* Apply bandwidth expansion on LPC coef */ void bw_lpc(spx_word16_t , const spx_coef_t *lpc_in, spx_coef_t *lpc_out, int order); +void sanitize_values32(spx_word32_t *vec, spx_word32_t min_val, spx_word32_t max_val, int len); - -void syn_percep_zero(const spx_sig_t *x, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_sig_t *y, int N, int ord, char *stack); - -void residue_percep_zero(const spx_sig_t *xx, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_sig_t *y, int N, int ord, char *stack); +void syn_percep_zero16(const spx_word16_t *xx, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack); +void residue_percep_zero16(const spx_word16_t *xx, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack); void compute_impulse_response(const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack); diff --git a/libspeex/filters_arm4.h b/libspeex/filters_arm4.h index ac4d7a9..9138610 100644 --- a/libspeex/filters_arm4.h +++ b/libspeex/filters_arm4.h @@ -95,295 +95,3 @@ int normalize16(const spx_sig_t *x, spx_word16_t *y, int max_scale, int len) return sig_shift; } -#define OVERRIDE_FILTER_MEM2 -void filter_mem2(const spx_sig_t *x, const spx_coef_t *num, const spx_coef_t *den, spx_sig_t *y, int N, int ord, spx_mem_t *mem) -{ - int i,j; - spx_sig_t xi,yi,nyi; - - for (i=0;i<ord;i++) - mem[i] = SHR32(mem[i],1); - for (i=0;i<N;i++) - { - int deadm, deadn, deadd, deadidx, x1, y1, dead1, dead2, dead3, dead4, dead5, dead6; - xi=SATURATE(x[i],805306368); - yi = SATURATE(ADD32(xi, SHL(mem[0],2)),805306368); - nyi = -yi; - y[i] = yi; - __asm__ __volatile__ ( - "\tldrsh %6, [%1], #2\n" - "\tsmull %8, %9, %4, %6\n" -#ifdef SHORTCUTS - "\tldrsh %6, [%2], #2\n" - "\tldr %10, [%0, #4]\n" - "\tmov %8, %8, lsr #15\n" - "\tsmull %7, %11, %5, %6\n" - "\tldrsh %6, [%1], #2\n" - "\tadd %8, %8, %9, lsl #17\n" - "\tadd %10, %10, %8\n" - "\tsmull %8, %9, %4, %6\n" - "\tadd %10, %10, %7, lsr #15\n" - "\tadd %10, %10, %11, lsl #17\n" - "\tstr %10, [%0], #4 \n" - - "\tldrsh %6, [%2], #2\n" - "\tldr %10, [%0, #4]\n" - "\tmov %8, %8, lsr #15\n" - "\tsmull %7, %11, %5, %6\n" - "\tldrsh %6, [%1], #2\n" - "\tadd %8, %8, %9, lsl #17\n" - "\tadd %10, %10, %8\n" - "\tsmull %8, %9, %4, %6\n" - "\tadd %10, %10, %7, lsr #15\n" - "\tadd %10, %10, %11, lsl #17\n" - "\tstr %10, [%0], #4 \n" - - "\tldrsh %6, [%2], #2\n" - "\tldr %10, [%0, #4]\n" - "\tmov %8, %8, lsr #15\n" - "\tsmull %7, %11, %5, %6\n" - "\tldrsh %6, [%1], #2\n" - "\tadd %8, %8, %9, lsl #17\n" - "\tadd %10, %10, %8\n" - "\tsmull %8, %9, %4, %6\n" - "\tadd %10, %10, %7, lsr #15\n" - "\tadd %10, %10, %11, lsl #17\n" - "\tstr %10, [%0], #4 \n" - - "\tldrsh %6, [%2], #2\n" - "\tldr %10, [%0, #4]\n" - "\tmov %8, %8, lsr #15\n" - "\tsmull %7, %11, %5, %6\n" - "\tldrsh %6, [%1], #2\n" - "\tadd %8, %8, %9, lsl #17\n" - "\tadd %10, %10, %8\n" - "\tsmull %8, %9, %4, %6\n" - "\tadd %10, %10, %7, lsr #15\n" - "\tadd %10, %10, %11, lsl #17\n" - "\tstr %10, [%0], #4 \n" - - "\tldrsh %6, [%2], #2\n" - "\tldr %10, [%0, #4]\n" - "\tmov %8, %8, lsr #15\n" - "\tsmull %7, %11, %5, %6\n" - "\tldrsh %6, [%1], #2\n" - "\tadd %8, %8, %9, lsl #17\n" - "\tadd %10, %10, %8\n" - "\tsmull %8, %9, %4, %6\n" - "\tadd %10, %10, %7, lsr #15\n" - "\tadd %10, %10, %11, lsl #17\n" - "\tstr %10, [%0], #4 \n" - - "\tldrsh %6, [%2], #2\n" - "\tldr %10, [%0, #4]\n" - "\tmov %8, %8, lsr #15\n" - "\tsmull %7, %11, %5, %6\n" - "\tldrsh %6, [%1], #2\n" - "\tadd %8, %8, %9, lsl #17\n" - "\tadd %10, %10, %8\n" - "\tsmull %8, %9, %4, %6\n" - "\tadd %10, %10, %7, lsr #15\n" - "\tadd %10, %10, %11, lsl #17\n" - "\tstr %10, [%0], #4 \n" - - "\tldrsh %6, [%2], #2\n" - "\tldr %10, [%0, #4]\n" - "\tmov %8, %8, lsr #15\n" - "\tsmull %7, %11, %5, %6\n" - "\tldrsh %6, [%1], #2\n" - "\tadd %8, %8, %9, lsl #17\n" - "\tadd %10, %10, %8\n" - "\tsmull %8, %9, %4, %6\n" - "\tadd %10, %10, %7, lsr #15\n" - "\tadd %10, %10, %11, lsl #17\n" - "\tstr %10, [%0], #4 \n" - - "\tldrsh %6, [%2], #2\n" - "\tldr %10, [%0, #4]\n" - "\tmov %8, %8, lsr #15\n" - "\tsmull %7, %11, %5, %6\n" - "\tldrsh %6, [%1], #2\n" - "\tadd %8, %8, %9, lsl #17\n" - "\tadd %10, %10, %8\n" - "\tsmull %8, %9, %4, %6\n" - "\tadd %10, %10, %7, lsr #15\n" - "\tadd %10, %10, %11, lsl #17\n" - "\tstr %10, [%0], #4 \n" - - "\tldrsh %6, [%2], #2\n" - "\tldr %10, [%0, #4]\n" - "\tmov %8, %8, lsr #15\n" - "\tsmull %7, %11, %5, %6\n" - "\tldrsh %6, [%1], #2\n" - "\tadd %8, %8, %9, lsl #17\n" - "\tadd %10, %10, %8\n" - "\tsmull %8, %9, %4, %6\n" - "\tadd %10, %10, %7, lsr #15\n" - "\tadd %10, %10, %11, lsl #17\n" - "\tstr %10, [%0], #4 \n" - - -#else - ".filterloop%=: \n" - "\tldrsh %6, [%2], #2\n" - "\tldr %10, [%0, #4]\n" - "\tmov %8, %8, lsr #15\n" - "\tsmull %7, %11, %5, %6\n" - "\tadd %8, %8, %9, lsl #17\n" - "\tldrsh %6, [%1], #2\n" - "\tadd %10, %10, %8\n" - "\tsmull %8, %9, %4, %6\n" - "\tadd %10, %10, %7, lsr #15\n" - "\tsubs %3, %3, #1\n" - "\tadd %10, %10, %11, lsl #17\n" - "\tstr %10, [%0], #4 \n" - "\t bne .filterloop%=\n" -#endif - "\tmov %8, %8, lsr #15\n" - "\tadd %10, %8, %9, lsl #17\n" - "\tldrsh %6, [%2], #2\n" - "\tsmull %8, %9, %5, %6\n" - "\tadd %10, %10, %8, lsr #15\n" - "\tadd %10, %10, %9, lsl #17\n" - "\tstr %10, [%0], #4 \n" - - : "=r" (deadm), "=r" (deadn), "=r" (deadd), "=r" (deadidx), - "=r" (xi), "=r" (nyi), "=r" (dead1), "=r" (dead2), - "=r" (dead3), "=r" (dead4), "=r" (dead5), "=r" (dead6) - : "0" (mem), "1" (num), "2" (den), "3" (ord-1), "4" (xi), "5" (nyi) - : "cc", "memory"); - - } - for (i=0;i<ord;i++) - mem[i] = SHL32(mem[i],1); -} - -#define OVERRIDE_IIR_MEM2 -void iir_mem2(const spx_sig_t *x, const spx_coef_t *den, spx_sig_t *y, int N, int ord, spx_mem_t *mem) -{ - int i,j; - spx_sig_t xi,yi,nyi; - - for (i=0;i<ord;i++) - mem[i] = SHR32(mem[i],1); - - for (i=0;i<N;i++) - { - int deadm, deadd, deadidx, dead1, dead2, dead3, dead4, dead5, dead6; - xi=SATURATE(x[i],805306368); - yi = SATURATE(ADD32(xi, SHL(mem[0],2)),805306368); - nyi = -yi; - y[i] = yi; - __asm__ __volatile__ ( - "\tldrsh %4, [%1], #2\n" - "\tsmull %5, %6, %3, %4\n" - -#ifdef SHORTCUTS - - "\tldrsh %4, [%1], #2\n" - "\tmov %5, %5, lsr #15\n" - "\tldr %7, [%0, #4]\n" - "\tadd %8, %5, %6, lsl #17\n" - "\tsmull %5, %6, %3, %4\n" - "\tadd %7, %7, %8\n" - "\tstr %7, [%0], #4 \n" - - - "\tldrsh %4, [%1], #2\n" - "\tmov %5, %5, lsr #15\n" - "\tldr %9, [%0, #4]\n" - "\tadd %8, %5, %6, lsl #17\n" - "\tsmull %5, %6, %3, %4\n" - "\tadd %9, %9, %8\n" - "\tstr %9, [%0], #4 \n" - - "\tldrsh %4, [%1], #2\n" - "\tmov %5, %5, lsr #15\n" - "\tldr %7, [%0, #4]\n" - "\tadd %8, %5, %6, lsl #17\n" - "\tsmull %5, %6, %3, %4\n" - "\tadd %7, %7, %8\n" - "\tstr %7, [%0], #4 \n" - - - "\tldrsh %4, [%1], #2\n" - "\tmov %5, %5, lsr #15\n" - "\tldr %9, [%0, #4]\n" - "\tadd %8, %5, %6, lsl #17\n" - "\tsmull %5, %6, %3, %4\n" - "\tadd %9, %9, %8\n" - "\tstr %9, [%0], #4 \n" - - "\tldrsh %4, [%1], #2\n" - "\tmov %5, %5, lsr #15\n" - "\tldr %7, [%0, #4]\n" - "\tadd %8, %5, %6, lsl #17\n" - "\tsmull %5, %6, %3, %4\n" - "\tadd %7, %7, %8\n" - "\tstr %7, [%0], #4 \n" - - - "\tldrsh %4, [%1], #2\n" - "\tmov %5, %5, lsr #15\n" - "\tldr %9, [%0, #4]\n" - "\tadd %8, %5, %6, lsl #17\n" - "\tsmull %5, %6, %3, %4\n" - "\tadd %9, %9, %8\n" - "\tstr %9, [%0], #4 \n" - - "\tldrsh %4, [%1], #2\n" - "\tmov %5, %5, lsr #15\n" - "\tldr %7, [%0, #4]\n" - "\tadd %8, %5, %6, lsl #17\n" - "\tsmull %5, %6, %3, %4\n" - "\tadd %7, %7, %8\n" - "\tstr %7, [%0], #4 \n" - - - "\tldrsh %4, [%1], #2\n" - "\tmov %5, %5, lsr #15\n" - "\tldr %9, [%0, #4]\n" - "\tadd %8, %5, %6, lsl #17\n" - "\tsmull %5, %6, %3, %4\n" - "\tadd %9, %9, %8\n" - "\tstr %9, [%0], #4 \n" - - "\tldrsh %4, [%1], #2\n" - "\tmov %5, %5, lsr #15\n" - "\tldr %7, [%0, #4]\n" - "\tadd %8, %5, %6, lsl #17\n" - "\tsmull %5, %6, %3, %4\n" - "\tadd %7, %7, %8\n" - "\tstr %7, [%0], #4 \n" - - - -#else - ".iirloop%=: \n" - "\tldr %7, [%0, #4]\n" - - "\tldrsh %4, [%1], #2\n" - "\tmov %5, %5, lsr #15\n" - "\tadd %8, %5, %6, lsl #17\n" - "\tsmull %5, %6, %3, %4\n" - "\tadd %7, %7, %8\n" - "\tstr %7, [%0], #4 \n" - "\tsubs %2, %2, #1\n" - "\t bne .iirloop%=\n" - -#endif - "\tmov %5, %5, lsr #15\n" - "\tadd %7, %5, %6, lsl #17\n" - "\tstr %7, [%0], #4 \n" - - : "=r" (deadm), "=r" (deadd), "=r" (deadidx), "=r" (nyi), - "=r" (dead1), "=r" (dead2), "=r" (dead3), "=r" (dead4), - "=r" (dead5), "=r" (dead6) - : "0" (mem), "1" (den), "2" (ord-1), "3" (nyi) - : "cc", "memory"); - - } - for (i=0;i<ord;i++) - mem[i] = SHL32(mem[i],1); - -} diff --git a/libspeex/filters_bfin.h b/libspeex/filters_bfin.h index 2180ed4..1e433ee 100644 --- a/libspeex/filters_bfin.h +++ b/libspeex/filters_bfin.h @@ -79,143 +79,6 @@ int normalize16(const spx_sig_t *x, spx_word16_t *y, spx_sig_t max_scale, int le return sig_shift; } -#define OVERRIDE_FILTER_MEM2 -void filter_mem2(const spx_sig_t *_x, const spx_coef_t *num, const spx_coef_t *den, spx_sig_t *_y, int N, int ord, spx_mem_t *mem) -{ - spx_word32_t xy2[N+1]; - spx_word32_t *xy = xy2+1; - spx_word32_t numden_a[2*ord+2]; - spx_word16_t *numden = (spx_word16_t*) numden_a; - int i; - for (i=0;i<ord;i++) - { - numden[2*i] = num[i]; - numden[2*i+1] = den[i]; - } - __asm__ __volatile__ - ( - /* Register setup */ - "R0 = %5;\n\t" /*ord */ - - "P0 = %3;\n\t" - "I0 = P0;\n\t" - "B0 = P0;\n\t" /* numden */ - "L0 = 0;\n\t" - - "P2 = %0;\n\t" /* Fused xy */ - "I2 = P2;\n\t" - "L2 = 0;\n\t" - - "P4 = %6;\n\t" /* mem */ - "P0 = %1;\n\t" /* _x */ - "P1 = %2;\n\t" /* _y */ - - /* First sample */ - "R1 = [P4++];\n\t" - "R1 <<= 1;\n\t" /* shift mem */ - "R2 = [P0++];\n\t" /* load x[0] */ - "R1 = R1 + R2;\n\t" - "[P1++] = R1;\n\t" /* store y[0] */ - "R1 <<= 2;\n\t" - "R2 <<= 2;\n\t" - "R2 = PACK(R1.H, R2.H);\n\t" /* pack x16 and y16 */ - "[P2] = R2;\n\t" - - /* Samples 1 to ord-1 (using memory) */ - "R0 += -1;\n\t" - "R3 = 0;\n\t" - "LC0 = R0;\n\t" - "LOOP filter_start%= LC0;\n\t" - "LOOP_BEGIN filter_start%=;\n\t" - "R3 += 1;\n\t" - "LC1 = R3;\n\t" - - "R1 = [P4++];\n\t" - "A1 = R1;\n\t" - "A0 = 0;\n\t" - "I0 = B0;\n\t" - "I2 = P2;\n\t" - "P2 += 4;\n\t" - "R4 = [I0++] || R5 = [I2--];\n\t" - "LOOP filter_start_inner%= LC1;\n\t" - "LOOP_BEGIN filter_start_inner%=;\n\t" - "A1 -= R4.H*R5.H, A0 += R4.L*R5.L (IS) || R4 = [I0++] || R5 = [I2--];\n\t" - "LOOP_END filter_start_inner%=;\n\t" - "A0 += A1;\n\t" - "R4 = A0;\n\t" - "R4 <<= 1;\n\t" /* shift mem */ - "R2 = [P0++];\n\t" /* load x */ - "R4 = R4 + R2;\n\t" - "[P1++] = R4;\n\t" /* store y */ - "R4 <<= 2;\n\t" - "R2 <<= 2;\n\t" - "R2 = PACK(R4.H, R2.H);\n\t" /* pack x16 and y16 */ - "[P2] = R2;\n\t" - - "LOOP_END filter_start%=;\n\t" - - /* Samples ord to N*/ - "R0 = %5;\n\t" - "R0 <<= 1;\n\t" - "I0 = B0;\n\t" /* numden */ - "R0 <<= 1;\n\t" - "L0 = R0;\n\t" - - "R0 = %5;\n\t" /* org */ - "R2 = %4;\n\t" /* N */ - "R2 = R2 - R0;\n\t" - "R4 = [I0++];\n\t" /* numden */ - "LC0 = R2;\n\t" - "P3 = R0;\n\t" - "R0 <<= 2;\n\t" - "R0 += 8;\n\t" - "I2 = P2;\n\t" - "M0 = R0;\n\t" - "A1 = A0 = 0;\n\t" - "R5 = [I2--];\n\t" /* load xy */ - "LOOP filter_mid%= LC0;\n\t" - "LOOP_BEGIN filter_mid%=;\n\t" - "LOOP filter_mid_inner%= LC1=P3;\n\t" - "LOOP_BEGIN filter_mid_inner%=;\n\t" - "A1 -= R4.H*R5.H, A0 += R4.L*R5.L (IS) || R4 = [I0++] || R5 = [I2--];\n\t" - "LOOP_END filter_mid_inner%=;\n\t" - "R0 = (A0 += A1) || I2 += M0;\n\t" - "R0 = R0 << 1 || R5 = [P0++];\n\t" /* load x */ - "R0 = R0 + R5;\n\t" - "R0 = R0 << 2 || [P1++] = R0;\n\t" /* shift y | store y */ - "R5 = R5 << 2;\n\t" - "R5 = PACK(R0.H, R5.H);\n\t" - "A1 = A0 = 0 || [I2--] = R5\n\t" - "LOOP_END filter_mid%=;\n\t" - "I2 += 4;\n\t" - "P2 = I2;\n\t" - /* Update memory */ - "P4 = %6;\n\t" - "R0 = %5;\n\t" - "LC0 = R0;\n\t" - "P0 = B0;\n\t" - "A1 = A0 = 0;\n\t" - "LOOP mem_update%= LC0;\n\t" - "LOOP_BEGIN mem_update%=;\n\t" - "I2 = P2;\n\t" - "I0 = P0;\n\t" - "P0 += 4;\n\t" - "R0 = LC0;\n\t" - "LC1 = R0;\n\t" - "R5 = [I2--] || R4 = [I0++];\n\t" - "LOOP mem_accum%= LC1;\n\t" - "LOOP_BEGIN mem_accum%=;\n\t" - "A1 -= R4.H*R5.H, A0 += R4.L*R5.L (IS) || R4 = [I0++] || R5 = [I2--];\n\t" - "LOOP_END mem_accum%=;\n\t" - "R0 = (A0 += A1);\n\t" - "A1 = A0 = 0 || [P4++] = R0;\n\t" - "LOOP_END mem_update%=;\n\t" - "L0 = 0;\n\t" - : : "m" (xy), "m" (_x), "m" (_y), "m" (numden), "m" (N), "m" (ord), "m" (mem) - : "A0", "A1", "R0", "R1", "R2", "R3", "R4", "R5", "P0", "P1", "P2", "P3", "P4", "B0", "I0", "I2", "L0", "L2", "M0", "memory" - ); - -} #define OVERRIDE_FILTER_MEM16 @@ -363,130 +226,6 @@ void filter_mem16(const spx_word16_t *_x, const spx_coef_t *num, const spx_coef_ - -#define OVERRIDE_IIR_MEM2 -void iir_mem2(const spx_sig_t *_x, const spx_coef_t *den, spx_sig_t *_y, int N, int ord, spx_mem_t *mem) -{ - spx_word16_t y[N+2]; - spx_word16_t *yy; - yy = y+2; - __asm__ __volatile__ - ( - /* Register setup */ - "R0 = %5;\n\t" /*ord */ - - "P1 = %3;\n\t" - "I1 = P1;\n\t" - "B1 = P1;\n\t" - "L1 = 0;\n\t" - - "P3 = %0;\n\t" - "I3 = P3;\n\t" - "L3 = 0;\n\t" - - "P4 = %6;\n\t" - "P0 = %1;\n\t" - "P1 = %2;\n\t" - - /* First sample */ - "R1 = [P4++];\n\t" - "R1 <<= 1;\n\t" - "R2 = [P0++];\n\t" - "R1 = R1 + R2;\n\t" - "[P1++] = R1;\n\t" - "R1 <<= 2;\n\t" - "W[P3] = R1.H;\n\t" - "R2 <<= 2;\n\t" - - /* Samples 1 to ord-1 (using memory) */ - "R0 += -1;\n\t" - "R3 = 0;\n\t" - "LC0 = R0;\n\t" - "LOOP filter_start%= LC0;\n\t" - "LOOP_BEGIN filter_start%=;\n\t" - "R3 += 1;\n\t" - "LC1 = R3;\n\t" - - "R1 = [P4++];\n\t" - "A1 = R1;\n\t" - "I1 = B1;\n\t" - "I3 = P3;\n\t" - "P3 += 2;\n\t" - "LOOP filter_start_inner%= LC1;\n\t" - "LOOP_BEGIN filter_start_inner%=;\n\t" - "R4.L = W[I1++];\n\t" - "R5.L = W[I3--];\n\t" - "A1 -= R4.L*R5.L (IS);\n\t" - "LOOP_END filter_start_inner%=;\n\t" - - "R1 = A1;\n\t" - "R1 <<= 1;\n\t" - "R2 = [P0++];\n\t" - "R1 = R1 + R2;\n\t" - "[P1++] = R1;\n\t" - "R1 <<= 2;\n\t" - "W[P3] = R1.H;\n\t" - "R2 <<= 2;\n\t" - "LOOP_END filter_start%=;\n\t" - - /* Samples ord to N*/ - "R0 = %5;\n\t" - "R0 <<= 1;\n\t" - "I1 = B1;\n\t" - "L1 = R0;\n\t" - - "R0 = %5;\n\t" - "R2 = %4;\n\t" - "R2 = R2 - R0;\n\t" - "R4.L = W[I1++];\n\t" - "LC0 = R2;\n\t" - "LOOP filter_mid%= LC0;\n\t" - "LOOP_BEGIN filter_mid%=;\n\t" - "LC1 = R0;\n\t" - "A1 = 0;\n\t" - "I3 = P3;\n\t" - "P3 += 2;\n\t" - "R5.L = W[I3--];\n\t" - "LOOP filter_mid_inner%= LC1;\n\t" - "LOOP_BEGIN filter_mid_inner%=;\n\t" - "A1 -= R4.L*R5.L (IS) || R4.L = W[I1++] || R5.L = W[I3--];\n\t" - "LOOP_END filter_mid_inner%=;\n\t" - "R1 = A1;\n\t" - "R1 = R1 << 1 || R2 = [P0++];\n\t" - "R1 = R1 + R2;\n\t" - "R1 = R1 << 2 || [P1++] = R1;\n\t" - "W[P3] = R1.H;\n\t" - "LOOP_END filter_mid%=;\n\t" - - /* Update memory */ - "P4 = %6;\n\t" - "R0 = %5;\n\t" - "LC0 = R0;\n\t" - "P1 = B1;\n\t" - "LOOP mem_update%= LC0;\n\t" - "LOOP_BEGIN mem_update%=;\n\t" - "A0 = 0;\n\t" - "I3 = P3;\n\t" - "I1 = P1;\n\t" - "P1 += 2;\n\t" - "R0 = LC0;\n\t" - "LC1=R0;\n\t" - "R5.L = W[I3--] || R4.L = W[I1++];\n\t" - "LOOP mem_accum%= LC1;\n\t" - "LOOP_BEGIN mem_accum%=;\n\t" - "A0 -= R4.L*R5.L (IS) || R4.L = W[I1++] || R5.L = W[I3--];\n\t" - "LOOP_END mem_accum%=;\n\t" - "R0 = A0;\n\t" - "[P4++] = R0;\n\t" - "LOOP_END mem_update%=;\n\t" - "L1 = 0;\n\t" - : : "m" (yy), "m" (_x), "m" (_y), "m" (den), "m" (N), "m" (ord), "m" (mem) - : "A0", "A1", "R0", "R1", "R2", "R3", "R4", "R5", "P0", "P1", "P2", "P3", "P4", "B1", "I1", "I3", "L1", "L3", "memory" - ); - -} - - #define OVERRIDE_IIR_MEM16 void iir_mem16(const spx_word16_t *_x, const spx_coef_t *den, spx_word16_t *_y, int N, int ord, spx_mem_t *mem, char *stack) { @@ -612,18 +351,6 @@ void iir_mem16(const spx_word16_t *_x, const spx_coef_t *den, spx_word16_t *_y, } -#define OVERRIDE_FIR_MEM2 -void fir_mem2(const spx_sig_t *x, const spx_coef_t *num, spx_sig_t *y, int N, int ord, spx_mem_t *mem) -{ - int i; - spx_coef_t den2[12]; - spx_coef_t *den; - den = (spx_coef_t*)((((int)den2)+4)&0xfffffffc); - for (i=0;i<10;i++) - den[i] = 0; - filter_mem2(x, num, den, y, N, ord, mem); -} - #define OVERRIDE_FIR_MEM16 void fir_mem16(const spx_word16_t *x, const spx_coef_t *num, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack) { diff --git a/libspeex/filters_sse.h b/libspeex/filters_sse.h index 2f03747..4bb333d 100644 --- a/libspeex/filters_sse.h +++ b/libspeex/filters_sse.h @@ -34,7 +34,7 @@ #include <xmmintrin.h> -void filter_mem2_10(const float *x, const float *_num, const float *_den, float *y, int N, int ord, float *_mem) +void filter_mem16_10(const float *x, const float *_num, const float *_den, float *y, int N, int ord, float *_mem) { __m128 num[3], den[3], mem[3]; @@ -87,7 +87,7 @@ void filter_mem2_10(const float *x, const float *_num, const float *_den, float _mm_store_ss(_mem+9, mem[2]); } -void filter_mem2_8(const float *x, const float *_num, const float *_den, float *y, int N, int ord, float *_mem) +void filter_mem16_8(const float *x, const float *_num, const float *_den, float *y, int N, int ord, float *_mem) { __m128 num[2], den[2], mem[2]; @@ -130,18 +130,18 @@ void filter_mem2_8(const float *x, const float *_num, const float *_den, float * } -#define OVERRIDE_FILTER_MEM2 -void filter_mem2(const float *x, const float *_num, const float *_den, float *y, int N, int ord, float *_mem) +#define OVERRIDE_FILTER_MEM16 +void filter_mem16(const float *x, const float *_num, const float *_den, float *y, int N, int ord, float *_mem, char *stack) { if(ord==10) - filter_mem2_10(x, _num, _den, y, N, ord, _mem); + filter_mem16_10(x, _num, _den, y, N, ord, _mem); else if (ord==8) - filter_mem2_8(x, _num, _den, y, N, ord, _mem); + filter_mem16_8(x, _num, _den, y, N, ord, _mem); } -void iir_mem2_10(const float *x, const float *_den, float *y, int N, int ord, float *_mem) +void iir_mem16_10(const float *x, const float *_den, float *y, int N, int ord, float *_mem) { __m128 den[3], mem[3]; @@ -190,7 +190,7 @@ void iir_mem2_10(const float *x, const float *_den, float *y, int N, int ord, fl } -void iir_mem2_8(const float *x, const float *_den, float *y, int N, int ord, float *_mem) +void iir_mem16_8(const float *x, const float *_den, float *y, int N, int ord, float *_mem) { __m128 den[2], mem[2]; @@ -229,17 +229,17 @@ void iir_mem2_8(const float *x, const float *_den, float *y, int N, int ord, flo _mm_storeu_ps(_mem+4, mem[1]); } -#define OVERRIDE_IIR_MEM2 -void iir_mem2(const float *x, const float *_den, float *y, int N, int ord, float *_mem) +#define OVERRIDE_IIR_MEM16 +void iir_mem16(const float *x, const float *_den, float *y, int N, int ord, float *_mem, char *stack) { if(ord==10) - iir_mem2_10(x, _den, y, N, ord, _mem); + iir_mem16_10(x, _den, y, N, ord, _mem); else if (ord==8) - iir_mem2_8(x, _den, y, N, ord, _mem); + iir_mem16_8(x, _den, y, N, ord, _mem); } -void fir_mem2_10(const float *x, const float *_num, float *y, int N, int ord, float *_mem) +void fir_mem16_10(const float *x, const float *_num, float *y, int N, int ord, float *_mem) { __m128 num[3], mem[3]; @@ -287,7 +287,7 @@ void fir_mem2_10(const float *x, const float *_num, float *y, int N, int ord, fl _mm_store_ss(_mem+9, mem[2]); } -void fir_mem2_8(const float *x, const float *_num, float *y, int N, int ord, float *_mem) +void fir_mem16_8(const float *x, const float *_num, float *y, int N, int ord, float *_mem) { __m128 num[2], mem[2]; @@ -326,11 +326,11 @@ void fir_mem2_8(const float *x, const float *_num, float *y, int N, int ord, flo _mm_storeu_ps(_mem+4, mem[1]); } -#define OVERRIDE_FIR_MEM2 -void fir_mem2(const float *x, const float *_num, float *y, int N, int ord, float *_mem) +#define OVERRIDE_FIR_MEM16 +void fir_mem16(const float *x, const float *_num, float *y, int N, int ord, float *_mem, char *stack) { if(ord==10) - fir_mem2_10(x, _num, y, N, ord, _mem); + fir_mem16_10(x, _num, y, N, ord, _mem); else if (ord==8) - fir_mem2_8(x, _num, y, N, ord, _mem); + fir_mem16_8(x, _num, y, N, ord, _mem); } diff --git a/libspeex/fixed_debug.h b/libspeex/fixed_debug.h index 65c5712..d5c449f 100644 --- a/libspeex/fixed_debug.h +++ b/libspeex/fixed_debug.h @@ -74,53 +74,57 @@ static inline int NEG32(long long x) return res; } -static inline short EXTRACT16(int x) +#define EXTRACT16(x) _EXTRACT16(x, __FILE__, __LINE__) +static inline short _EXTRACT16(int x, char *file, int line) { int res; if (!VERIFY_SHORT(x)) { - fprintf (stderr, "EXTRACT16: input is not short: %d\n", x); + fprintf (stderr, "EXTRACT16: input is not short: %d in %s: line %d\n", x, file, line); } res = x; spx_mips++; return res; } -static inline int EXTEND32(int x) +#define EXTEND32(x) _EXTEND32(x, __FILE__, __LINE__) +static inline int _EXTEND32(int x, char *file, int line) { int res; if (!VERIFY_SHORT(x)) { - fprintf (stderr, "EXTRACT16: input is not short: %d\n", x); + fprintf (stderr, "EXTEND32: input is not short: %d in %s: line %d\n", x, file, line); } res = x; spx_mips++; return res; } -static inline short SHR16(int a, int shift) +#define SHR16(a, shift) _SHR16(a, shift, __FILE__, __LINE__) +static inline short _SHR16(int a, int shift, char *file, int line) { int res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) { - fprintf (stderr, "SHR16: inputs are not short: %d %d\n", a, shift); + fprintf (stderr, "SHR16: inputs are not short: %d >> %d in %s: line %d\n", a, shift, file, line); } res = a>>shift; if (!VERIFY_SHORT(res)) - fprintf (stderr, "SHR16: output is not short: %d\n", res); + fprintf (stderr, "SHR16: output is not short: %d in %s: line %d\n", res, file, line); spx_mips++; return res; } -static inline short SHL16(int a, int shift) +#define SHL16(a, shift) _SHL16(a, shift, __FILE__, __LINE__) +static inline short _SHL16(int a, int shift, char *file, int line) { int res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) { - fprintf (stderr, "SHR16: inputs are not short: %d %d\n", a, shift); + fprintf (stderr, "SHL16: inputs are not short: %d %d in %s: line %d\n", a, shift, file, line); } res = a<<shift; if (!VERIFY_SHORT(res)) - fprintf (stderr, "SHR16: output is not short: %d\n", res); + fprintf (stderr, "SHL16: output is not short: %d in %s: line %d\n", res, file, line); spx_mips++; return res; } @@ -134,7 +138,9 @@ static inline int SHR32(long long a, int shift) } res = a>>shift; if (!VERIFY_INT(res)) + { fprintf (stderr, "SHR32: output is not int: %d\n", (int)res); + } spx_mips++; return res; } @@ -143,62 +149,71 @@ static inline int SHL32(long long a, int shift) long long res; if (!VERIFY_INT(a) || !VERIFY_SHORT(shift)) { - fprintf (stderr, "SHR32: inputs are not int: %d %d\n", (int)a, shift); + fprintf (stderr, "SHL32: inputs are not int: %d %d\n", (int)a, shift); } res = a<<shift; if (!VERIFY_INT(res)) - fprintf (stderr, "SHR32: output is not int: %d\n", (int)res); + { + fprintf (stderr, "SHL32: output is not int: %d\n", (int)res); + } spx_mips++; return res; } +#define PSHR16(a,shift) (SHR16(ADD16((a),((1<<((shift))>>1))),shift)) +#define PSHR32(a,shift) (SHR32(ADD32((a),((1<<((shift))>>1))),shift)) +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) -#define PSHR16(a,shift) (SHR16(ADD16(a,(1<<((shift)-1))),shift)) -#define PSHR32(a,shift) (SHR32(ADD32(a,(1<<((shift)-1))),shift)) #define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) #define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) -#define SHR(a,shift) ((a) >> (shift)) -#define SHL(a,shift) ((a) << (shift)) +//#define SHR(a,shift) ((a) >> (shift)) +//#define SHL(a,shift) ((a) << (shift)) -static inline short ADD16(int a, int b) +#define ADD16(a, b) _ADD16(a, b, __FILE__, __LINE__) +static inline short _ADD16(int a, int b, char *file, int line) { int res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) { - fprintf (stderr, "ADD16: inputs are not short: %d %d\n", a, b); + fprintf (stderr, "ADD16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); } res = a+b; if (!VERIFY_SHORT(res)) - fprintf (stderr, "ADD16: output is not short: %d+%d=%d\n", a,b,res); + { + fprintf (stderr, "ADD16: output is not short: %d+%d=%d in %s: line %d\n", a,b,res, file, line); + } spx_mips++; return res; } -static inline short SUB16(int a, int b) + +#define SUB16(a, b) _SUB16(a, b, __FILE__, __LINE__) +static inline short _SUB16(int a, int b, char *file, int line) { int res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) { - fprintf (stderr, "SUB16: inputs are not short: %d %d\n", a, b); + fprintf (stderr, "SUB16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); } res = a-b; if (!VERIFY_SHORT(res)) - fprintf (stderr, "SUB16: output is not short: %d\n", res); + fprintf (stderr, "SUB16: output is not short: %d in %s: line %d\n", res, file, line); spx_mips++; return res; } -static inline int ADD32(long long a, long long b) +#define ADD32(a, b) _ADD32(a, b, __FILE__, __LINE__) +static inline int _ADD32(long long a, long long b, char *file, int line) { long long res; if (!VERIFY_INT(a) || !VERIFY_INT(b)) { - fprintf (stderr, "ADD32: inputs are not int: %d %d\n", (int)a, (int)b); + fprintf (stderr, "ADD32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line); } res = a+b; if (!VERIFY_INT(res)) { - fprintf (stderr, "ADD32: output is not int: %d\n", (int)res); + fprintf (stderr, "ADD32: output is not int: %d in %s: line %d\n", (int)res, file, line); } spx_mips++; return res; @@ -220,8 +235,6 @@ static inline int SUB32(long long a, long long b) #define ADD64(a,b) (MIPS_INC(a)+(b)) -#define PSHR(a,shift) (SHR((a)+(1<<((shift)-1)),shift)) - /* result fits in 16 bits */ static inline short MULT16_16_16(int a, int b) { @@ -237,36 +250,56 @@ static inline short MULT16_16_16(int a, int b) return res; } -static inline int MULT16_16(int a, int b) +#define MULT16_16(a, b) _MULT16_16(a, b, __FILE__, __LINE__) +static inline int _MULT16_16(int a, int b, char *file, int line) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) { - fprintf (stderr, "MULT16_16: inputs are not short: %d %d\n", a, b); + fprintf (stderr, "MULT16_16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); } res = ((long long)a)*b; if (!VERIFY_INT(res)) - fprintf (stderr, "MULT16_16: output is not int: %d\n", (int)res); + fprintf (stderr, "MULT16_16: output is not int: %d in %s: line %d\n", (int)res, file, line); spx_mips++; return res; } #define MAC16_16(c,a,b) (spx_mips--,ADD32((c),MULT16_16((a),(b)))) -#define MAC16_16_Q11(c,a,b) (ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),11)))) -#define MAC16_16_Q13(c,a,b) (ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),13)))) -#define MAC16_16_P13(c,a,b) (ADD32((c),SHR(ADD32(4096,MULT16_16((a),(b))),13))) +#define MAC16_16_Q11(c,a,b) (EXTRACT16(ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),11))))) +#define MAC16_16_Q13(c,a,b) (EXTRACT16(ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),13))))) +#define MAC16_16_P13(c,a,b) (EXTRACT16(ADD32((c),SHR32(ADD32(4096,MULT16_16((a),(b))),13)))) -static inline int MULT16_32_QX(int a, long long b, int Q) +#define MULT16_32_QX(a, b, Q) _MULT16_32_QX(a, b, Q, __FILE__, __LINE__) +static inline int _MULT16_32_QX(int a, long long b, int Q, char *file, int line) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_INT(b)) { - fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d\n", Q, (int)a, (int)b); + fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); } + if (ABS32(b)>=(1<<(15+Q))) + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); res = (((long long)a)*(long long)b) >> Q; if (!VERIFY_INT(res)) - fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d\n", Q, (int)a, (int)b,(int)res); + fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line); + spx_mips+=5; + return res; +} + +static inline int MULT16_32_PX(int a, long long b, int Q) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d\n", Q, (int)a, (int)b); + } + if (ABS32(b)>=(1<<(15+Q))) + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b); + res = ((((long long)a)*(long long)b) + ((1<<Q)>>1))>> Q; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d\n", Q, (int)a, (int)b,(int)res); spx_mips+=5; return res; } @@ -278,6 +311,7 @@ static inline int MULT16_32_QX(int a, long long b, int Q) #define MULT16_32_Q13(a,b) MULT16_32_QX(a,b,13) #define MULT16_32_Q14(a,b) MULT16_32_QX(a,b,14) #define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15) +#define MULT16_32_P15(a,b) MULT16_32_PX(a,b,15) #define MAC16_32_Q15(c,a,b) ADD32((c),MULT16_32_Q15((a),(b))) static inline int SATURATE(int a, int b) @@ -341,7 +375,9 @@ static inline short MULT16_16_Q15(int a, int b) res = ((long long)a)*b; res >>= 15; if (!VERIFY_SHORT(res)) + { fprintf (stderr, "MULT16_16_Q15: output is not short: %d\n", (int)res); + } spx_mips+=3; return res; } @@ -398,23 +434,24 @@ static inline short MULT16_16_P15(int a, int b) return res; } +#define DIV32_16(a, b) _DIV32_16(a, b, __FILE__, __LINE__) -static inline int DIV32_16(long long a, long long b) +static inline int _DIV32_16(long long a, long long b, char *file, int line) { long long res; if (b==0) { - fprintf(stderr, "DIV32_16: divide by zero: %d/%d\n", (int)a, (int)b); + fprintf(stderr, "DIV32_16: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); return 0; } if (!VERIFY_INT(a) || !VERIFY_SHORT(b)) { - fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d\n", (int)a, (int)b); + fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); } res = a/b; if (!VERIFY_SHORT(res)) { - fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d\n", (int)a,(int)b,(int)res); + fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d in %s: line %d\n", (int)a,(int)b,(int)res, file, line); if (res>32767) res = 32767; if (res<-32768) @@ -423,22 +460,24 @@ static inline int DIV32_16(long long a, long long b) spx_mips+=20; return res; } -static inline int DIV32(long long a, long long b) + +#define DIV32(a, b) _DIV32(a, b, __FILE__, __LINE__) +static inline int _DIV32(long long a, long long b, char *file, int line) { long long res; if (b==0) { - fprintf(stderr, "DIV32: divide by zero: %d/%d\n", (int)a, (int)b); + fprintf(stderr, "DIV32: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); return 0; } if (!VERIFY_INT(a) || !VERIFY_INT(b)) { - fprintf (stderr, "DIV32: inputs are not int/short: %d %d\n", (int)a, (int)b); + fprintf (stderr, "DIV32: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); } res = a/b; if (!VERIFY_INT(res)) - fprintf (stderr, "DIV32: output is not int: %d\n", (int)res); + fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line); spx_mips+=36; return res; } diff --git a/libspeex/fixed_generic.h b/libspeex/fixed_generic.h index 375050c..2948177 100644 --- a/libspeex/fixed_generic.h +++ b/libspeex/fixed_generic.h @@ -46,14 +46,15 @@ #define SHL16(a,shift) ((a) << (shift)) #define SHR32(a,shift) ((a) >> (shift)) #define SHL32(a,shift) ((a) << (shift)) -#define PSHR16(a,shift) (SHR16((a)+(1<<((shift)-1)),shift)) -#define PSHR32(a,shift) (SHR32((a)+(1<<((shift)-1)),shift)) +#define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift)) +#define PSHR32(a,shift) (SHR32((a)+((1<<((shift))>>1)),shift)) +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) #define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) #define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) #define SHR(a,shift) ((a) >> (shift)) #define SHL(a,shift) ((spx_word32_t)(a) << (shift)) -#define PSHR(a,shift) (SHR((a)+(1<<((shift)-1)),shift)) +#define PSHR(a,shift) (SHR((a)+((1<<((shift))>>1)),shift)) #define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) @@ -77,6 +78,7 @@ #define MULT16_32_Q11(a,b) ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11)) #define MAC16_32_Q11(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11))) +#define MULT16_32_P15(a,b) ADD32(MULT16_16((a),SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15)) #define MULT16_32_Q15(a,b) ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)) #define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))) diff --git a/libspeex/jitter.c b/libspeex/jitter.c index 6d5f2ad..2b64453 100644 --- a/libspeex/jitter.c +++ b/libspeex/jitter.c @@ -41,9 +41,12 @@ #include <speex/speex.h> #include <speex/speex_bits.h> #include <speex/speex_jitter.h> -#include <stdio.h> -#define LATE_BINS 10 +#ifndef NULL +#define NULL 0 +#endif + +#define LATE_BINS 15 #define MAX_MARGIN 30 /**< Number of bins in margin histogram */ #define SPEEX_JITTER_MAX_BUFFER_SIZE 200 /**< Maximum number of packets in jitter buffer */ @@ -68,7 +71,9 @@ struct JitterBuffer_ { int tick_size; /**< Output granularity */ int reset_state; /**< True if state was just reset */ int buffer_margin; /**< How many frames we want to keep in the buffer (lower bound) */ - + int late_cutoff; /**< How late must a packet be for it not to be considered at all */ + int interp_requested; /**< An interpolation is requested by speex_jitter_update_delay() */ + int lost_count; /**< Number of consecutive lost packets */ float shortterm_margin[MAX_MARGIN]; /**< Short term margin histogram */ float longterm_margin[MAX_MARGIN]; /**< Long term margin histogram */ @@ -86,6 +91,7 @@ JitterBuffer *jitter_buffer_init(int tick) jitter->buf[i]=NULL; jitter->tick_size = tick; jitter->buffer_margin = 1; + jitter->late_cutoff = 50; jitter_buffer_reset(jitter); } return jitter; @@ -141,6 +147,7 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) /* Cleanup buffer (remove old packets that weren't played) */ for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) { + /* Make sure we don't discard a "just-late" packet in case we want to play it next (if we interpolate). */ if (jitter->buf[i] && LE32(jitter->timestamp[i] + jitter->span[i], jitter->pointer_timestamp)) { /*fprintf (stderr, "cleaned (not played)\n");*/ @@ -187,27 +194,33 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) jitter->span[i]=packet->span; jitter->len[i]=packet->len; - /* Adjust the buffer size depending on network conditions */ - arrival_margin = (packet->timestamp - jitter->current_timestamp) - jitter->buffer_margin*jitter->tick_size; + /* Adjust the buffer size depending on network conditions. + The arrival margin is how much in advance (or late) the packet it */ + arrival_margin = (((spx_int32_t)packet->timestamp) - ((spx_int32_t)jitter->current_timestamp))/jitter->tick_size - jitter->buffer_margin; - if (arrival_margin >= -LATE_BINS*jitter->tick_size) + if (arrival_margin >= -jitter->late_cutoff) { + /* Here we compute the histogram based on the time of arrival of the packet. + This is based on a (first-order) recursive average. We keep both a short-term + histogram and a long-term histogram */ spx_int32_t int_margin; + /* First, apply the "damping" of the recursive average to all bins */ for (i=0;i<MAX_MARGIN;i++) { jitter->shortterm_margin[i] *= .98; jitter->longterm_margin[i] *= .995; } - int_margin = LATE_BINS + arrival_margin/jitter->tick_size; + /* What histogram bin the packet should be counted in */ + int_margin = LATE_BINS + arrival_margin; if (int_margin>MAX_MARGIN-1) int_margin = MAX_MARGIN-1; - if (int_margin>=0) - { - jitter->shortterm_margin[int_margin] += .02; - jitter->longterm_margin[int_margin] += .005; - } + if (int_margin<0) + int_margin = 0; + /* Add the packet to the right bin */ + jitter->shortterm_margin[int_margin] += .02; + jitter->longterm_margin[int_margin] += .005; } else { - + /* Packet has arrived *way* too late, we pretty much consider it lost and not take it into account in the histogram */ /*fprintf (stderr, "way too late = %d\n", arrival_margin);*/ if (jitter->lost_count>20) { @@ -229,9 +242,10 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) } /** Get one packet from the jitter buffer */ -int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint32_t *start_offset) +int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset) { - int i, j; + int i; + unsigned int j; float late_ratio_short; float late_ratio_long; float ontime_ratio_short; @@ -241,6 +255,17 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint int chunk_size; int incomplete = 0; + if (jitter->interp_requested) + { + jitter->interp_requested = 0; + if (start_offset) + *start_offset = 0; + packet->timestamp = jitter->pointer_timestamp; + packet->span = jitter->tick_size; + jitter->pointer_timestamp += jitter->tick_size; + packet->len = 0; + return JITTER_BUFFER_MISSING; + } if (LT32(jitter->current_timestamp+jitter->tick_size, jitter->pointer_timestamp)) { jitter->current_timestamp = jitter->pointer_timestamp; @@ -255,14 +280,17 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint late_ratio_short = 0; late_ratio_long = 0; + /* Count the proportion of packets that are late */ for (i=0;i<LATE_BINS;i++) { late_ratio_short += jitter->shortterm_margin[i]; late_ratio_long += jitter->longterm_margin[i]; } + /* Count the proportion of packets that are just on time */ ontime_ratio_short = jitter->shortterm_margin[LATE_BINS]; ontime_ratio_long = jitter->longterm_margin[LATE_BINS]; early_ratio_short = early_ratio_long = 0; + /* Count the proportion of packets that are early */ for (i=LATE_BINS+1;i<MAX_MARGIN;i++) { early_ratio_short += jitter->shortterm_margin[i]; @@ -274,42 +302,6 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint /*fprintf (stderr, "%f %f\n", early_ratio_short + ontime_ratio_short + late_ratio_short, early_ratio_long + ontime_ratio_long + late_ratio_long);*/ } - /* Adjusting the buffering */ - - if (late_ratio_short > .1 || late_ratio_long > .03) - { - /* If too many packets are arriving late */ - jitter->shortterm_margin[MAX_MARGIN-1] += jitter->shortterm_margin[MAX_MARGIN-2]; - jitter->longterm_margin[MAX_MARGIN-1] += jitter->longterm_margin[MAX_MARGIN-2]; - for (i=MAX_MARGIN-3;i>=0;i--) - { - jitter->shortterm_margin[i+1] = jitter->shortterm_margin[i]; - jitter->longterm_margin[i+1] = jitter->longterm_margin[i]; - } - jitter->shortterm_margin[0] = 0; - jitter->longterm_margin[0] = 0; - jitter->pointer_timestamp -= jitter->tick_size; - jitter->current_timestamp -= jitter->tick_size; - /*fprintf (stderr, "i");*/ - /*fprintf (stderr, "interpolate (getting some slack)\n");*/ - } else if (late_ratio_short + ontime_ratio_short < .005 && late_ratio_long + ontime_ratio_long < .01 && early_ratio_short > .8) - { - /* Many frames arriving early */ - jitter->shortterm_margin[0] += jitter->shortterm_margin[1]; - jitter->longterm_margin[0] += jitter->longterm_margin[1]; - for (i=1;i<MAX_MARGIN-1;i++) - { - jitter->shortterm_margin[i] = jitter->shortterm_margin[i+1]; - jitter->longterm_margin[i] = jitter->longterm_margin[i+1]; - } - jitter->shortterm_margin[MAX_MARGIN-1] = 0; - jitter->longterm_margin[MAX_MARGIN-1] = 0; - /*fprintf (stderr, "drop frame\n");*/ - /*fprintf (stderr, "d");*/ - jitter->pointer_timestamp += jitter->tick_size; - jitter->current_timestamp += jitter->tick_size; - /*fprintf (stderr, "dropping packet (getting more aggressive)\n");*/ - } /* Searching for the packet that fits best */ @@ -325,7 +317,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint { for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) { - if (jitter->buf[i] && jitter->timestamp[i]<=jitter->pointer_timestamp && GE32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp+chunk_size)) + if (jitter->buf[i] && LE32(jitter->timestamp[i], jitter->pointer_timestamp) && GE32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp+chunk_size)) break; } } @@ -335,7 +327,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint { for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) { - if (jitter->buf[i] && jitter->timestamp[i]<=jitter->pointer_timestamp && GT32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp)) + if (jitter->buf[i] && LE32(jitter->timestamp[i], jitter->pointer_timestamp) && GT32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp)) break; } } @@ -385,7 +377,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint jitter->buf[i] = NULL; /* Set timestamp and span (if requested) */ if (start_offset) - *start_offset = jitter->timestamp[i]-jitter->pointer_timestamp; + *start_offset = (spx_int32_t)jitter->timestamp[i]-(spx_int32_t)jitter->pointer_timestamp; packet->timestamp = jitter->timestamp[i]; packet->span = jitter->span[i]; /* Point at the end of the current packet */ @@ -409,6 +401,26 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint packet->span = jitter->tick_size; jitter->pointer_timestamp += chunk_size; packet->len = 0; + + /* Adjusting the buffering bssed on the amount of packets that are early/on time/late */ + if (late_ratio_short > .1 || late_ratio_long > .03) + { + /* If too many packets are arriving late */ + jitter->shortterm_margin[MAX_MARGIN-1] += jitter->shortterm_margin[MAX_MARGIN-2]; + jitter->longterm_margin[MAX_MARGIN-1] += jitter->longterm_margin[MAX_MARGIN-2]; + for (i=MAX_MARGIN-3;i>=0;i--) + { + jitter->shortterm_margin[i+1] = jitter->shortterm_margin[i]; + jitter->longterm_margin[i+1] = jitter->longterm_margin[i]; + } + jitter->shortterm_margin[0] = 0; + jitter->longterm_margin[0] = 0; + jitter->pointer_timestamp -= jitter->tick_size; + jitter->current_timestamp -= jitter->tick_size; + /*fprintf (stderr, "i");*/ + /*fprintf (stderr, "interpolate (getting some slack)\n");*/ + } + return JITTER_BUFFER_MISSING; } @@ -424,7 +436,113 @@ void jitter_buffer_tick(JitterBuffer *jitter) jitter->current_timestamp += jitter->tick_size; } +/* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */ +int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset) +{ + int i; + float late_ratio_short; + float late_ratio_long; + float ontime_ratio_short; + float ontime_ratio_long; + float early_ratio_short; + float early_ratio_long; + + if (LT32(jitter->current_timestamp+jitter->tick_size, jitter->pointer_timestamp)) + { + jitter->current_timestamp = jitter->pointer_timestamp; + speex_warning("did you forget to call jitter_buffer_tick() by any chance?"); + } + /*fprintf (stderr, "get packet %d %d\n", jitter->pointer_timestamp, jitter->current_timestamp);*/ + + /* FIXME: This should be only what remaining of the current tick */ + late_ratio_short = 0; + late_ratio_long = 0; + /* Count the proportion of packets that are late */ + for (i=0;i<LATE_BINS;i++) + { + late_ratio_short += jitter->shortterm_margin[i]; + late_ratio_long += jitter->longterm_margin[i]; + } + /* Count the proportion of packets that are just on time */ + ontime_ratio_short = jitter->shortterm_margin[LATE_BINS]; + ontime_ratio_long = jitter->longterm_margin[LATE_BINS]; + early_ratio_short = early_ratio_long = 0; + /* Count the proportion of packets that are early */ + for (i=LATE_BINS+1;i<MAX_MARGIN;i++) + { + early_ratio_short += jitter->shortterm_margin[i]; + early_ratio_long += jitter->longterm_margin[i]; + } + + /* Adjusting the buffering bssed on the amount of packets that are early/on time/late */ + if (late_ratio_short > .1 || late_ratio_long > .03) + { + /* If too many packets are arriving late */ + jitter->shortterm_margin[MAX_MARGIN-1] += jitter->shortterm_margin[MAX_MARGIN-2]; + jitter->longterm_margin[MAX_MARGIN-1] += jitter->longterm_margin[MAX_MARGIN-2]; + for (i=MAX_MARGIN-3;i>=0;i--) + { + jitter->shortterm_margin[i+1] = jitter->shortterm_margin[i]; + jitter->longterm_margin[i+1] = jitter->longterm_margin[i]; + } + jitter->shortterm_margin[0] = 0; + jitter->longterm_margin[0] = 0; + jitter->pointer_timestamp -= jitter->tick_size; + jitter->current_timestamp -= jitter->tick_size; + jitter->interp_requested = 1; + return JITTER_BUFFER_ADJUST_INTERPOLATE; + + } else if (late_ratio_short + ontime_ratio_short < .005 && late_ratio_long + ontime_ratio_long < .01 && early_ratio_short > .8) + { + /* Many frames arriving early */ + jitter->shortterm_margin[0] += jitter->shortterm_margin[1]; + jitter->longterm_margin[0] += jitter->longterm_margin[1]; + for (i=1;i<MAX_MARGIN-1;i++) + { + jitter->shortterm_margin[i] = jitter->shortterm_margin[i+1]; + jitter->longterm_margin[i] = jitter->longterm_margin[i+1]; + } + jitter->shortterm_margin[MAX_MARGIN-1] = 0; + jitter->longterm_margin[MAX_MARGIN-1] = 0; + /*fprintf (stderr, "drop frame\n");*/ + /*fprintf (stderr, "d");*/ + jitter->pointer_timestamp += jitter->tick_size; + jitter->current_timestamp += jitter->tick_size; + return JITTER_BUFFER_ADJUST_DROP; + } + + return JITTER_BUFFER_ADJUST_OK; +} +/* Used like the ioctl function to control the jitter buffer parameters */ +int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr) +{ + int count, i; + switch(request) + { + case JITTER_BUFFER_SET_MARGIN: + jitter->buffer_margin = *(spx_int32_t*)ptr; + break; + case JITTER_BUFFER_GET_MARGIN: + *(spx_int32_t*)ptr = jitter->buffer_margin; + break; + case JITTER_BUFFER_GET_AVALIABLE_COUNT: + count = 0; + for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) + { + if (jitter->buf[i] && LE32(jitter->pointer_timestamp, jitter->timestamp[i])) + { + count++; + } + } + *(spx_int32_t*)ptr = count; + break; + default: + speex_warning_int("Unknown jitter_buffer_ctl request: ", request); + return -1; + } + return 0; +} @@ -499,6 +617,7 @@ void speex_jitter_get(SpeexJitter *jitter, short *out, int *current_timestamp) out[i]=0; } } + jitter_buffer_update_delay(jitter->packets, &packet, NULL); jitter_buffer_tick(jitter->packets); } diff --git a/libspeex/kiss_fft.c b/libspeex/kiss_fft.c index a0b3724..775a257 100644 --- a/libspeex/kiss_fft.c +++ b/libspeex/kiss_fft.c @@ -1,5 +1,6 @@ /* Copyright (c) 2003-2004, Mark Borgerding +Copyright (c) 2005-2007, Jean-Marc Valin All rights reserved. @@ -24,121 +25,142 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND fixed or floating point complex numbers. It also delares the kf_ internal functions. */ -static kiss_fft_cpx *scratchbuf=NULL; -static size_t nscratchbuf=0; -static kiss_fft_cpx *tmpbuf=NULL; -static size_t ntmpbuf=0; - -#define CHECKBUF(buf,nbuf,n) \ - do { \ - if ( nbuf < (size_t)(n) ) {\ - speex_free(buf); \ - buf = (kiss_fft_cpx*)KISS_FFT_MALLOC(sizeof(kiss_fft_cpx)*(n)); \ - nbuf = (size_t)(n); \ - } \ - }while(0) - static void kf_bfly2( kiss_fft_cpx * Fout, const size_t fstride, const kiss_fft_cfg st, - int m + int m, + int N, + int mm ) { kiss_fft_cpx * Fout2; - kiss_fft_cpx * tw1 = st->twiddles; + kiss_fft_cpx * tw1; kiss_fft_cpx t; - Fout2 = Fout + m; if (!st->inverse) { - int i; - kiss_fft_cpx *x=Fout; - for (i=0;i<2*m;i++) + int i,j; + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;i<N;i++) + { + Fout = Fout_beg + i*mm; + Fout2 = Fout + m; + tw1 = st->twiddles; + for(j=0;j<m;j++) + { + /* Almost the same as the code path below, except that we divide the input by two + (while keeping the best accuracy possible) */ + spx_word32_t tr, ti; + tr = SHR32(SUB32(MULT16_16(Fout2->r , tw1->r),MULT16_16(Fout2->i , tw1->i)), 1); + ti = SHR32(ADD32(MULT16_16(Fout2->i , tw1->r),MULT16_16(Fout2->r , tw1->i)), 1); + tw1 += fstride; + Fout2->r = PSHR32(SUB32(SHL32(EXTEND32(Fout->r), 14), tr), 15); + Fout2->i = PSHR32(SUB32(SHL32(EXTEND32(Fout->i), 14), ti), 15); + Fout->r = PSHR32(ADD32(SHL32(EXTEND32(Fout->r), 14), tr), 15); + Fout->i = PSHR32(ADD32(SHL32(EXTEND32(Fout->i), 14), ti), 15); + ++Fout2; + ++Fout; + } + } + } else { + int i,j; + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;i<N;i++) { - x[i].r = SHR(x[i].r,1); - x[i].i = SHR(x[i].i,1); + Fout = Fout_beg + i*mm; + Fout2 = Fout + m; + tw1 = st->twiddles; + for(j=0;j<m;j++) + { + C_MUL (t, *Fout2 , *tw1); + tw1 += fstride; + C_SUB( *Fout2 , *Fout , t ); + C_ADDTO( *Fout , t ); + ++Fout2; + ++Fout; + } } } - - do{ - C_MUL (t, *Fout2 , *tw1); - tw1 += fstride; - C_SUB( *Fout2 , *Fout , t ); - C_ADDTO( *Fout , t ); - ++Fout2; - ++Fout; - }while (--m); } static void kf_bfly4( kiss_fft_cpx * Fout, const size_t fstride, const kiss_fft_cfg st, - const size_t m + const size_t m, + int N, + int mm ) { kiss_fft_cpx *tw1,*tw2,*tw3; kiss_fft_cpx scratch[6]; - size_t k=m; const size_t m2=2*m; const size_t m3=3*m; + int i, j; - tw3 = tw2 = tw1 = st->twiddles; - - if (!st->inverse) { - int i; - kiss_fft_cpx *x=Fout; - for (i=0;i<4*m;i++) - { - x[i].r = PSHR16(x[i].r,2); - x[i].i = PSHR16(x[i].i,2); - } - } if (st->inverse) { - do { - C_MUL(scratch[0],Fout[m] , *tw1 ); - C_MUL(scratch[1],Fout[m2] , *tw2 ); - C_MUL(scratch[2],Fout[m3] , *tw3 ); - - C_SUB( scratch[5] , *Fout, scratch[1] ); - C_ADDTO(*Fout, scratch[1]); - C_ADD( scratch[3] , scratch[0] , scratch[2] ); - C_SUB( scratch[4] , scratch[0] , scratch[2] ); - C_SUB( Fout[m2], *Fout, scratch[3] ); - tw1 += fstride; - tw2 += fstride*2; - tw3 += fstride*3; - C_ADDTO( *Fout , scratch[3] ); - - Fout[m].r = scratch[5].r - scratch[4].i; - Fout[m].i = scratch[5].i + scratch[4].r; - Fout[m3].r = scratch[5].r + scratch[4].i; - Fout[m3].i = scratch[5].i - scratch[4].r; - ++Fout; - } while(--k); + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;i<N;i++) + { + Fout = Fout_beg + i*mm; + tw3 = tw2 = tw1 = st->twiddles; + for (j=0;j<m;j++) + { + C_MUL(scratch[0],Fout[m] , *tw1 ); + C_MUL(scratch[1],Fout[m2] , *tw2 ); + C_MUL(scratch[2],Fout[m3] , *tw3 ); + + C_SUB( scratch[5] , *Fout, scratch[1] ); + C_ADDTO(*Fout, scratch[1]); + C_ADD( scratch[3] , scratch[0] , scratch[2] ); + C_SUB( scratch[4] , scratch[0] , scratch[2] ); + C_SUB( Fout[m2], *Fout, scratch[3] ); + tw1 += fstride; + tw2 += fstride*2; + tw3 += fstride*3; + C_ADDTO( *Fout , scratch[3] ); + + Fout[m].r = scratch[5].r - scratch[4].i; + Fout[m].i = scratch[5].i + scratch[4].r; + Fout[m3].r = scratch[5].r + scratch[4].i; + Fout[m3].i = scratch[5].i - scratch[4].r; + ++Fout; + } + } } else { - do { - C_MUL(scratch[0],Fout[m] , *tw1 ); - C_MUL(scratch[1],Fout[m2] , *tw2 ); - C_MUL(scratch[2],Fout[m3] , *tw3 ); - - C_SUB( scratch[5] , *Fout, scratch[1] ); - C_ADDTO(*Fout, scratch[1]); - C_ADD( scratch[3] , scratch[0] , scratch[2] ); - C_SUB( scratch[4] , scratch[0] , scratch[2] ); - C_SUB( Fout[m2], *Fout, scratch[3] ); - tw1 += fstride; - tw2 += fstride*2; - tw3 += fstride*3; - C_ADDTO( *Fout , scratch[3] ); - - Fout[m].r = scratch[5].r + scratch[4].i; - Fout[m].i = scratch[5].i - scratch[4].r; - Fout[m3].r = scratch[5].r - scratch[4].i; - Fout[m3].i = scratch[5].i + scratch[4].r; - ++Fout; - }while(--k); + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;i<N;i++) + { + Fout = Fout_beg + i*mm; + tw3 = tw2 = tw1 = st->twiddles; + for (j=0;j<m;j++) + { + C_MUL4(scratch[0],Fout[m] , *tw1 ); + C_MUL4(scratch[1],Fout[m2] , *tw2 ); + C_MUL4(scratch[2],Fout[m3] , *tw3 ); + + Fout->r = PSHR16(Fout->r, 2); + Fout->i = PSHR16(Fout->i, 2); + C_SUB( scratch[5] , *Fout, scratch[1] ); + C_ADDTO(*Fout, scratch[1]); + C_ADD( scratch[3] , scratch[0] , scratch[2] ); + C_SUB( scratch[4] , scratch[0] , scratch[2] ); + Fout[m2].r = PSHR16(Fout[m2].r, 2); + Fout[m2].i = PSHR16(Fout[m2].i, 2); + C_SUB( Fout[m2], *Fout, scratch[3] ); + tw1 += fstride; + tw2 += fstride*2; + tw3 += fstride*3; + C_ADDTO( *Fout , scratch[3] ); + + Fout[m].r = scratch[5].r + scratch[4].i; + Fout[m].i = scratch[5].i - scratch[4].r; + Fout[m3].r = scratch[5].r - scratch[4].i; + Fout[m3].i = scratch[5].i + scratch[4].r; + ++Fout; + } + } } } @@ -263,10 +285,13 @@ static void kf_bfly_generic( int u,k,q1,q; kiss_fft_cpx * twiddles = st->twiddles; kiss_fft_cpx t; + kiss_fft_cpx scratchbuf[17]; int Norig = st->nfft; - CHECKBUF(scratchbuf,nscratchbuf,p); - + /*CHECKBUF(scratchbuf,nscratchbuf,p);*/ + if (p>17) + speex_error("KissFFT: max radix supported is 17"); + for ( u=0; u<m; ++u ) { k=u; for ( q1=0 ; q1<p ; ++q1 ) { @@ -291,6 +316,39 @@ static void kf_bfly_generic( } } } + +static +void kf_shuffle( + kiss_fft_cpx * Fout, + const kiss_fft_cpx * f, + const size_t fstride, + int in_stride, + int * factors, + const kiss_fft_cfg st + ) +{ + const int p=*factors++; /* the radix */ + const int m=*factors++; /* stage's fft length/p */ + + /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/ + if (m==1) + { + int j; + for (j=0;j<p;j++) + { + Fout[j] = *f; + f += fstride*in_stride; + } + } else { + int j; + for (j=0;j<p;j++) + { + kf_shuffle( Fout , f, fstride*p, in_stride, factors,st); + f += fstride*in_stride; + Fout += m; + } + } +} static void kf_work( @@ -299,24 +357,34 @@ void kf_work( const size_t fstride, int in_stride, int * factors, - const kiss_fft_cfg st + const kiss_fft_cfg st, + int N, + int s2, + int m2 ) { + int i; kiss_fft_cpx * Fout_beg=Fout; const int p=*factors++; /* the radix */ const int m=*factors++; /* stage's fft length/p */ - const kiss_fft_cpx * Fout_end = Fout + p*m; - - if (m==1) { - do{ - *Fout = *f; - f += fstride*in_stride; - }while(++Fout != Fout_end ); - }else{ - do{ - kf_work( Fout , f, fstride*p, in_stride, factors,st); - f += fstride*in_stride; - }while( (Fout += m) != Fout_end ); +#if 0 + /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/ + if (m==1) + { + /* int j; + for (j=0;j<p;j++) + { + Fout[j] = *f; + f += fstride*in_stride; + }*/ + } else { + int j; + for (j=0;j<p;j++) + { + kf_work( Fout , f, fstride*p, in_stride, factors,st, N*p, fstride*in_stride, m); + f += fstride*in_stride; + Fout += m; + } } Fout=Fout_beg; @@ -328,6 +396,36 @@ void kf_work( case 5: kf_bfly5(Fout,fstride,st,m); break; default: kf_bfly_generic(Fout,fstride,st,m,p); break; } +#else + /*printf ("fft %d %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N, m2);*/ + if (m==1) + { + /*for (i=0;i<N;i++) + { + int j; + Fout = Fout_beg+i*m2; + const kiss_fft_cpx * f2 = f+i*s2; + for (j=0;j<p;j++) + { + *Fout++ = *f2; + f2 += fstride*in_stride; + } + }*/ + }else{ + kf_work( Fout , f, fstride*p, in_stride, factors,st, N*p, fstride*in_stride, m); + } + + + + + switch (p) { + case 2: kf_bfly2(Fout,fstride,st,m, N, m2); break; + case 3: for (i=0;i<N;i++){Fout=Fout_beg+i*m2; kf_bfly3(Fout,fstride,st,m);} break; + case 4: kf_bfly4(Fout,fstride,st,m, N, m2); break; + case 5: for (i=0;i<N;i++){Fout=Fout_beg+i*m2; kf_bfly5(Fout,fstride,st,m);} break; + default: for (i=0;i<N;i++){Fout=Fout_beg+i*m2; kf_bfly_generic(Fout,fstride,st,m,p);} break; + } +#endif } /* facbuf is populated by p1,m1,p2,m2, ... @@ -338,8 +436,6 @@ static void kf_factor(int n,int * facbuf) { int p=4; - double floor_sqrt; - floor_sqrt = floor( sqrt((double)n) ); /*factor out powers of 4, powers of 2, then any remaining primes */ do { @@ -349,7 +445,7 @@ void kf_factor(int n,int * facbuf) case 2: p = 3; break; default: p += 2; break; } - if (p > floor_sqrt) + if (p>32000 || (spx_int32_t)p*(spx_int32_t)p > n) p = n; /* no more factors, skip to end */ } n /= p; @@ -357,7 +453,6 @@ void kf_factor(int n,int * facbuf) *facbuf++ = n; } while (n > 1); } - /* * * User-callable function to allocate all necessary storage space for the fft. @@ -382,15 +477,22 @@ kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem int i; st->nfft=nfft; st->inverse = inverse_fft; - +#ifdef FIXED_POINT for (i=0;i<nfft;++i) { - const double pi=3.14159265358979323846264338327; - double phase = ( -2*pi /nfft ) * i; - if (st->inverse) - phase *= -1; - kf_cexp(st->twiddles+i, phase ); + spx_word32_t phase = i; + if (!st->inverse) + phase = -phase; + kf_cexp2(st->twiddles+i, DIV32(SHL32(phase,17),nfft)); } - +#else + for (i=0;i<nfft;++i) { + const double pi=3.14159265358979323846264338327; + double phase = ( -2*pi /nfft ) * i; + if (st->inverse) + phase *= -1; + kf_cexp(st->twiddles+i, phase ); + } +#endif kf_factor(nfft,st->factors); } return st; @@ -401,12 +503,15 @@ kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride) { - if (fin == fout) { - CHECKBUF(tmpbuf,ntmpbuf,st->nfft); - kf_work(tmpbuf,fin,1,in_stride, st->factors,st); - speex_move(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft); - }else{ - kf_work( fout, fin, 1,in_stride, st->factors,st ); + if (fin == fout) + { + speex_error("In-place FFT not supported"); + /*CHECKBUF(tmpbuf,ntmpbuf,st->nfft); + kf_work(tmpbuf,fin,1,in_stride, st->factors,st); + speex_move(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft);*/ + } else { + kf_shuffle( fout, fin, 1,in_stride, st->factors,st); + kf_work( fout, fin, 1,in_stride, st->factors,st, 1, in_stride, 1); } } @@ -415,16 +520,3 @@ void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) kiss_fft_stride(cfg,fin,fout,1); } - -/* not really necessary to call, but if someone is doing in-place ffts, they may want to free the - buffers from CHECKBUF - */ -void kiss_fft_cleanup(void) -{ - speex_free(scratchbuf); - scratchbuf = NULL; - nscratchbuf=0; - speex_free(tmpbuf); - tmpbuf=NULL; - ntmpbuf=0; -} diff --git a/libspeex/kiss_fftr.c b/libspeex/kiss_fftr.c index b90b725..392945c 100644 --- a/libspeex/kiss_fftr.c +++ b/libspeex/kiss_fftr.c @@ -58,13 +58,22 @@ kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenme st->super_twiddles = st->tmpbuf + nfft; kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize); - for (i = 0; i < nfft; ++i) { - double phase = - -3.14159265358979323846264338327 * ((double) i / nfft + .5); - if (inverse_fft) - phase *= -1; - kf_cexp (st->super_twiddles+i,phase); +#ifdef FIXED_POINT + for (i=0;i<nfft;++i) { + spx_word32_t phase = i+(nfft>>1); + if (!inverse_fft) + phase = -phase; + kf_cexp2(st->super_twiddles+i, DIV32(SHL32(phase,16),nfft)); } +#else + for (i=0;i<nfft;++i) { + const double pi=3.14159265358979323846264338327; + double phase = pi*(((double)i) /nfft + .5); + if (!inverse_fft) + phase = -phase; + kf_cexp(st->super_twiddles+i, phase ); + } +#endif return st; } @@ -75,8 +84,7 @@ void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *fr kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc; if ( st->substate->inverse) { - speex_warning("kiss fft usage error: improper alloc\n"); - exit(1); + speex_error("kiss fft usage error: improper alloc\n"); } ncfft = st->substate->nfft; @@ -124,14 +132,13 @@ void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *fr } } -void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata) +void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata, kiss_fft_scalar *timedata) { /* input buffer timedata is stored row-wise */ int k, ncfft; if (st->substate->inverse == 0) { - speex_warning ("kiss fft usage error: improper alloc\n"); - exit (1); + speex_error ("kiss fft usage error: improper alloc\n"); } ncfft = st->substate->nfft; @@ -161,3 +168,129 @@ void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *t } kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata); } + +void kiss_fftr2(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_scalar *freqdata) +{ + /* input buffer timedata is stored row-wise */ + int k,ncfft; + kiss_fft_cpx f2k,tdc; + spx_word32_t f1kr, f1ki, twr, twi; + + if ( st->substate->inverse) { + speex_error("kiss fft usage error: improper alloc\n"); + } + + ncfft = st->substate->nfft; + + /*perform the parallel fft of two real signals packed in real,imag*/ + kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf ); + /* The real part of the DC element of the frequency spectrum in st->tmpbuf + * contains the sum of the even-numbered elements of the input time sequence + * The imag part is the sum of the odd-numbered elements + * + * The sum of tdc.r and tdc.i is the sum of the input time sequence. + * yielding DC of input time sequence + * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... + * yielding Nyquist bin of input time sequence + */ + + tdc.r = st->tmpbuf[0].r; + tdc.i = st->tmpbuf[0].i; + C_FIXDIV(tdc,2); + CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i); + CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i); + freqdata[0] = tdc.r + tdc.i; + freqdata[2*ncfft-1] = tdc.r - tdc.i; + + for ( k=1;k <= ncfft/2 ; ++k ) + { + /*fpk = st->tmpbuf[k]; + fpnk.r = st->tmpbuf[ncfft-k].r; + fpnk.i = - st->tmpbuf[ncfft-k].i; + C_FIXDIV(fpk,2); + C_FIXDIV(fpnk,2); + + C_ADD( f1k, fpk , fpnk ); + C_SUB( f2k, fpk , fpnk ); + + C_MUL( tw , f2k , st->super_twiddles[k]); + + freqdata[2*k-1] = HALF_OF(f1k.r + tw.r); + freqdata[2*k] = HALF_OF(f1k.i + tw.i); + freqdata[2*(ncfft-k)-1] = HALF_OF(f1k.r - tw.r); + freqdata[2*(ncfft-k)] = HALF_OF(tw.i - f1k.i); + */ + + /*f1k.r = PSHR32(ADD32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1); + f1k.i = PSHR32(SUB32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1); + f2k.r = PSHR32(SUB32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1); + f2k.i = SHR32(ADD32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1); + + C_MUL( tw , f2k , st->super_twiddles[k]); + + freqdata[2*k-1] = HALF_OF(f1k.r + tw.r); + freqdata[2*k] = HALF_OF(f1k.i + tw.i); + freqdata[2*(ncfft-k)-1] = HALF_OF(f1k.r - tw.r); + freqdata[2*(ncfft-k)] = HALF_OF(tw.i - f1k.i); + */ + f2k.r = SHR32(SUB32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1); + f2k.i = PSHR32(ADD32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1); + + f1kr = SHL32(ADD32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),13); + f1ki = SHL32(SUB32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),13); + + twr = SHR32(SUB32(MULT16_16(f2k.r,st->super_twiddles[k].r),MULT16_16(f2k.i,st->super_twiddles[k].i)), 1); + twi = SHR32(ADD32(MULT16_16(f2k.i,st->super_twiddles[k].r),MULT16_16(f2k.r,st->super_twiddles[k].i)), 1); + +#ifdef FIXED_POINT + freqdata[2*k-1] = PSHR32(f1kr + twr, 15); + freqdata[2*k] = PSHR32(f1ki + twi, 15); + freqdata[2*(ncfft-k)-1] = PSHR32(f1kr - twr, 15); + freqdata[2*(ncfft-k)] = PSHR32(twi - f1ki, 15); +#else + freqdata[2*k-1] = .5f*(f1kr + twr); + freqdata[2*k] = .5f*(f1ki + twi); + freqdata[2*(ncfft-k)-1] = .5f*(f1kr - twr); + freqdata[2*(ncfft-k)] = .5f*(twi - f1ki); + +#endif + } +} + +void kiss_fftri2(kiss_fftr_cfg st,const kiss_fft_scalar *freqdata,kiss_fft_scalar *timedata) +{ + /* input buffer timedata is stored row-wise */ + int k, ncfft; + + if (st->substate->inverse == 0) { + speex_error ("kiss fft usage error: improper alloc\n"); + } + + ncfft = st->substate->nfft; + + st->tmpbuf[0].r = freqdata[0] + freqdata[2*ncfft-1]; + st->tmpbuf[0].i = freqdata[0] - freqdata[2*ncfft-1]; + /*C_FIXDIV(st->tmpbuf[0],2);*/ + + for (k = 1; k <= ncfft / 2; ++k) { + kiss_fft_cpx fk, fnkc, fek, fok, tmp; + fk.r = freqdata[2*k-1]; + fk.i = freqdata[2*k]; + fnkc.r = freqdata[2*(ncfft - k)-1]; + fnkc.i = -freqdata[2*(ncfft - k)]; + /*C_FIXDIV( fk , 2 ); + C_FIXDIV( fnkc , 2 );*/ + + C_ADD (fek, fk, fnkc); + C_SUB (tmp, fk, fnkc); + C_MUL (fok, tmp, st->super_twiddles[k]); + C_ADD (st->tmpbuf[k], fek, fok); + C_SUB (st->tmpbuf[ncfft - k], fek, fok); +#ifdef USE_SIMD + st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0); +#else + st->tmpbuf[ncfft - k].i *= -1; +#endif + } + kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata); +} diff --git a/libspeex/kiss_fftr.h b/libspeex/kiss_fftr.h index 2e8351a..7bfb423 100644 --- a/libspeex/kiss_fftr.h +++ b/libspeex/kiss_fftr.h @@ -32,7 +32,12 @@ void kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *f output freqdata has nfft/2+1 complex points */ +void kiss_fftr2(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_scalar *freqdata); + void kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata); + +void kiss_fftri2(kiss_fftr_cfg st,const kiss_fft_scalar *freqdata, kiss_fft_scalar *timedata); + /* input freqdata has nfft/2+1 complex points output timedata has nfft scalar points diff --git a/libspeex/lbr_48k_tables.c b/libspeex/lbr_48k_tables.c index 2e6db3f..d4d80dc 100644 --- a/libspeex/lbr_48k_tables.c +++ b/libspeex/lbr_48k_tables.c @@ -34,74 +34,74 @@ #endif -int dummy_epic_48k_variable=0; +const int dummy_epic_48k_variable=0; #ifdef EPIC_48K -const signed char gain_cdbk_ulbr[192] = { --31, -48, -30, --19, -10, -18, --33, -22, -45, --5, -56, -43, --30, -56, -3, --59, -17, -52, --41, -60, -58, --64, -47, -22, --30, -31, -31, --29, -14, -31, --22, -37, -58, --31, -44, 13, --37, 0, 1, --46, -55, -35, --56, -14, -53, --8, 1, -36, --29, -15, -27, --29, -39, -28, --43, -5, 3, --51, -27, -54, -10, -46, -36, -3, -3, -42, --27, 16, -22, --34, -52, 13, --31, -21, -28, --34, -45, -40, --20, -48, 4, --40, -27, 16, --6, 11, -44, --35, 12, -5, -19, -33, -37, --29, 18, -32, --29, -23, -19, -16, -47, -28, --34, -30, 17, --20, 2, -26, --38, -40, -36, -15, -14, -40, --39, 14, -9, --15, 25, -39, --26, 19, -32, --39, 17, -14, -10, -36, -26, -14, -13, -40, --29, -21, -12, --8, 19, -39, --36, -18, 15, --32, -38, -38, --19, 4, -23, --38, -7, 11, -9, -10, -39, --37, 24, -19, --34, -5, -8, --20, 23, -41, --4, 17, -31, --17, -26, -26, --24, 28, -36, --7, 15, -39, --42, 16, -11, --29, 14, -6, --36, 28, -27, --21, 5, -26, -11, -9, -39, --38, -7, 13, +const signed char gain_cdbk_ulbr[256] = { +-31, -48, -30, 10, +-19, -10, -18, 25, +-33, -22, -45, 12, +-5, -56, -43, 31, +-30, -56, -3, 28, +-59, -17, -52, 31, +-41, -60, -58, 32, +-64, -47, -22, 29, +-30, -31, -31, 2, +-29, -14, -31, 11, +-22, -37, -58, 21, +-31, -44, 13, 29, +-37, 0, 1, 35, +-46, -55, -35, 20, +-56, -14, -53, 32, +-8, 1, -36, 31, +-29, -15, -27, 13, +-29, -39, -28, 7, +-43, -5, 3, 37, +-51, -27, -54, 23, +10, -46, -36, 30, +3, -3, -42, 37, +-27, 16, -22, 32, +-34, -52, 13, 34, +-31, -21, -28, 8, +-34, -45, -40, 12, +-20, -48, 4, 32, +-40, -27, 16, 31, +-6, 11, -44, 41, +-35, 12, -5, 37, +19, -33, -37, 29, +-29, 18, -32, 27, +-29, -23, -19, 13, +16, -47, -28, 34, +-34, -30, 17, 27, +-20, 2, -26, 26, +-38, -40, -36, 9, +15, -14, -40, 37, +-39, 14, -9, 38, +-15, 25, -39, 41, +-26, 19, -32, 29, +-39, 17, -14, 37, +10, -36, -26, 26, +14, -13, -40, 37, +-29, -21, -12, 17, +-8, 19, -39, 41, +-36, -18, 15, 33, +-32, -38, -38, 6, +-19, 4, -23, 29, +-38, -7, 11, 37, +9, -10, -39, 35, +-37, 24, -19, 37, +-34, -5, -8, 27, +-20, 23, -41, 38, +-4, 17, -31, 39, +-17, -26, -26, 14, +-24, 28, -36, 36, +-7, 15, -39, 40, +-42, 16, -11, 40, +-29, 14, -6, 38, +-36, 28, -27, 35, +-21, 5, -26, 27, +11, -9, -39, 37, +-38, -7, 13, 38 }; diff --git a/libspeex/lsp.c b/libspeex/lsp.c index 3fdc08a..a73d883 100644 --- a/libspeex/lsp.c +++ b/libspeex/lsp.c @@ -509,7 +509,7 @@ void lsp_to_lpc(spx_lsp_t *freq,spx_coef_t *ak,int lpcrdr, char *stack) /* hard limit ak's to +/- 32767 */ - if (a < -32767) a = 32767; + if (a < -32767) a = -32767; if (a > 32767) a = 32767; ak[j-1] = (short)a; diff --git a/libspeex/ltp.c b/libspeex/ltp.c index 27e4f4d..fa77da2 100644 --- a/libspeex/ltp.c +++ b/libspeex/ltp.c @@ -176,20 +176,56 @@ void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *p VARDECL(spx_word32_t *best_ener); spx_word32_t e0; VARDECL(spx_word32_t *corr); +#ifdef FIXED_POINT + /* In fixed-point, we need only one (temporary) array of 32-bit values and two (corr16, ener16) + arrays for (normalized) 16-bit values */ + VARDECL(spx_word16_t *corr16); + VARDECL(spx_word16_t *ener16); + spx_word32_t *energy; + int cshift=0, eshift=0; + int scaledown = 0; + ALLOC(corr16, end-start+1, spx_word16_t); + ALLOC(ener16, end-start+1, spx_word16_t); + ALLOC(corr, end-start+1, spx_word32_t); + energy = corr; +#else + /* In floating-point, we need to float arrays and no normalized copies */ VARDECL(spx_word32_t *energy); - + spx_word16_t *corr16; + spx_word16_t *ener16; + ALLOC(energy, end-start+2, spx_word32_t); + ALLOC(corr, end-start+1, spx_word32_t); + corr16 = corr; + ener16 = energy; +#endif + ALLOC(best_score, N, spx_word32_t); ALLOC(best_ener, N, spx_word32_t); - ALLOC(corr, end-start+1, spx_word32_t); - ALLOC(energy, end-start+2, spx_word32_t); - for (i=0;i<N;i++) { best_score[i]=-1; best_ener[i]=0; pitch[i]=start; } - + +#ifdef FIXED_POINT + for (i=-end;i<len;i++) + { + if (ABS16(sw[i])>16383) + { + scaledown=1; + break; + } + } + /* If the weighted input is close to saturation, then we scale it down */ + if (scaledown) + { + for (i=-end;i<len;i++) + { + sw[i]=SHR16(sw[i],1); + } + } +#endif energy[0]=inner_prod(sw-start, sw-start, len); e0=inner_prod(sw, sw, len); for (i=start;i<end;i++) @@ -199,59 +235,42 @@ void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *p if (energy[i-start+1] < 0) energy[i-start+1] = 0; } - + +#ifdef FIXED_POINT + eshift = normalize16(energy, ener16, 32766, end-start+1); +#endif + + /* In fixed-point, this actually overrites the energy array (aliased to corr) */ pitch_xcorr(sw, sw-end, corr, len, end-start+1, stack); - - /* FIXME: Fixed-point and floating-point code should be merged */ + #ifdef FIXED_POINT + /* Normalize to 180 so we can square it and it still fits in 16 bits */ + cshift = normalize16(corr, corr16, 180, end-start+1); + /* If we scaled weighted input down, we need to scale it up again (OK, so we've just lost the LSB, who cares?) */ + if (scaledown) { - VARDECL(spx_word16_t *corr16); - VARDECL(spx_word16_t *ener16); - ALLOC(corr16, end-start+1, spx_word16_t); - ALLOC(ener16, end-start+1, spx_word16_t); - /* Normalize to 180 so we can square it and it still fits in 16 bits */ - normalize16(corr, corr16, 180, end-start+1); - normalize16(energy, ener16, 180, end-start+1); - - for (i=start;i<=end;i++) + for (i=-end;i<len;i++) { - spx_word16_t tmp = MULT16_16_16(corr16[i-start],corr16[i-start]); - /* Instead of dividing the tmp by the energy, we multiply on the other side */ - if (MULT16_16(tmp,best_ener[N-1])>MULT16_16(best_score[N-1],ADD16(1,ener16[i-start]))) - { - /* We can safely put it last and then check */ - best_score[N-1]=tmp; - best_ener[N-1]=ener16[i-start]+1; - pitch[N-1]=i; - /* Check if it comes in front of others */ - for (j=0;j<N-1;j++) - { - if (MULT16_16(tmp,best_ener[j])>MULT16_16(best_score[j],ADD16(1,ener16[i-start]))) - { - for (k=N-1;k>j;k--) - { - best_score[k]=best_score[k-1]; - best_ener[k]=best_ener[k-1]; - pitch[k]=pitch[k-1]; - } - best_score[j]=tmp; - best_ener[j]=ener16[i-start]+1; - pitch[j]=i; - break; - } - } - } + sw[i]=SHL16(sw[i],1); } - } -#else + } +#endif + + /* Search for the best pitch prediction gain */ for (i=start;i<=end;i++) { - float tmp = corr[i-start]*corr[i-start]; - if (tmp*best_ener[N-1]>best_score[N-1]*(1+energy[i-start])) + spx_word16_t tmp = MULT16_16_16(corr16[i-start],corr16[i-start]); + /* Instead of dividing the tmp by the energy, we multiply on the other side */ + if (MULT16_16(tmp,best_ener[N-1])>MULT16_16(best_score[N-1],ADD16(1,ener16[i-start]))) { - for (j=0;j<N;j++) + /* We can safely put it last and then check */ + best_score[N-1]=tmp; + best_ener[N-1]=ener16[i-start]+1; + pitch[N-1]=i; + /* Check if it comes in front of others */ + for (j=0;j<N-1;j++) { - if (tmp*best_ener[j]>best_score[j]*(1+energy[i-start])) + if (MULT16_16(tmp,best_ener[j])>MULT16_16(best_score[j],ADD16(1,ener16[i-start]))) { for (k=N-1;k>j;k--) { @@ -260,29 +279,30 @@ void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *p pitch[k]=pitch[k-1]; } best_score[j]=tmp; - best_ener[j]=energy[i-start]+1; + best_ener[j]=ener16[i-start]+1; pitch[j]=i; break; } } } } -#endif - - /* Compute open-loop gain */ + + /* Compute open-loop gain if necessary */ if (gain) { - for (j=0;j<N;j++) - { - spx_word16_t g; - i=pitch[j]; - g = DIV32(corr[i-start], 10+SHR32(MULT16_16(spx_sqrt(e0),spx_sqrt(energy[i-start])),6)); - /* FIXME: g = max(g,corr/energy) */ - if (g<0) - g = 0; - gain[j]=g; - } + for (j=0;j<N;j++) + { + spx_word16_t g; + i=pitch[j]; + g = DIV32(SHL32(EXTEND32(corr16[i-start]),cshift), 10+SHR32(MULT16_16(spx_sqrt(e0),spx_sqrt(SHL32(EXTEND32(ener16[i-start]),eshift))),6)); + /* FIXME: g = max(g,corr/energy) */ + if (g<0) + g = 0; + gain[j]=g; + } } + + } #endif @@ -342,7 +362,8 @@ const spx_word16_t *r, spx_word16_t *new_target, int *cdbk_index, int plc_tuning, -spx_word32_t cumul_gain +spx_word32_t cumul_gain, +int scaledown ) { int i,j; @@ -366,6 +387,9 @@ spx_word32_t cumul_gain x[1]=tmp1+nsf; x[2]=tmp1+2*nsf; + for (j=0;j<nsf;j++) + new_target[j] = target[j]; + { VARDECL(spx_mem_t *mm); int pp=pitch-1; @@ -379,6 +403,16 @@ spx_word32_t cumul_gain else e[j]=0; } +#ifdef FIXED_POINT + /* Scale target and excitation down if needed (avoiding overflow) */ + if (scaledown) + { + for (j=0;j<nsf;j++) + e[j] = SHR16(e[j],1); + for (j=0;j<nsf;j++) + new_target[j] = SHR16(new_target[j],1); + } +#endif for (j=0;j<p;j++) mm[j] = 0; iir_mem16(e, ak, e, nsf, p, mm, stack); @@ -391,13 +425,18 @@ spx_word32_t cumul_gain for (i=1;i>=0;i--) { spx_word16_t e0=exc2[-pitch-1+i]; +#ifdef FIXED_POINT + /* Scale excitation down if needed (avoiding overflow) */ + if (scaledown) + e0 = SHR16(e0,1); +#endif x[i][0]=MULT16_16_Q14(r[0], e0); for (j=0;j<nsf-1;j++) x[i][j+1]=ADD32(x[i+1][j],MULT16_16_P14(r[j+1], e0)); } for (i=0;i<3;i++) - corr[i]=inner_prod(x[i],target,nsf); + corr[i]=inner_prod(x[i],new_target,nsf); for (i=0;i<3;i++) for (j=0;j<=i;j++) A[i][j]=A[j][i]=inner_prod(x[i],x[j],nsf); @@ -478,7 +517,7 @@ spx_word32_t cumul_gain { spx_word32_t tmp = ADD32(ADD32(MULT16_16(gain[0],x[2][i]),MULT16_16(gain[1],x[1][i])), MULT16_16(gain[2],x[0][i])); - new_target[i] = SUB16(target[i], EXTRACT16(PSHR32(tmp,6))); + new_target[i] = SUB16(new_target[i], EXTRACT16(PSHR32(tmp,6))); } err = inner_prod(new_target, new_target, nsf); @@ -520,7 +559,8 @@ spx_word32_t *cumul_gain const ltp_params *params; const signed char *gain_cdbk; int gain_cdbk_size; - + int scaledown=0; + VARDECL(int *nbest); params = (const ltp_params*) par; @@ -545,6 +585,25 @@ spx_word32_t *cumul_gain return start; } +#ifdef FIXED_POINT + /* Check if we need to scale everything down in the pitch search to avoid overflows */ + for (i=0;i<nsf;i++) + { + if (ABS16(target[i])>16383) + { + scaledown=1; + break; + } + } + for (i=-end;i<nsf;i++) + { + if (ABS16(exc2[i])>16383) + { + scaledown=1; + break; + } + } +#endif if (N>end-start+1) N=end-start+1; if (end != start) @@ -562,7 +621,7 @@ spx_word32_t *cumul_gain for (j=0;j<nsf;j++) exc[j]=0; err=pitch_gain_search_3tap(target, ak, awk1, awk2, exc, gain_cdbk, gain_cdbk_size, pitch, p, nsf, - bits, stack, exc2, r, new_target, &cdbk_index, plc_tuning, *cumul_gain); + bits, stack, exc2, r, new_target, &cdbk_index, plc_tuning, *cumul_gain, scaledown); if (err<best_err || best_err<0) { for (j=0;j<nsf;j++) @@ -588,7 +647,14 @@ spx_word32_t *cumul_gain exc[i]=best_exc[i]; for (i=0;i<nsf;i++) target[i]=best_target[i]; - +#ifdef FIXED_POINT + /* Scale target back up if needed */ + if (scaledown) + { + for (i=0;i<nsf;i++) + target[i]=SHL16(target[i],1); + } +#endif return pitch; } @@ -717,8 +783,8 @@ spx_word32_t *cumul_gain ) { int i; - VARDECL(spx_sig_t *res); - ALLOC(res, nsf, spx_sig_t); + VARDECL(spx_word16_t *res); + ALLOC(res, nsf, spx_word16_t); #ifdef FIXED_POINT if (pitch_coef>63) pitch_coef=63; @@ -734,9 +800,11 @@ spx_word32_t *cumul_gain { exc[i]=MULT16_32_Q15(SHL16(pitch_coef, 9),exc[i-start]); } - syn_percep_zero(exc, ak, awk1, awk2, res, nsf, p, stack); for (i=0;i<nsf;i++) - target[i]=EXTRACT16(SATURATE(SUB32(EXTEND32(target[i]),PSHR32(res[i],SIG_SHIFT-1)),32700)); + res[i] = EXTRACT16(PSHR32(exc[i], SIG_SHIFT-1)); + syn_percep_zero16(res, ak, awk1, awk2, res, nsf, p, stack); + for (i=0;i<nsf;i++) + target[i]=EXTRACT16(SATURATE(SUB32(EXTEND32(target[i]),EXTEND32(res[i])),32700)); return start; } @@ -770,7 +838,7 @@ int cdbk_offset for (i=0;i<nsf;i++) { exc_out[i]=MULT16_16(exc[i-start],SHL16(pitch_coef,7)); - exc[i] = PSHR(exc_out[i],13); + exc[i] = EXTRACT16(PSHR32(exc_out[i],13)); } *pitch_val = start; gain_val[0]=gain_val[2]=0; diff --git a/libspeex/ltp_arm4.h b/libspeex/ltp_arm4.h index 7479e8b..cdb94e6 100644 --- a/libspeex/ltp_arm4.h +++ b/libspeex/ltp_arm4.h @@ -75,9 +75,10 @@ spx_word32_t inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len) "\tadd %2, %2, %7, asr #5\n" "\tadd %3, %3, %10, asr #5\n" "\tbne .inner_prod_loop%=\n" - : "=r" (deadx), "=r" (deady), "=r" (sum1), "=r" (sum2), "=r" (deadlen), - "=r" (dead1), "=r" (dead2), "=r" (dead3), "=r" (dead4), "=r" (dead5), "=r" (dead6) - : "0" (x), "1" (y), "2" (sum1), "3" (sum2), "4" (len>>3) + : "=r" (deadx), "=r" (deady), "+r" (sum1), "+r" (sum2), + "=r" (deadlen), "=r" (dead1), "=r" (dead2), "=r" (dead3), + "=r" (dead4), "=r" (dead5), "=r" (dead6) + : "0" (x), "1" (y), "4" (len>>3) : "cc" ); return (sum1+sum2)>>1; @@ -169,13 +170,11 @@ void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *c "\tstr %6, %13 \n" "\tstr %7, %14 \n" - : "=r" (y0), "=r" (y1), "=r" (y2), "=r" (y3), + : "+r" (y0), "+r" (y1), "+r" (y2), "+r" (y3), "=r" (part1), "=r" (part2), "=r" (part3), "=r" (part4), - "=r" (x), "=r" (y), "=r" (x0), - "=m" (sum1), "=m" (sum2), "=m" (sum3), "=m" (sum4), "=r" (dead1) - : "0" (y0), "1" (y1), "2" (y2), "3" (y3), - "8" (x), "9" (y), - "11" (sum1), "12" (sum2), "13" (sum3), "14" (sum4) + "+r" (x), "+r" (y), "=r" (x0), "+m" (sum1), + "+m" (sum2), "+m" (sum3), "+m" (sum4), "=r" (dead1) + : : "cc", "memory" ); } diff --git a/libspeex/ltp_bfin.h b/libspeex/ltp_bfin.h index c466902..b530f85 100644 --- a/libspeex/ltp_bfin.h +++ b/libspeex/ltp_bfin.h @@ -330,7 +330,6 @@ static int pitch_gain_search_3tap_vq( " %0 = 0;\n\t" /* %0: best_sum */ " %1 = 0;\n\t" /* %1: best_cbdk */ " P1 = 0;\n\t" /* P1: loop counter */ -" R5 = 64;\n\t" /* R5: pitch_control */ " LSETUP (pgs1, pgs2) LC1 = %4;\n\t" "pgs1: R2 = B [P0++] (X);\n\t" /* R2: g[0] */ @@ -339,6 +338,7 @@ static int pitch_gain_search_3tap_vq( " R2 += 32;\n\t" " R3 += 32;\n\t" " R4 += 32;\n\t" +" R4.H = 64;\n\t" /* R4.H: pitch_control */ " R0 = B [P0++] (X);\n\t" " B0 = R0;\n\t" /* BO: gain_sum */ @@ -349,13 +349,13 @@ static int pitch_gain_search_3tap_vq( " A0 = 0;\n\t" " R0.L = W[I1++];\n\t" -" R1.L = R2.L*R5.L (IS);\n\t" +" R1.L = R2.L*R4.H (IS);\n\t" " A0 += R1.L*R0.L (IS) || R0.L = W[I1++];\n\t" -" R1.L = R3.L*R5.L (IS);\n\t" +" R1.L = R3.L*R4.H (IS);\n\t" " A0 += R1.L*R0.L (IS) || R0.L = W[I1++];\n\t" -" R1.L = R4.L*R5.L (IS);\n\t" +" R1.L = R4.L*R4.H (IS);\n\t" " A0 += R1.L*R0.L (IS) || R0.L = W[I1++];\n\t" " R1.L = R2.L*R3.L (IS);\n\t" @@ -406,7 +406,7 @@ static int pitch_gain_search_3tap_vq( : "=&d" (best_sum), "=&d" (best_cdbk) : "a" (gain_cdbk), "a" (C16), "a" (gain_cdbk_size), "a" (max_gain), "b" (-VERY_LARGE32) - : "R0", "R1", "R2", "R3", "R4", "R5", "P0", + : "R0", "R1", "R2", "R3", "R4", "P0", "P1", "I1", "L1", "A0", "B0" #if (__GNUC__ == 4) , "LC1" diff --git a/libspeex/math_approx.c b/libspeex/math_approx.c index d98e05b..21af766 100644 --- a/libspeex/math_approx.c +++ b/libspeex/math_approx.c @@ -37,67 +37,83 @@ #include "math_approx.h" #include "misc.h" -#ifdef FIXED_POINT - -/* sqrt(x) ~= 0.22178 + 1.29227*x - 0.77070*x^2 + 0.25723*x^3 (for .25 < x < 1) */ -#define C0 3634 -#define C1 21173 -#define C2 -12627 -#define C3 4215 - -spx_word16_t spx_sqrt(spx_word32_t x) +spx_int16_t spx_ilog2(spx_uint32_t x) { - int k=0; - spx_word32_t rt; - - if (x<=0) - return 0; -#if 1 - if (x>=16777216) + int r=0; + if (x>=(spx_int32_t)65536) { - x>>=10; - k+=5; + x >>= 16; + r += 16; } - if (x>=1048576) + if (x>=256) { - x>>=6; - k+=3; + x >>= 8; + r += 8; } - if (x>=262144) + if (x>=16) { - x>>=4; - k+=2; + x >>= 4; + r += 4; } - if (x>=32768) + if (x>=4) { - x>>=2; - k+=1; + x >>= 2; + r += 2; } - if (x>=16384) + if (x>=2) { - x>>=2; - k+=1; + r += 1; } -#else - while (x>=16384) + return r; +} + +spx_int16_t spx_ilog4(spx_uint32_t x) +{ + int r=0; + if (x>=(spx_int32_t)65536) { - x>>=2; - k++; - } -#endif - while (x<4096) + x >>= 16; + r += 8; + } + if (x>=256) { - x<<=2; - k--; + x >>= 8; + r += 4; } + if (x>=16) + { + x >>= 4; + r += 2; + } + if (x>=4) + { + r += 1; + } + return r; +} + +#ifdef FIXED_POINT + +/* sqrt(x) ~= 0.22178 + 1.29227*x - 0.77070*x^2 + 0.25723*x^3 (for .25 < x < 1) */ +/*#define C0 3634 +#define C1 21173 +#define C2 -12627 +#define C3 4215*/ + +/* sqrt(x) ~= 0.22178 + 1.29227*x - 0.77070*x^2 + 0.25659*x^3 (for .25 < x < 1) */ +#define C0 3634 +#define C1 21173 +#define C2 -12627 +#define C3 4204 + +spx_word16_t spx_sqrt(spx_word32_t x) +{ + int k; + spx_word32_t rt; + k = spx_ilog4(x)-6; + x = VSHR32(x, (k<<1)); rt = ADD16(C0, MULT16_16_Q14(x, ADD16(C1, MULT16_16_Q14(x, ADD16(C2, MULT16_16_Q14(x, (C3))))))); - if (rt > 16383) - rt = 16383; - if (k>0) - rt <<= k; - else - rt >>= -k; - rt >>=7; + rt = VSHR32(rt,7-k); return rt; } @@ -151,6 +167,101 @@ spx_word16_t spx_cos(spx_word16_t x) } } +#define L1 32767 +#define L2 -7651 +#define L3 8277 +#define L4 -626 + +static inline spx_word16_t _spx_cos_pi_2(spx_word16_t x) +{ + spx_word16_t x2; + + x2 = MULT16_16_P15(x,x); + return ADD16(1,MIN16(32766,ADD32(SUB16(L1,x2), MULT16_16_P15(x2, ADD32(L2, MULT16_16_P15(x2, ADD32(L3, MULT16_16_P15(L4, x2)))))))); +} + +spx_word16_t spx_cos_norm(spx_word32_t x) +{ + x = x&0x0001ffff; + if (x>SHL32(EXTEND32(1), 16)) + x = SUB32(SHL32(EXTEND32(1), 17),x); + if (x&0x00007fff) + { + if (x<SHL32(EXTEND32(1), 15)) + { + return _spx_cos_pi_2(EXTRACT16(x)); + } else { + return NEG32(_spx_cos_pi_2(EXTRACT16(65536-x))); + } + } else { + if (x&0x0000ffff) + return 0; + else if (x&0x0001ffff) + return -32767; + else + return 32767; + } +} + +/* + K0 = 1 + K1 = log(2) + K2 = 3-4*log(2) + K3 = 3*log(2) - 2 +*/ +#define D0 16384 +#define D1 11356 +#define D2 3726 +#define D3 1301 +/* Input in Q11 format, output in Q16 */ +static spx_word32_t spx_exp2(spx_word16_t x) +{ + int integer; + spx_word16_t frac; + integer = SHR16(x,11); + if (integer>14) + return 0x7fffffff; + else if (integer < -15) + return 0; + frac = SHL16(x-SHL16(integer,11),3); + frac = ADD16(D0, MULT16_16_Q14(frac, ADD16(D1, MULT16_16_Q14(frac, ADD16(D2 , MULT16_16_Q14(D3,frac)))))); + return VSHR32(EXTEND32(frac), -integer-2); +} + +/* Input in Q11 format, output in Q16 */ +spx_word32_t spx_exp(spx_word16_t x) +{ + if (x>21290) + return 0x7fffffff; + else if (x<-21290) + return 0; + else + return spx_exp2(MULT16_16_P14(23637,x)); +} +#define M1 32767 +#define M2 -21 +#define M3 -11943 +#define M4 4936 + +static inline spx_word16_t spx_atan01(spx_word16_t x) +{ + return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x))))))); +} + +/* Input in Q15, output in Q14 */ +spx_word16_t spx_atan(spx_word32_t x) +{ + if (x <= 32767) + { + return SHR16(spx_atan01(x),1); + } else { + int e = spx_ilog2(x); + if (e>=29) + return 25736; + x = DIV32_16(SHL32(EXTEND32(32767),29-e), EXTRACT16(SHR32(x, e-14))); + return SUB16(25736, SHR16(spx_atan01(x),1)); + } +} #else #ifndef M_PI @@ -177,5 +288,4 @@ spx_word16_t spx_cos(spx_word16_t x) } } - #endif diff --git a/libspeex/math_approx.h b/libspeex/math_approx.h index 377bf1a..49cfda6 100644 --- a/libspeex/math_approx.h +++ b/libspeex/math_approx.h @@ -38,13 +38,25 @@ #include "misc.h" spx_word16_t spx_cos(spx_word16_t x); - +spx_int16_t spx_ilog2(spx_uint32_t x); +spx_int16_t spx_ilog4(spx_uint32_t x); #ifdef FIXED_POINT spx_word16_t spx_sqrt(spx_word32_t x); spx_word16_t spx_acos(spx_word16_t x); +spx_word32_t spx_exp(spx_word16_t x); +spx_word16_t spx_cos_norm(spx_word32_t x); + +/* Input in Q15, output in Q14 */ +spx_word16_t spx_atan(spx_word32_t x); + #else + #define spx_sqrt sqrt #define spx_acos acos +#define spx_exp exp +#define spx_cos_norm(x) (cos((.5f*M_PI)*(x))) +#define spx_atan atan + #endif #endif diff --git a/libspeex/mdf.c b/libspeex/mdf.c index 3d79383..014ea25 100644 --- a/libspeex/mdf.c +++ b/libspeex/mdf.c @@ -41,8 +41,8 @@ double-talk is achieved using a variable learning rate as described in: Valin, J.-M., On Adjusting the Learning Rate in Frequency Domain Echo - Cancellation With Double-Talk. To appear in IEEE Transactions on Audio, - Speech and Language Processing, 2006. + Cancellation With Double-Talk. IEEE Transactions on Audio, + Speech and Language Processing, Vol. 15, No. 3, pp. 1030-1034, 2007. http://people.xiph.org/~jm/papers/valin_taslp2006.pdf There is no explicit double-talk detection, but a continuous variation @@ -79,9 +79,6 @@ #define M_PI 3.14159265358979323846 #endif -#define min(a,b) ((a)<(b) ? (a) : (b)) -#define max(a,b) ((a)>(b) ? (a) : (b)) - #ifdef FIXED_POINT #define WEIGHT_SHIFT 11 #define NORMALIZE_SCALEDOWN 5 @@ -93,16 +90,40 @@ /* If enabled, the transition between blocks is smooth, so there isn't any blocking aftifact when adapting. The cost is an extra FFT and a matrix-vector multiply */ #define SMOOTH_BLOCKS +/* If enabled, the AEC will use a foreground filter and a background filter to be more robust to double-talk + and difficult signals in general. The cost is an extra FFT and a matrix-vector multiply */ +#define TWO_PATH #ifdef FIXED_POINT -static const spx_float_t MIN_LEAK = {16777, -19}; +static const spx_float_t MIN_LEAK = {20972, -22}; + +/* Constants for the two-path filter */ +static const spx_float_t VAR1_SMOOTH = {23593, -16}; +static const spx_float_t VAR2_SMOOTH = {23675, -15}; +static const spx_float_t VAR1_UPDATE = {16384, -15}; +static const spx_float_t VAR2_UPDATE = {16384, -16}; +static const spx_float_t VAR_BACKTRACK = {16384, -12}; #define TOP16(x) ((x)>>16) + #else -static const spx_float_t MIN_LEAK = .032f; + +static const spx_float_t MIN_LEAK = .0032f; + +/* Constants for the two-path filter */ +static const spx_float_t VAR1_SMOOTH = .36f; +static const spx_float_t VAR2_SMOOTH = .7225f; +static const spx_float_t VAR1_UPDATE = .5f; +static const spx_float_t VAR2_UPDATE = .25f; +static const spx_float_t VAR_BACKTRACK = 4.f; #define TOP16(x) (x) #endif +#define PLAYBACK_DELAY 2 + +void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len); + + /** Speex echo cancellation state. */ struct SpeexEchoState_ { int frame_size; /**< Number of samples processed each time */ @@ -111,6 +132,7 @@ struct SpeexEchoState_ { int cancel_count; int adapted; int saturated; + int screwed_up; int C; /** Number of input channels (microphones) */ int K; /** Number of output channels (loudspeakers) */ spx_int32_t sampling_rate; @@ -118,30 +140,38 @@ struct SpeexEchoState_ { spx_word16_t beta0; spx_word16_t beta_max; spx_word32_t sum_adapt; - spx_word16_t *e; - spx_word16_t *x; - spx_word16_t *X; - spx_word16_t *d; - spx_word16_t *y; + spx_word16_t leak_estimate; + + spx_word16_t *e; /* scratch */ + spx_word16_t *x; /* Far-end input buffer (2N) */ + spx_word16_t *X; /* Far-end buffer (M+1 frames) in frequency domain */ + spx_word16_t *input; /* scratch */ + spx_word16_t *y; /* scratch */ spx_word16_t *last_y; - spx_word32_t *Yps; - spx_word16_t *Y; + spx_word16_t *Y; /* scratch */ spx_word16_t *E; - spx_word32_t *PHI; - spx_word32_t *W; - spx_word32_t *power; - spx_float_t *power_1; - spx_word16_t *wtmp; + spx_word32_t *PHI; /* scratch */ + spx_word32_t *W; /* (Background) filter weights */ +#ifdef TWO_PATH + spx_word16_t *foreground; /* Foreground filter weights */ + spx_word32_t Davg1; /* 1st recursive average of the residual power difference */ + spx_word32_t Davg2; /* 2nd recursive average of the residual power difference */ + spx_float_t Dvar1; /* Estimated variance of 1st estimator */ + spx_float_t Dvar2; /* Estimated variance of 2nd estimator */ +#endif + spx_word32_t *power; /* Power of the far-end signal */ + spx_float_t *power_1;/* Inverse power of far-end */ + spx_word16_t *wtmp; /* scratch */ #ifdef FIXED_POINT - spx_word16_t *wtmp2; + spx_word16_t *wtmp2; /* scratch */ #endif - spx_word32_t *Rf; - spx_word32_t *Yf; - spx_word32_t *Xf; + spx_word32_t *Rf; /* scratch */ + spx_word32_t *Yf; /* scratch */ + spx_word32_t *Xf; /* scratch */ spx_word32_t *Eh; spx_word32_t *Yh; - spx_float_t Pey; - spx_float_t Pyy; + spx_float_t Pey; + spx_float_t Pyy; spx_word16_t *window; spx_word16_t *prop; void *fft_table; @@ -153,6 +183,7 @@ struct SpeexEchoState_ { /* NOTE: If you only use speex_echo_cancel() and want to save some memory, remove this */ spx_int16_t *play_buf; int play_buf_pos; + int play_buf_started; }; static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius, spx_word16_t *out, int len, spx_mem_t *mem, int stride) @@ -179,6 +210,7 @@ static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius, } } +/* This inner product is slightly different from the codec version because of fixed-point */ static inline spx_word32_t mdf_inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len) { spx_word32_t sum=0; @@ -247,6 +279,34 @@ static inline void spectral_mul_accum(const spx_word16_t *X, const spx_word32_t } acc[N-1] = PSHR32(tmp1,WEIGHT_SHIFT); } +static inline void spectral_mul_accum16(const spx_word16_t *X, const spx_word16_t *Y, spx_word16_t *acc, int N, int M) +{ + int i,j; + spx_word32_t tmp1=0,tmp2=0; + for (j=0;j<M;j++) + { + tmp1 = MAC16_16(tmp1, X[j*N],Y[j*N]); + } + acc[0] = PSHR32(tmp1,WEIGHT_SHIFT); + for (i=1;i<N-1;i+=2) + { + tmp1 = tmp2 = 0; + for (j=0;j<M;j++) + { + tmp1 = SUB32(MAC16_16(tmp1, X[j*N+i],Y[j*N+i]), MULT16_16(X[j*N+i+1],Y[j*N+i+1])); + tmp2 = MAC16_16(MAC16_16(tmp2, X[j*N+i+1],Y[j*N+i]), X[j*N+i], Y[j*N+i+1]); + } + acc[i] = PSHR32(tmp1,WEIGHT_SHIFT); + acc[i+1] = PSHR32(tmp2,WEIGHT_SHIFT); + } + tmp1 = tmp2 = 0; + for (j=0;j<M;j++) + { + tmp1 = MAC16_16(tmp1, X[(j+1)*N-1],Y[(j+1)*N-1]); + } + acc[N-1] = PSHR32(tmp1,WEIGHT_SHIFT); +} + #else static inline void spectral_mul_accum(const spx_word16_t *X, const spx_word32_t *Y, spx_word16_t *acc, int N, int M) { @@ -266,21 +326,73 @@ static inline void spectral_mul_accum(const spx_word16_t *X, const spx_word32_t Y += N; } } +#define spectral_mul_accum16 spectral_mul_accum #endif /** Compute weighted cross-power spectrum of a half-complex (packed) vector with conjugate */ -static inline void weighted_spectral_mul_conj(const spx_float_t *w, const spx_word16_t *X, const spx_word16_t *Y, spx_word32_t *prod, int N) +static inline void weighted_spectral_mul_conj(const spx_float_t *w, const spx_float_t p, const spx_word16_t *X, const spx_word16_t *Y, spx_word32_t *prod, int N) { int i, j; - prod[0] = FLOAT_MUL32(w[0],MULT16_16(X[0],Y[0])); + spx_float_t W; + W = FLOAT_AMULT(p, w[0]); + prod[0] = FLOAT_MUL32(W,MULT16_16(X[0],Y[0])); for (i=1,j=1;i<N-1;i+=2,j++) { - prod[i] = FLOAT_MUL32(w[j],MAC16_16(MULT16_16(X[i],Y[i]), X[i+1],Y[i+1])); - prod[i+1] = FLOAT_MUL32(w[j],MAC16_16(MULT16_16(-X[i+1],Y[i]), X[i],Y[i+1])); + W = FLOAT_AMULT(p, w[j]); + prod[i] = FLOAT_MUL32(W,MAC16_16(MULT16_16(X[i],Y[i]), X[i+1],Y[i+1])); + prod[i+1] = FLOAT_MUL32(W,MAC16_16(MULT16_16(-X[i+1],Y[i]), X[i],Y[i+1])); + } + W = FLOAT_AMULT(p, w[j]); + prod[i] = FLOAT_MUL32(W,MULT16_16(X[i],Y[i])); +} + +static inline void mdf_adjust_prop(const spx_word32_t *W, int N, int M, int P, spx_word16_t *prop) +{ + int i, j, p; + spx_word16_t max_sum = 1; + spx_word32_t prop_sum = 1; + for (i=0;i<M;i++) + { + spx_word32_t tmp = 1; + for (p=0;p<P;p++) + for (j=0;j<N;j++) + tmp += MULT16_16(EXTRACT16(SHR32(W[p*N*M + i*N+j],18)), EXTRACT16(SHR32(W[p*N*M + i*N+j],18))); +#ifdef FIXED_POINT + /* Just a security in case an overflow were to occur */ + tmp = MIN32(ABS32(tmp), 536870912); +#endif + prop[i] = spx_sqrt(tmp); + if (prop[i] > max_sum) + max_sum = prop[i]; + } + for (i=0;i<M;i++) + { + prop[i] += MULT16_16_Q15(QCONST16(.03f,15),max_sum); + prop_sum += EXTEND32(prop[i]); + } + for (i=0;i<M;i++) + { + prop[i] = DIV32(MULT16_16(QCONST16(.99f,15), prop[i]),prop_sum); + /*printf ("%f ", prop[i]);*/ } - prod[i] = FLOAT_MUL32(w[j],MULT16_16(X[i],Y[i])); + /*printf ("\n");*/ } +#ifdef DUMP_ECHO_CANCEL_DATA +#include <stdio.h> +static FILE *rFile=NULL, *pFile=NULL, *oFile=NULL; + +static void dump_audio(const spx_int16_t *rec, const spx_int16_t *play, const spx_int16_t *out, int len) +{ + if (!(rFile && pFile && oFile)) + { + speex_error("Dump files not open"); + } + fwrite(rec, sizeof(spx_int16_t), len, rFile); + fwrite(play, sizeof(spx_int16_t), len, pFile); + fwrite(out, sizeof(spx_int16_t), len, oFile); +} +#endif /** Creates a new echo canceller state */ SpeexEchoState *mc_echo_state_init(int frame_size, int filter_length, int nb_mic, int nb_speakers) @@ -292,6 +404,14 @@ SpeexEchoState *mc_echo_state_init(int frame_size, int filter_length, int nb_mic st->C = nb_mic; C=st->C; K=st->K; +#ifdef DUMP_ECHO_CANCEL_DATA + if (rFile || pFile || oFile) + speex_error("Opening dump files twice"); + rFile = fopen("aec_rec.sw", "w"); + pFile = fopen("aec_play.sw", "w"); + oFile = fopen("aec_out.sw", "w"); +#endif + st->frame_size = frame_size; st->window_size = 2*frame_size; N = st->window_size; @@ -299,7 +419,8 @@ SpeexEchoState *mc_echo_state_init(int frame_size, int filter_length, int nb_mic st->cancel_count=0; st->sum_adapt = 0; st->saturated = 0; - /* FIXME: Make that an init option (new API call?) */ + st->screwed_up = 0; + /* This is the default sampling rate */ st->sampling_rate = 8000; st->spec_average = DIV32_16(SHL32(EXTEND32(st->frame_size), 15), st->sampling_rate); #ifdef FIXED_POINT @@ -309,14 +430,14 @@ SpeexEchoState *mc_echo_state_init(int frame_size, int filter_length, int nb_mic st->beta0 = (2.0f*st->frame_size)/st->sampling_rate; st->beta_max = (.5f*st->frame_size)/st->sampling_rate; #endif + st->leak_estimate = 0; st->fft_table = spx_fft_init(N); st->e = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); st->x = (spx_word16_t*)speex_alloc(K*N*sizeof(spx_word16_t)); - st->d = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); + st->input = (spx_word16_t*)speex_alloc(C*st->frame_size*sizeof(spx_word16_t)); st->y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); - st->Yps = (spx_word32_t*)speex_alloc(C*N*sizeof(spx_word32_t)); st->last_y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); st->Yf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); st->Rf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); @@ -328,6 +449,9 @@ SpeexEchoState *mc_echo_state_init(int frame_size, int filter_length, int nb_mic st->Y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); st->E = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); st->W = (spx_word32_t*)speex_alloc(C*K*M*N*sizeof(spx_word32_t)); +#ifdef TWO_PATH + st->foreground = (spx_word16_t*)speex_alloc(M*N*C*K*sizeof(spx_word16_t)); +#endif st->PHI = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); st->power = (spx_word32_t*)speex_alloc((frame_size+1)*sizeof(spx_word32_t)); st->power_1 = (spx_float_t*)speex_alloc((frame_size+1)*sizeof(spx_float_t)); @@ -349,12 +473,10 @@ SpeexEchoState *mc_echo_state_init(int frame_size, int filter_length, int nb_mic st->power_1[i] = FLOAT_ONE; for (i=0;i<N*M*K*C;i++) st->W[i] = 0; - for (i=0;i<N;i++) - st->PHI[i] = 0; { spx_word32_t sum = 0; /* Ratio of ~10 between adaptation rate of first and last block */ - spx_word16_t decay = QCONST16(exp(-2.4/M),15); + spx_word16_t decay = SHR32(spx_exp(NEG16(DIV32_16(QCONST16(2.4,11),M))),1); st->prop[0] = QCONST16(.7, 15); sum = EXTEND32(st->prop[0]); for (i=1;i<M;i++) @@ -364,7 +486,7 @@ SpeexEchoState *mc_echo_state_init(int frame_size, int filter_length, int nb_mic } for (i=M-1;i>=0;i--) { - st->prop[i] = DIV32(SHL32(EXTEND32(st->prop[i]),15),sum); + st->prop[i] = DIV32(MULT16_16(QCONST16(.99f,15), st->prop[i]),sum); } } @@ -383,9 +505,15 @@ SpeexEchoState *mc_echo_state_init(int frame_size, int filter_length, int nb_mic st->adapted = 0; st->Pey = st->Pyy = FLOAT_ONE; - st->play_buf = (spx_int16_t*)speex_alloc(K*2*st->frame_size*sizeof(spx_int16_t)); - st->play_buf_pos = 0; - +#ifdef TWO_PATH + st->Davg1 = st->Davg2 = 0; + st->Dvar1 = st->Dvar2 = FLOAT_ZERO; +#endif + + st->play_buf = (spx_int16_t*)speex_alloc(K*(PLAYBACK_DELAY+1)*st->frame_size*sizeof(spx_int16_t)); + st->play_buf_pos = PLAYBACK_DELAY*st->frame_size; + st->play_buf_started = 0; + return st; } @@ -394,26 +522,57 @@ void speex_echo_state_reset(SpeexEchoState *st) { int i, M, N, C, K; st->cancel_count=0; + st->screwed_up = 0; N = st->window_size; M = st->M; C=st->C; K=st->K; for (i=0;i<N*M;i++) st->W[i] = 0; +#ifdef TWO_PATH + for (i=0;i<N*M;i++) + st->foreground[i] = 0; +#endif for (i=0;i<N*(M+1);i++) st->X[i] = 0; for (i=0;i<=st->frame_size;i++) + { st->power[i] = 0; - for (i=0;i<N;i++) + st->power_1[i] = FLOAT_ONE; + st->Eh[i] = 0; + st->Yh[i] = 0; + } + for (i=0;i<st->frame_size;i++) + { + st->last_y[i] = 0; + } + for (i=0;i<N*C;i++) + { st->E[i] = 0; + } + for (i=0;i<N*K;i++) + { + st->x[i] = 0; + } for (i=0;i<2*C;i++) st->notch_mem[i] = 0; - + for (i=0;i<C;i++) + st->memD[i]=st->memE[i]=0; + for (i=0;i<K;i++) + st->memX[i]=0; + st->saturated = 0; st->adapted = 0; st->sum_adapt = 0; st->Pey = st->Pyy = FLOAT_ONE; - st->play_buf_pos = 0; +#ifdef TWO_PATH + st->Davg1 = st->Davg2 = 0; + st->Dvar1 = st->Dvar2 = FLOAT_ZERO; +#endif + for (i=0;i<3*st->frame_size;i++) + st->play_buf[i] = 0; + st->play_buf_pos = PLAYBACK_DELAY*st->frame_size; + st->play_buf_started = 0; } @@ -424,10 +583,9 @@ void mc_echo_state_destroy(SpeexEchoState *st) speex_free(st->e); speex_free(st->x); - speex_free(st->d); + speex_free(st->input); speex_free(st->y); speex_free(st->last_y); - speex_free(st->Yps); speex_free(st->Yf); speex_free(st->Rf); speex_free(st->Xf); @@ -438,6 +596,9 @@ void mc_echo_state_destroy(SpeexEchoState *st) speex_free(st->Y); speex_free(st->E); speex_free(st->W); +#ifdef TWO_PATH + speex_free(st->foreground); +#endif speex_free(st->PHI); speex_free(st->power); speex_free(st->power_1); @@ -449,19 +610,29 @@ void mc_echo_state_destroy(SpeexEchoState *st) #endif speex_free(st->play_buf); speex_free(st); + +#ifdef DUMP_ECHO_CANCEL_DATA + fclose(rFile); + fclose(pFile); + fclose(oFile); + rFile = pFile = oFile = NULL; +#endif } -void mc_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out, spx_int32_t *Yout) + +void mc_echo_capture2(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out) { int i; + /*speex_warning_int("capture with fill level ", st->play_buf_pos/st->frame_size);*/ + st->play_buf_started = 1; if (st->play_buf_pos>=st->frame_size) { - mc_echo_cancel(st, rec, st->play_buf, out, Yout); + mc_echo_cancellation(st, rec, st->play_buf, out); st->play_buf_pos -= st->frame_size; - for (i=0;i<st->frame_size;i++) + for (i=0;i<st->play_buf_pos;i++) st->play_buf[i] = st->play_buf[i+st->frame_size]; } else { - speex_warning("no playback frame available"); + speex_warning("No playback frame available (your application is buggy and/or got xruns)"); if (st->play_buf_pos!=0) { speex_warning("internal playback buffer corruption?"); @@ -474,23 +645,47 @@ void mc_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *ou void mc_echo_playback(SpeexEchoState *st, const spx_int16_t *play) { - if (st->play_buf_pos<=st->frame_size) + /*speex_warning_int("playback with fill level ", st->play_buf_pos/st->frame_size);*/ + if (!st->play_buf_started) + { + speex_warning("discarded first playback frame"); + return; + } + if (st->play_buf_pos<=PLAYBACK_DELAY*st->frame_size) { int i; for (i=0;i<st->frame_size;i++) st->play_buf[st->play_buf_pos+i] = play[i]; st->play_buf_pos += st->frame_size; + if (st->play_buf_pos <= (PLAYBACK_DELAY-1)*st->frame_size) + { + speex_warning("Auto-filling the buffer (your application is buggy and/or got xruns)"); + for (i=0;i<st->frame_size;i++) + st->play_buf[st->play_buf_pos+i] = play[i]; + st->play_buf_pos += st->frame_size; + } } else { - speex_warning("had to discard a playback frame"); + speex_warning("Had to discard a playback frame (your application is buggy and/or got xruns)"); } } /** Performs echo cancellation on a frame */ -void mc_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int16_t *echo, spx_int16_t *out, spx_int32_t *Yout) +void mc_echo_cancel(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out, spx_int32_t *Yout) +{ + mc_echo_cancellation(st, in, far_end, out); +} + +/** Performs echo cancellation on a frame (deprecated, last arg now ignored) */ +void mc_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out) { int i,j, chan, speak; int N,M, C, K; - spx_word16_t leak_estimate; + spx_word32_t Syy,See,Sxx,Sdd, Sff; +#ifdef TWO_PATH + spx_word32_t Dbf; + int update_foreground; +#endif + spx_word32_t Sey; spx_word16_t ss, ss_1; spx_float_t Pey = FLOAT_ONE, Pyy=FLOAT_ONE; spx_float_t alpha, alpha_1; @@ -501,7 +696,6 @@ void mc_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int16_ M = st->M; C = st->C; K = st->K; - spx_word32_t Syy=0,See=0,Sxx=0; st->cancel_count++; #ifdef FIXED_POINT @@ -514,29 +708,31 @@ void mc_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int16_ for (chan = 0; chan < C; chan++) { - filter_dc_notch16(ref+chan, st->notch_radius, st->d+chan*N, st->frame_size, st->notch_mem+2*chan, C); + /* Apply a notch filter to make sure DC doesn't end up causing problems */ + filter_dc_notch16(in+chan, st->notch_radius, st->input+chan*st->frame_size, st->frame_size, st->notch_mem+2*chan, C); + /* Copy input data to buffer and apply pre-emphasis */ /* Copy input data to buffer */ for (i=0;i<st->frame_size;i++) { - spx_word16_t tmp; spx_word32_t tmp32; - tmp = st->d[chan*N+i]; - st->d[chan*N+i] = st->d[chan*N+i+st->frame_size]; - tmp32 = SUB32(EXTEND32(tmp), EXTEND32(MULT16_16_P15(st->preemph, st->memD[chan]))); + /* FIXME: This core has changed a bit, need to merge properly */ + tmp32 = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(MULT16_16_P15(st->preemph, st->memD[chan]))); #ifdef FIXED_POINT if (tmp32 > 32767) { tmp32 = 32767; - st->saturated = 1; + if (st->saturated == 0) + st->saturated = 1; } if (tmp32 < -32767) { tmp32 = -32767; - st->saturated = 1; + if (st->saturated == 0) + st->saturated = 1; } #endif - st->d[chan*N+i+st->frame_size] = tmp32; - st->memD[chan] = tmp; + st->memD[chan] = st->input[chan*st->frame_size+i]; + st->input[chan*st->frame_size+i] = EXTRACT16(tmp32); } } @@ -544,25 +740,24 @@ void mc_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int16_ { for (i=0;i<st->frame_size;i++) { - spx_word16_t tmp; spx_word32_t tmp32; st->x[speak*N+i] = st->x[speak*N+i+st->frame_size]; - tmp32 = SUB32(EXTEND32(echo[i*K+speak]), EXTEND32(MULT16_16_P15(st->preemph, st->memX[speak]))); + tmp32 = SUB32(EXTEND32(far_end[i*K+speak]), EXTEND32(MULT16_16_P15(st->preemph, st->memX[speak]))); #ifdef FIXED_POINT /*FIXME: If saturation occurs here, we need to freeze adaptation for M frames (not just one) */ if (tmp32 > 32767) { tmp32 = 32767; - st->saturated = 1; + st->saturated = M+1; } if (tmp32 < -32767) { tmp32 = -32767; - st->saturated = 1; + st->saturated = M+1; } #endif st->x[speak*N+i+st->frame_size] = EXTRACT16(tmp32); - st->memX[speak] = echo[i*K+speak]; + st->memX[speak] = far_end[i*K+speak]; } } @@ -578,16 +773,32 @@ void mc_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int16_ spx_fft(st->fft_table, st->x+speak*N, &st->X[speak*N]); } + Sxx = 0; + for (speak = 0; speak < K; speak++) + { + Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size); + power_spectrum_accum(st->X+speak*N, st->Xf, N); + } + + Sff = 0; for (chan = 0; chan < C; chan++) { -#ifdef SMOOTH_BLOCKS - spectral_mul_accum(st->X, st->W+chan*N*K*M, st->Y+chan*N, N, M*K); +#ifdef TWO_PATH + /* Compute foreground filter */ + spectral_mul_accum16(st->X, st->foreground+chan*N*K*M, st->Y+chan*N, N, M*K); spx_ifft(st->fft_table, st->Y+chan*N, st->e+chan*N); + for (i=0;i<st->frame_size;i++) + st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->e[chan*N+i+st->frame_size]); + Sff += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size); #endif } + /* Adjust proportional adaption rate */ + /* FIXME: Adjust that for C, K*/ + if (st->adapted) + mdf_adjust_prop (st->W, N, M, C*K, st->prop); /* Compute weight gradient */ - if (!st->saturated) + if (st->saturated == 0) { for (chan = 0; chan < C; chan++) { @@ -595,16 +806,16 @@ void mc_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int16_ { for (j=M-1;j>=0;j--) { - weighted_spectral_mul_conj(st->power_1, &st->X[(j+1)*N*K+speak*N], st->E+chan*N, st->PHI, N); + weighted_spectral_mul_conj(st->power_1, FLOAT_SHL(PSEUDOFLOAT(st->prop[j]),-15), &st->X[(j+1)*N*K+speak*N], st->E+chan*N, st->PHI, N); for (i=0;i<N;i++) - st->W[chan*N*K*M + j*N*K + speak*N + i] += MULT16_32_Q15(st->prop[j], st->PHI[i]); + st->W[chan*N*K*M + j*N*K + speak*N + i] += st->PHI[i]; } } - } + } + } else { + st->saturated--; } - st->saturated = 0; - /* FIXME: MC conversion required */ /* Update weight to prevent circular convolution (MDF / AUMDF) */ for (chan = 0; chan < C; chan++) @@ -649,52 +860,141 @@ void mc_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int16_ /* So we can use power_spectrum_accum */ for (i=0;i<=st->frame_size;i++) st->Rf[i] = st->Yf[i] = st->Xf[i] = 0; - + + Dbf = 0; + See = 0; +#ifdef TWO_PATH + /* Difference in response, this is used to estimate the variance of our residual power estimate */ for (chan = 0; chan < C; chan++) { - /* Compute filter response Y */ spectral_mul_accum(st->X, st->W+chan*N*K*M, st->Y+chan*N, N, M*K); spx_ifft(st->fft_table, st->Y+chan*N, st->y+chan*N); + for (i=0;i<st->frame_size;i++) + st->e[chan*N+i] = SUB16(st->e[chan*N+i+st->frame_size], st->y[chan*N+i+st->frame_size]); + Dbf += 10+mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size); + for (i=0;i<st->frame_size;i++) + st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->y[chan*N+i+st->frame_size]); + See += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size); + } +#endif + +#ifndef TWO_PATH + Sff = See; +#endif +#ifdef TWO_PATH + /* Logic for updating the foreground filter */ + + /* For two time windows, compute the mean of the energy difference, as well as the variance */ + st->Davg1 = ADD32(MULT16_32_Q15(QCONST16(.6f,15),st->Davg1), MULT16_32_Q15(QCONST16(.4f,15),SUB32(Sff,See))); + st->Davg2 = ADD32(MULT16_32_Q15(QCONST16(.85f,15),st->Davg2), MULT16_32_Q15(QCONST16(.15f,15),SUB32(Sff,See))); + st->Dvar1 = FLOAT_ADD(FLOAT_MULT(VAR1_SMOOTH, st->Dvar1), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.4f,15),Sff), MULT16_32_Q15(QCONST16(.4f,15),Dbf))); + st->Dvar2 = FLOAT_ADD(FLOAT_MULT(VAR2_SMOOTH, st->Dvar2), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.15f,15),Sff), MULT16_32_Q15(QCONST16(.15f,15),Dbf))); + + /* Equivalent float code: + st->Davg1 = .6*st->Davg1 + .4*(Sff-See); + st->Davg2 = .85*st->Davg2 + .15*(Sff-See); + st->Dvar1 = .36*st->Dvar1 + .16*Sff*Dbf; + st->Dvar2 = .7225*st->Dvar2 + .0225*Sff*Dbf; + */ + + update_foreground = 0; + /* Check if we have a statistically significant reduction in the residual echo */ + /* Note that this is *not* Gaussian, so we need to be careful about the longer tail */ + if (FLOAT_GT(FLOAT_MUL32U(SUB32(Sff,See),ABS32(SUB32(Sff,See))), FLOAT_MUL32U(Sff,Dbf))) + update_foreground = 1; + else if (FLOAT_GT(FLOAT_MUL32U(st->Davg1, ABS32(st->Davg1)), FLOAT_MULT(VAR1_UPDATE,(st->Dvar1)))) + update_foreground = 1; + else if (FLOAT_GT(FLOAT_MUL32U(st->Davg2, ABS32(st->Davg2)), FLOAT_MULT(VAR2_UPDATE,(st->Dvar2)))) + update_foreground = 1; + /* Do we update? */ + if (update_foreground) + { + st->Davg1 = st->Davg2 = 0; + st->Dvar1 = st->Dvar2 = FLOAT_ZERO; + /* Copy background filter to foreground filter */ + for (i=0;i<N*M*C*K;i++) + st->foreground[i] = EXTRACT16(PSHR32(st->W[i],16)); + /* Apply a smooth transition so as to not introduce blocking artifacts */ + for (chan = 0; chan < C; chan++) + for (i=0;i<st->frame_size;i++) + st->e[chan*N+i+st->frame_size] = MULT16_16_Q15(st->window[i+st->frame_size],st->e[chan*N+i+st->frame_size]) + MULT16_16_Q15(st->window[i],st->y[chan*N+i+st->frame_size]); + } else { + int reset_background=0; + /* Otherwise, check if the background filter is significantly worse */ + if (FLOAT_GT(FLOAT_MUL32U(NEG32(SUB32(Sff,See)),ABS32(SUB32(Sff,See))), FLOAT_MULT(VAR_BACKTRACK,FLOAT_MUL32U(Sff,Dbf)))) + reset_background = 1; + if (FLOAT_GT(FLOAT_MUL32U(NEG32(st->Davg1), ABS32(st->Davg1)), FLOAT_MULT(VAR_BACKTRACK,st->Dvar1))) + reset_background = 1; + if (FLOAT_GT(FLOAT_MUL32U(NEG32(st->Davg2), ABS32(st->Davg2)), FLOAT_MULT(VAR_BACKTRACK,st->Dvar2))) + reset_background = 1; + if (reset_background) + { + /* Copy foreground filter to background filter */ + for (i=0;i<N*M*C*K;i++) + st->W[i] = SHL32(EXTEND32(st->foreground[i]),16); + /* We also need to copy the output so as to get correct adaptation */ + for (chan = 0; chan < C; chan++) + { + for (i=0;i<st->frame_size;i++) + st->y[chan*N+i+st->frame_size] = st->e[chan*N+i+st->frame_size]; + for (i=0;i<st->frame_size;i++) + st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->y[chan*N+i+st->frame_size]); + } + See = Sff; + st->Davg1 = st->Davg2 = 0; + st->Dvar1 = st->Dvar2 = FLOAT_ZERO; + } + } +#endif + + Sey = Syy = Sdd = 0; + for (chan = 0; chan < C; chan++) + { /* Compute error signal (for the output with de-emphasis) */ for (i=0;i<st->frame_size;i++) { spx_word32_t tmp_out; -#ifdef SMOOTH_BLOCKS - spx_word16_t y = MULT16_16_Q15(st->window[i+st->frame_size],st->e[chan*N+i+st->frame_size]) + MULT16_16_Q15(st->window[i],st->y[chan*N+i+st->frame_size]); - tmp_out = SUB32(EXTEND32(st->d[chan*N+i+st->frame_size]), EXTEND32(y)); +#ifdef TWO_PATH + tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->e[chan*N+i+st->frame_size])); #else - tmp_out = SUB32(EXTEND32(st->d[chan*N+i+st->frame_size]), EXTEND32(st->y[chan*N+i+st->frame_size])); + tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->y[chan*N+i+st->frame_size])); #endif - /* Saturation */ if (tmp_out>32767) tmp_out = 32767; else if (tmp_out<-32768) tmp_out = -32768; tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE[chan]))); - /* This is an arbitrary test for saturation */ - if (ref[i*C+chan] <= -32000 || ref[i*C+chan] >= 32000) + /* This is an arbitrary test for saturation in the microphone signal */ + if (in[i*C+chan] <= -32000 || in[i*C+chan] >= 32000) { tmp_out = 0; + if (st->saturated == 0) st->saturated = 1; } out[i*C+chan] = (spx_int16_t)tmp_out; st->memE[chan] = tmp_out; } - + +#ifdef DUMP_ECHO_CANCEL_DATA + dump_audio(in, far_end, out, st->frame_size); +#endif + /* Compute error signal (filter update version) */ for (i=0;i<st->frame_size;i++) { + st->e[chan*N+i+st->frame_size] = st->e[chan*N+i]; st->e[chan*N+i] = 0; - st->e[chan*N+i+st->frame_size] = st->d[chan*N+i+st->frame_size] - st->y[chan*N+i+st->frame_size]; } /* Compute a bunch of correlations */ - See += mdf_inner_prod(st->e+chan*N+st->frame_size, st->e+chan*N+st->frame_size, st->frame_size); + /* FIXME: bad merge */ + Sey += mdf_inner_prod(st->e+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size); Syy += mdf_inner_prod(st->y+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size); - + Sdd += mdf_inner_prod(st->input+chan*st->frame_size, st->input+chan*st->frame_size, st->frame_size); + /* Convert error to frequency domain */ spx_fft(st->fft_table, st->e+chan*N, st->E+chan*N); for (i=0;i<st->frame_size;i++) @@ -704,16 +1004,48 @@ void mc_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int16_ /* Compute power spectrum of echo (X), error (E) and filter response (Y) */ power_spectrum_accum(st->E+chan*N, st->Rf, N); power_spectrum_accum(st->Y+chan*N, st->Yf, N); + } - See = ADD32(See, SHR32(EXTEND32(10000),6)); + /*printf ("%f %f %f %f\n", Sff, See, Syy, Sdd, st->update_cond);*/ + + /* Do some sanity check */ + if (!(Syy>=0 && Sxx>=0 && See >= 0) +#ifndef FIXED_POINT + || !(Sff < N*1e9 && Syy < N*1e9 && Sxx < N*1e9) +#endif + ) + { + /* Things have gone really bad */ + st->screwed_up += 50; + for (i=0;i<st->frame_size*C;i++) + out[i] = 0; + } else if (SHR32(Sff, 2) > ADD32(Sdd, SHR32(MULT16_16(N, 10000),6))) + { + /* AEC seems to add lots of echo instead of removing it, let's see if it will improve */ + st->screwed_up++; + } else { + /* Everything's fine */ + st->screwed_up=0; + } + if (st->screwed_up>=50) + { + speex_warning("The echo canceller started acting funny and got slapped (reset). It swears it will behave now."); + speex_echo_state_reset(st); + return; + } + + /* Add a small noise floor to make sure not to have problems when dividing */ + See = MAX32(See, SHR32(MULT16_16(N, 100),6)); + for (speak = 0; speak < K; speak++) { Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size); power_spectrum_accum(st->X+speak*N, st->Xf, N); } + - /* Smooth echo energy estimate over time */ + /* Smooth far end energy estimate over time */ for (j=0;j<=st->frame_size;j++) st->power[j] = MULT16_32_Q15(ss_1,st->power[j]) + 1 + MULT16_32_Q15(ss,st->Xf[j]); @@ -754,40 +1086,53 @@ void mc_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int16_ if (FLOAT_GT(st->Pey, st->Pyy)) st->Pey = st->Pyy; /* leak_estimate is the linear regression result */ - leak_estimate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIVU(st->Pey, st->Pyy),14)); + st->leak_estimate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIVU(st->Pey, st->Pyy),14)); /* This looks like a stupid bug, but it's right (because we convert from Q14 to Q15) */ - if (leak_estimate > 16383) - leak_estimate = 32767; + if (st->leak_estimate > 16383) + st->leak_estimate = 32767; else - leak_estimate = SHL16(leak_estimate,1); - /*printf ("%f\n", leak_estimate);*/ + st->leak_estimate = SHL16(st->leak_estimate,1); + /*printf ("%f\n", st->leak_estimate);*/ /* Compute Residual to Error Ratio */ #ifdef FIXED_POINT - tmp32 = MULT16_32_Q15(leak_estimate,Syy); - tmp32 = ADD32(tmp32, SHL32(tmp32,1)); + tmp32 = MULT16_32_Q15(st->leak_estimate,Syy); + tmp32 = ADD32(SHR32(Sxx,13), ADD32(tmp32, SHL32(tmp32,1))); + /* Check for y in e (lower bound on RER) */ + { + spx_float_t bound = PSEUDOFLOAT(Sey); + bound = FLOAT_DIVU(FLOAT_MULT(bound, bound), PSEUDOFLOAT(ADD32(1,Syy))); + if (FLOAT_GT(bound, PSEUDOFLOAT(See))) + tmp32 = See; + else if (tmp32 < FLOAT_EXTRACT32(bound)) + tmp32 = FLOAT_EXTRACT32(bound); + } if (tmp32 > SHR32(See,1)) tmp32 = SHR32(See,1); RER = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32,See),15)); -#else - RER = (.0001*Sxx + 3.*MULT16_32_Q15(leak_estimate,Syy)) / See; +#else + RER = (.0001*Sxx + 3.*MULT16_32_Q15(st->leak_estimate,Syy)) / See; + /* Check for y in e (lower bound on RER) */ + if (RER < Sey*Sey/(1+See*Syy)) + RER = Sey*Sey/(1+See*Syy); if (RER > .5) RER = .5; #endif /* We consider that the filter has had minimal adaptation if the following is true*/ - if (!st->adapted && st->sum_adapt > QCONST32(1,15)) + if (!st->adapted && st->sum_adapt > QCONST32(M,15) && MULT16_32_Q15(st->leak_estimate,Syy) > MULT16_32_Q15(QCONST16(.03f,15),Syy)) { st->adapted = 1; } if (st->adapted) { + /* Normal learning rate calculation once we're past the minimal adaptation phase */ for (i=0;i<=st->frame_size;i++) { spx_word32_t r, e; /* Compute frequency-domain adaptation mask */ - r = MULT16_32_Q15(leak_estimate,SHL32(st->Yf[i],3)); + r = MULT16_32_Q15(st->leak_estimate,SHL32(st->Yf[i],3)); e = SHL32(st->Rf[i],3)+1; #ifdef FIXED_POINT if (r>SHR32(e,1)) @@ -804,16 +1149,18 @@ void mc_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int16_ /* Temporary adaption rate if filter is not yet adapted enough */ spx_word16_t adapt_rate=0; - tmp32 = MULT16_32_Q15(QCONST16(.15f, 15), Sxx); + if (Sxx > SHR32(MULT16_16(N, 1000),6)) + { + tmp32 = MULT16_32_Q15(QCONST16(.25f, 15), Sxx); #ifdef FIXED_POINT - if (Sxx > SHR32(See,2)) - Sxx = SHR32(See,2); + if (tmp32 > SHR32(See,2)) + tmp32 = SHR32(See,2); #else - if (Sxx > .25*See) - Sxx = .25*See; + if (tmp32 > .25*See) + tmp32 = .25*See; #endif - adapt_rate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(Sxx, See),15)); - + adapt_rate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32, See),15)); + } for (i=0;i<=st->frame_size;i++) st->power_1[i] = FLOAT_SHL(FLOAT_DIV32(EXTEND32(adapt_rate),ADD32(st->power[i],10)),WEIGHT_SHIFT+1); @@ -823,49 +1170,55 @@ void mc_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int16_ } /* FIXME: MC conversion required */ - /* Compute spectrum of estimated echo for use in an echo post-filter (if necessary)*/ - if (Yout) - { - spx_word16_t leak2; for (i=0;i<st->frame_size;i++) st->last_y[i] = st->last_y[st->frame_size+i]; - if (st->adapted) - { - /* If the filter is adapted, take the filtered echo */ - for (i=0;i<st->frame_size;i++) - st->last_y[st->frame_size+i] = ref[i]-out[i]; - } else { - /* If filter isn't adapted yet, all we can do is take the echo signal directly */ - for (i=0;i<st->frame_size;i++) - st->last_y[st->frame_size+i] = echo[i]; - } - - /* Apply hanning window (should pre-compute it)*/ - for (i=0;i<N;i++) - st->y[i] = MULT16_16_Q15(st->window[i],st->last_y[i]); + if (st->adapted) + { + /* If the filter is adapted, take the filtered echo */ + for (i=0;i<st->frame_size;i++) + st->last_y[st->frame_size+i] = in[i]-out[i]; + } else { + /* If filter isn't adapted yet, all we can do is take the far end signal directly */ + /* moved earlier: for (i=0;i<N;i++) + st->last_y[i] = st->x[i];*/ + } + +} + +/* Compute spectrum of estimated echo for use in an echo post-filter */ +void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *residual_echo, int len) +{ + int i; + spx_word16_t leak2; + int N; + + N = st->window_size; + + /* Apply hanning window (should pre-compute it)*/ + for (i=0;i<N;i++) + st->y[i] = MULT16_16_Q15(st->window[i],st->last_y[i]); - /* Compute power spectrum of the echo */ - spx_fft(st->fft_table, st->y, st->Y); - power_spectrum(st->Y, st->Yps, N); + /* Compute power spectrum of the echo */ + spx_fft(st->fft_table, st->y, st->Y); + power_spectrum(st->Y, residual_echo, N); #ifdef FIXED_POINT - if (leak_estimate > 16383) - leak2 = 32767; - else - leak2 = SHL16(leak_estimate, 1); + if (st->leak_estimate > 16383) + leak2 = 32767; + else + leak2 = SHL16(st->leak_estimate, 1); #else - if (leak_estimate>.5) - leak2 = 1; - else - leak2 = 2*leak_estimate; + if (st->leak_estimate>.5) + leak2 = 1; + else + leak2 = 2*st->leak_estimate; #endif - /* Estimate residual echo */ - for (i=0;i<=st->frame_size;i++) - Yout[i] = (spx_int32_t)MULT16_32_Q15(leak2,st->Yps[i]); - } + /* Estimate residual echo */ + for (i=0;i<=st->frame_size;i++) + residual_echo[i] = (spx_int32_t)MULT16_32_Q15(leak2,residual_echo[i]); + } - int mc_echo_ctl(SpeexEchoState *st, int request, void *ptr) { switch(request) diff --git a/libspeex/misc.c b/libspeex/misc.c index 53bdd0b..df44d86 100644 --- a/libspeex/misc.c +++ b/libspeex/misc.c @@ -63,74 +63,6 @@ long long spx_mips=0; #endif -spx_uint32_t be_int(spx_uint32_t i) -{ - spx_uint32_t ret=i; -#ifndef WORDS_BIGENDIAN - ret = i>>24; - ret += (i>>8)&0x0000ff00; - ret += (i<<8)&0x00ff0000; - ret += (i<<24); -#endif - return ret; -} - -spx_uint32_t le_int(spx_uint32_t i) -{ - spx_uint32_t ret=i; -#ifdef WORDS_BIGENDIAN - ret = i>>24; - ret += (i>>8)&0x0000ff00; - ret += (i<<8)&0x00ff0000; - ret += (i<<24); -#endif - return ret; -} - -#if BYTES_PER_CHAR == 2 -void speex_memcpy_bytes(char *dst, char *src, int nbytes) -{ - int i; - int nchars = nbytes/BYTES_PER_CHAR; - for (i=0;i<nchars;i++) - dst[i]=src[i]; - if (nbytes & 1) { - /* copy in the last byte */ - int last_i = nchars; - char last_dst_char = dst[last_i]; - char last_src_char = src[last_i]; - last_dst_char &= 0xff00; - last_dst_char |= (last_src_char & 0x00ff); - dst[last_i] = last_dst_char; - } -} -void speex_memset_bytes(char *dst, char c, int nbytes) -{ - int i; - spx_int16_t cc = ((c << 8) | c); - int nchars = nbytes/BYTES_PER_CHAR; - for (i=0;i<nchars;i++) - dst[i]=cc; - if (nbytes & 1) { - /* copy in the last byte */ - int last_i = nchars; - char last_dst_char = dst[last_i]; - last_dst_char &= 0xff00; - last_dst_char |= (c & 0x00ff); - dst[last_i] = last_dst_char; - } -} -#else -void speex_memcpy_bytes(char *dst, char *src, int nbytes) -{ - memcpy(dst, src, nbytes); -} -void speex_memset_bytes(char *dst, char src, int nbytes) -{ - memset(dst, src, nbytes); -} -#endif - #ifndef OVERRIDE_SPEEX_ALLOC void *speex_alloc (int size) { @@ -176,7 +108,7 @@ void *speex_move (void *dest, void *src, int n) #ifndef OVERRIDE_SPEEX_ERROR void speex_error(const char *str) { - fprintf (stderr, "Fatal error: %s\n", str); + fprintf (stderr, "Fatal (internal) error: %s\n", str); exit(1); } #endif @@ -184,14 +116,27 @@ void speex_error(const char *str) #ifndef OVERRIDE_SPEEX_WARNING void speex_warning(const char *str) { +#ifndef DISABLE_WARNINGS fprintf (stderr, "warning: %s\n", str); +#endif } #endif #ifndef OVERRIDE_SPEEX_WARNING_INT void speex_warning_int(const char *str, int val) { +#ifndef DISABLE_WARNINGS fprintf (stderr, "warning: %s %d\n", str, val); +#endif +} +#endif + +#ifndef OVERRIDE_SPEEX_NOTIFY +void speex_notify(const char *str) +{ +#ifndef DISABLE_NOTIFICATIONS + fprintf (stderr, "notification: %s\n", str); +#endif } #endif @@ -201,7 +146,7 @@ spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed) spx_word32_t res; *seed = 1664525 * *seed + 1013904223; res = MULT16_16(EXTRACT16(SHR32(*seed,16)),std); - return PSHR32(SUB32(res, SHR(res, 3)),14); + return EXTRACT16(PSHR32(SUB32(res, SHR32(res, 3)),14)); } #else spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed) diff --git a/libspeex/misc.h b/libspeex/misc.h index 4c70980..c6ea9e7 100644 --- a/libspeex/misc.h +++ b/libspeex/misc.h @@ -40,7 +40,7 @@ #define SPEEX_MINOR_VERSION 1 /**< Minor Speex version. */ #define SPEEX_MICRO_VERSION 13 /**< Micro Speex version. */ #define SPEEX_EXTRA_VERSION "" /**< Extra Speex version. */ -#define SPEEX_VERSION "speex-1.2-beta1" /**< Speex version string. */ +#define SPEEX_VERSION "speex-1.2beta1" /**< Speex version string. */ #endif /* A couple test to catch stupid option combinations */ @@ -75,10 +75,21 @@ void print_vec(float *vec, int len, char *name); #endif -/** Convert big endian */ -spx_uint32_t be_int(spx_uint32_t i); /** Convert little endian */ -spx_uint32_t le_int(spx_uint32_t i); +static inline spx_int32_t le_int(spx_int32_t i) +{ +#ifdef WORDS_BIGENDIAN + spx_uint32_t ui, ret; + ui = i; + ret = ui>>24; + ret |= (ui>>8)&0x0000ff00; + ret |= (ui<<8)&0x00ff0000; + ret |= (ui<<24); + return ret; +#else + return i; +#endif +} /** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_free */ void *speex_alloc (int size); @@ -98,21 +109,18 @@ void speex_free_scratch (void *ptr); /** Speex wrapper for mem_move */ void *speex_move (void *dest, void *src, int n); -/** Speex wrapper for memcpy */ -void speex_memcpy_bytes(char *dst, char *src, int nbytes); - -/** Speex wrapper for memset */ -void speex_memset_bytes(char *dst, char src, int nbytes); - -/** Print error message to stderr */ +/** Abort with an error message to stderr (internal Speex error) */ void speex_error(const char *str); -/** Print warning message to stderr */ +/** Print warning message to stderr (programming error) */ void speex_warning(const char *str); /** Print warning message with integer argument to stderr */ void speex_warning_int(const char *str, int val); +/** Print notification message to stderr */ +void speex_notify(const char *str); + /** Generate a random number */ spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed); diff --git a/libspeex/modes.c b/libspeex/modes.c index 97e7d1e..9a1fe9c 100644 --- a/libspeex/modes.c +++ b/libspeex/modes.c @@ -495,7 +495,7 @@ static const SpeexSBMode sb_wb_mode = { #endif .012, /*lag_factor*/ QCONST16(.0002,15), /*lpc_floor*/ - 0.9, + QCONST16(0.9f,15), {NULL, &wb_submode1, &wb_submode2, &wb_submode3, &wb_submode4, NULL, NULL, NULL}, 3, {1, 8, 2, 3, 4, 5, 5, 6, 6, 7, 7}, @@ -541,7 +541,7 @@ static const SpeexSBMode sb_uwb_mode = { #endif .012, /*lag_factor*/ QCONST16(.0002,15), /*lpc_floor*/ - 0.7, + QCONST16(0.7f,15), {NULL, &wb_submode1, NULL, NULL, NULL, NULL, NULL, NULL}, 1, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, @@ -608,11 +608,7 @@ static const SpeexSubmode nb_48k_submode = { split_cb_search_shape_sign, split_cb_shape_sign_unquant, &split_cb_nb_48k, -#ifdef FIXED_POINT - 22938, 16384, 11796, 18022, -#else - 0.7, 0.5, .36, .55, -#endif + QCONST16(.7,15), 144 }; @@ -622,7 +618,6 @@ static const SpeexNBMode nb_48k_mode = { 240, /*frameSize*/ 48, /*subframeSize*/ 10, /*lpcSize*/ - 640, /*bufSize*/ 17, /*pitchStart*/ 144, /*pitchEnd*/ 0.9, /*gamma1*/ @@ -667,7 +662,7 @@ const SpeexMode * speex_lib_get_mode (int mode) if (mode == SPEEX_MODEID_NB_48K) return &speex_nb_48k_mode; #endif - if (mode < 0 || mode > SPEEX_NB_MODES) return NULL; + if (mode < 0 || mode >= SPEEX_NB_MODES) return NULL; return speex_mode_list[mode]; } diff --git a/libspeex/modes.h b/libspeex/modes.h index 6a63240..5bf1971 100644 --- a/libspeex/modes.h +++ b/libspeex/modes.h @@ -46,6 +46,23 @@ #define SB_SUBMODES 8 #define SB_SUBMODE_BITS 3 +/* Used internally, NOT TO BE USED in applications */ +/** Used internally*/ +#define SPEEX_GET_PI_GAIN 100 +/** Used internally*/ +#define SPEEX_GET_EXC 101 +/** Used internally*/ +#define SPEEX_GET_INNOV 102 +/** Used internally*/ +#define SPEEX_GET_DTX_STATUS 103 +/** Used internally*/ +#define SPEEX_SET_INNOVATION_SAVE 104 +/** Used internally*/ +#define SPEEX_SET_WIDEBAND 105 + +/** Used internally*/ +#define SPEEX_GET_STACK 106 + /** Quantizes LSPs */ typedef void (*lsp_quant_func)(spx_lsp_t *, spx_lsp_t *, int, SpeexBits *); @@ -130,7 +147,7 @@ typedef struct SpeexSBMode { spx_word16_t gamma2; /**< Perceptual filter parameter #1 */ float lag_factor; /**< Lag-windowing parameter */ spx_word16_t lpc_floor; /**< Noise floor for LPC analysis */ - float folding_gain; + spx_word16_t folding_gain; const SpeexSubmode *submodes[SB_SUBMODES]; /**< Sub-mode data for the mode */ int defaultSubmode; /**< Default sub-mode to use when encoding */ diff --git a/libspeex/nb_celp.c b/libspeex/nb_celp.c index feedf71..1828aed 100644 --- a/libspeex/nb_celp.c +++ b/libspeex/nb_celp.c @@ -87,14 +87,14 @@ const spx_word16_t exc_gain_quant_scal1[2]={11546, 17224}; #else -const float exc_gain_quant_scal3_bound[7]={0.112338, 0.236980, 0.369316, 0.492054, 0.637471, 0.828874, 1.132784}; -const float exc_gain_quant_scal3[8]={0.061130, 0.163546, 0.310413, 0.428220, 0.555887, 0.719055, 0.938694, 1.326874}; -const float exc_gain_quant_scal1_bound[1]={0.87798}; -const float exc_gain_quant_scal1[2]={0.70469, 1.05127}; +const float exc_gain_quant_scal3_bound[7]={0.112338f, 0.236980f, 0.369316f, 0.492054f, 0.637471f, 0.828874f, 1.132784f}; +const float exc_gain_quant_scal3[8]={0.061130f, 0.163546f, 0.310413f, 0.428220f, 0.555887f, 0.719055f, 0.938694f, 1.326874f}; +const float exc_gain_quant_scal1_bound[1]={0.87798f}; +const float exc_gain_quant_scal1[2]={0.70469f, 1.05127f}; -#define LSP_MARGIN .002 -#define LSP_DELTA1 .2 -#define LSP_DELTA2 .05 +#define LSP_MARGIN .002f +#define LSP_DELTA1 .2f +#define LSP_DELTA2 .05f #endif @@ -187,7 +187,7 @@ void *nb_encoder_init(const SpeexMode *m) st->mem_exc2 = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t)); - st->innov_save = NULL; + st->innov_rms_save = NULL; st->pitch = (int*)speex_alloc((st->nbSubframes)*sizeof(int)); @@ -280,6 +280,8 @@ int nb_encode(void *state, void *vin, SpeexBits *bits) int pitch_half[2]; int ol_pitch_id=0; #endif + spx_word32_t ener=0; + spx_word16_t fine_gain; spx_word16_t *in = (spx_word16_t*)vin; st=(EncState *)state; @@ -432,7 +434,7 @@ int nb_encode(void *state, void *vin, SpeexBits *bits) ol_gain2=ol2; ol_gain2 = sqrt(2*ol_gain2*(ol1+ol2))*1.3*(1-.5*GAIN_SCALING_1*GAIN_SCALING_1*ol_pitch_coef*ol_pitch_coef); - ol_gain=SHR(sqrt(1+ol_gain2/st->frameSize),SIG_SHIFT); + ol_gain=SHR32(sqrt(1+ol_gain2/st->frameSize),SIG_SHIFT); } else #endif @@ -490,7 +492,7 @@ int nb_encode(void *state, void *vin, SpeexBits *bits) /* delta_qual*=.1*(3+st->vbr_quality);*/ if (st->vbr_enabled) { - int mode; + spx_int32_t mode; int choice=0; float min_diff=100; mode = 8; @@ -540,7 +542,7 @@ int nb_encode(void *state, void *vin, SpeexBits *bits) if (st->abr_enabled) { - int bitrate; + spx_int32_t bitrate; speex_encoder_ctl(state, SPEEX_GET_BITRATE, &bitrate); st->abr_drift+=(bitrate-st->abr_enabled); st->abr_drift2 = .95*st->abr_drift2 + .05*(bitrate-st->abr_enabled); @@ -720,7 +722,6 @@ int nb_encode(void *state, void *vin, SpeexBits *bits) int offset; spx_word16_t *sw; spx_word16_t *exc; - spx_sig_t *innov_save = NULL; int pitch; int response_bound = st->subframeSize; #ifdef EPIC_48K @@ -739,9 +740,6 @@ int nb_encode(void *state, void *vin, SpeexBits *bits) exc=st->exc+offset; /* Weighted signal */ sw=st->sw+offset; - /* Pointer for saving innovation */ - if (st->innov_save) - innov_save = st->innov_save+offset; /* LSP interpolation (quantized and unquantized) */ lsp_interpolate(st->old_lsp, lsp, interp_lsp, st->lpcSize, sub, st->nbSubframes); @@ -838,9 +836,9 @@ int nb_encode(void *state, void *vin, SpeexBits *bits) for (i=0;i<st->lpcSize;i++) st->mem_sw[i]=mem[i]; - /* Compute target signal */ + /* Compute target signal (saturation prevents overflows on clipped input speech) */ for (i=0;i<st->subframeSize;i++) - target[i]=SUB16(sw[i],PSHR32(ringing[i],1)); + target[i]=EXTRACT16(SATURATE(SUB32(sw[i],PSHR32(ringing[i],1)),32767)); /* Reset excitation */ for (i=0;i<st->subframeSize;i++) @@ -901,75 +899,64 @@ int nb_encode(void *state, void *vin, SpeexBits *bits) } /* Quantization of innovation */ - { - spx_word32_t ener=0; - spx_word16_t fine_gain; - - for (i=0;i<st->subframeSize;i++) - innov[i]=0; - - for (i=0;i<st->subframeSize;i++) - real_exc[i] = SUB16(real_exc[i], PSHR32(exc32[i],SIG_SHIFT-1)); - - ener = SHL32(EXTEND32(compute_rms16(real_exc, st->subframeSize)),SIG_SHIFT); - - /*FIXME: Should use DIV32_16 and make sure result fits in 16 bits */ + for (i=0;i<st->subframeSize;i++) + innov[i]=0; + + /* FIXME: Make sure this is save from overflows (so far so good) */ + for (i=0;i<st->subframeSize;i++) + real_exc[i] = EXTRACT16(SUB32(EXTEND32(real_exc[i]), PSHR32(exc32[i],SIG_SHIFT-1))); + + ener = SHL32(EXTEND32(compute_rms16(real_exc, st->subframeSize)),SIG_SHIFT); + + /*FIXME: Should use DIV32_16 and make sure result fits in 16 bits */ #ifdef FIXED_POINT - { - spx_word32_t f = PDIV32(ener,PSHR32(ol_gain,SIG_SHIFT)); - if (f<=32767) - fine_gain = f; - else - fine_gain = 32767; - } + { + spx_word32_t f = PDIV32(ener,PSHR32(ol_gain,SIG_SHIFT)); + if (f<=32767) + fine_gain = f; + else + fine_gain = 32767; + } #else - fine_gain = PDIV32_16(ener,PSHR32(ol_gain,SIG_SHIFT)); + fine_gain = PDIV32_16(ener,PSHR32(ol_gain,SIG_SHIFT)); #endif - /* Calculate gain correction for the sub-frame (if any) */ - if (SUBMODE(have_subframe_gain)) - { - int qe; - if (SUBMODE(have_subframe_gain)==3) - { - qe = scal_quant(fine_gain, exc_gain_quant_scal3_bound, 8); - speex_bits_pack(bits, qe, 3); - ener=MULT16_32_Q14(exc_gain_quant_scal3[qe],ol_gain); - } else { - qe = scal_quant(fine_gain, exc_gain_quant_scal1_bound, 2); - speex_bits_pack(bits, qe, 1); - ener=MULT16_32_Q14(exc_gain_quant_scal1[qe],ol_gain); - } - } else { - ener=ol_gain; - } - - /*printf ("%f %f\n", ener, ol_gain);*/ - - /* Normalize innovation */ - signal_div(target, target, ener, st->subframeSize); - - /* Quantize innovation */ - if (SUBMODE(innovation_quant)) + /* Calculate gain correction for the sub-frame (if any) */ + if (SUBMODE(have_subframe_gain)) + { + int qe; + if (SUBMODE(have_subframe_gain)==3) { - /* Codebook search */ - SUBMODE(innovation_quant)(target, interp_qlpc, bw_lpc1, bw_lpc2, - SUBMODE(innovation_params), st->lpcSize, st->subframeSize, - innov, syn_resp, bits, stack, st->complexity, SUBMODE(double_codebook)); - - /* De-normalize innovation and update excitation */ - signal_mul(innov, innov, ener, st->subframeSize); - - for (i=0;i<st->subframeSize;i++) - exc[i] = EXTRACT16(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT)); + qe = scal_quant(fine_gain, exc_gain_quant_scal3_bound, 8); + speex_bits_pack(bits, qe, 3); + ener=MULT16_32_Q14(exc_gain_quant_scal3[qe],ol_gain); } else { - speex_error("No fixed codebook"); + qe = scal_quant(fine_gain, exc_gain_quant_scal1_bound, 2); + speex_bits_pack(bits, qe, 1); + ener=MULT16_32_Q14(exc_gain_quant_scal1[qe],ol_gain); } + } else { + ener=ol_gain; + } + + /*printf ("%f %f\n", ener, ol_gain);*/ + + /* Normalize innovation */ + signal_div(target, target, ener, st->subframeSize); + + /* Quantize innovation */ + if (SUBMODE(innovation_quant)) + { + /* Codebook search */ + SUBMODE(innovation_quant)(target, interp_qlpc, bw_lpc1, bw_lpc2, + SUBMODE(innovation_params), st->lpcSize, st->subframeSize, + innov, syn_resp, bits, stack, st->complexity, SUBMODE(double_codebook)); + + /* De-normalize innovation and update excitation */ + signal_mul(innov, innov, ener, st->subframeSize); + + for (i=0;i<st->subframeSize;i++) + exc[i] = EXTRACT16(SATURATE32(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT),32767)); - if (innov_save) - { - for (i=0;i<st->subframeSize;i++) - innov_save[i] = innov[i]; - } /* In some (rare) modes, we do a second search (more bits) to reduce noise even more */ if (SUBMODE(double_codebook)) { char *tmp_stack=stack; @@ -978,23 +965,26 @@ int nb_encode(void *state, void *vin, SpeexBits *bits) for (i=0;i<st->subframeSize;i++) innov2[i]=0; for (i=0;i<st->subframeSize;i++) - target[i]=MULT16_16_P13(QCONST16(2.2,13), target[i]); + target[i]=MULT16_16_P13(QCONST16(2.2f,13), target[i]); SUBMODE(innovation_quant)(target, interp_qlpc, bw_lpc1, bw_lpc2, SUBMODE(innovation_params), st->lpcSize, st->subframeSize, innov2, syn_resp, bits, stack, st->complexity, 0); - signal_mul(innov2, innov2, MULT16_32_Q15(QCONST16(0.454545,15),ener), st->subframeSize); + signal_mul(innov2, innov2, MULT16_32_Q15(QCONST16(0.454545f,15),ener), st->subframeSize); for (i=0;i<st->subframeSize;i++) - exc[i] = ADD32(exc[i],PSHR32(innov2[i],SIG_SHIFT)); - if (innov_save) - { - for (i=0;i<st->subframeSize;i++) - innov_save[i] = ADD32(innov_save[i],innov2[i]); - } + innov[i] = ADD32(innov[i],innov2[i]); stack = tmp_stack; } - + for (i=0;i<st->subframeSize;i++) + exc[i] = EXTRACT16(SATURATE32(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT),32767)); + if (st->innov_rms_save) + { + st->innov_rms_save[sub] = compute_rms(innov, st->subframeSize); + } + } else { + speex_error("No fixed codebook"); } + for (i=0;i<st->subframeSize;i++) sw[i] = exc[i]; /* Final signal synthesis from excitation */ @@ -1145,7 +1135,7 @@ const spx_word16_t attenuation[10] = {1., 0.961, 0.852, 0.698, 0.527, 0.368, 0.2 static void nb_decode_lost(DecState *st, spx_word16_t *out, char *stack) { - int i, sub; + int i; int pitch_val; spx_word16_t pitch_gain; spx_word16_t fact; @@ -1166,7 +1156,7 @@ static void nb_decode_lost(DecState *st, spx_word16_t *out, char *stack) pitch_gain = st->last_pitch_gain; if (pitch_gain>54) pitch_gain = 54; - pitch_gain = SHL(pitch_gain, 9); + pitch_gain = SHL16(pitch_gain, 9); #else pitch_gain = GAIN_SCALING_1*st->last_pitch_gain; if (pitch_gain>.85) @@ -1200,7 +1190,7 @@ static void nb_decode_lost(DecState *st, spx_word16_t *out, char *stack) st->first = 0; st->count_lost++; - st->pitch_gain_buf[st->pitch_gain_buf_idx++] = PSHR(pitch_gain,9); + st->pitch_gain_buf[st->pitch_gain_buf_idx++] = PSHR16(pitch_gain,9); if (st->pitch_gain_buf_idx > 2) /* rollover */ st->pitch_gain_buf_idx = 0; } @@ -1226,7 +1216,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout) VARDECL(spx_lsp_t *qlsp); spx_word16_t pitch_average=0; #ifdef EPIC_48K - int pitch_half[2]; + int pitch_half[2] = {0, 0}; int ol_pitch_id=0; #endif spx_word16_t *out = (spx_word16_t*)vout; @@ -1267,7 +1257,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout) speex_mode_query(&speex_wb_mode, SPEEX_SUBMODE_BITS_PER_FRAME, &advance); if (advance < 0) { - speex_warning ("Invalid wideband mode encountered. Corrupted stream?"); + speex_notify("Invalid mode encountered. The stream is corrupted."); return -2; } advance -= (SB_SUBMODE_BITS+1); @@ -1282,7 +1272,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout) speex_mode_query(&speex_wb_mode, SPEEX_SUBMODE_BITS_PER_FRAME, &advance); if (advance < 0) { - speex_warning ("Invalid wideband mode encountered: corrupted stream?"); + speex_notify("Invalid mode encountered. The stream is corrupted."); return -2; } advance -= (SB_SUBMODE_BITS+1); @@ -1290,7 +1280,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout) wideband = speex_bits_unpack_unsigned(bits, 1); if (wideband) { - speex_warning ("More than two wideband layers found: corrupted stream?"); + speex_notify("More than two wideband layers found. The stream is corrupted."); return -2; } @@ -1315,7 +1305,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout) return ret; } else if (m>8) /* Invalid mode */ { - speex_warning("Invalid mode encountered: corrupted stream?"); + speex_notify("Invalid mode encountered. The stream is corrupted."); return -2; } @@ -1338,7 +1328,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout) { VARDECL(spx_coef_t *lpc); ALLOC(lpc, st->lpcSize, spx_coef_t); - bw_lpc(GAMMA_SCALING*.93, st->interp_qlpc, lpc, st->lpcSize); + bw_lpc(QCONST16(0.93f,15), st->interp_qlpc, lpc, st->lpcSize); { float innov_gain=0; float pgain=GAIN_SCALING_1*st->last_pitch_gain; @@ -1426,6 +1416,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout) int qe; qe = speex_bits_unpack_unsigned(bits, 5); #ifdef FIXED_POINT + /* FIXME: Perhaps we could slightly lower the gain here when the output is going to saturate? */ ol_gain = MULT16_32_Q15(28406,ol_gain_table[qe]); #else ol_gain = SIG_SCALING*exp(qe/3.5); @@ -1458,7 +1449,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout) int offset; spx_word16_t *exc; spx_word16_t *sp; - spx_sig_t *innov_save = NULL; + spx_word16_t *innov_save = NULL; spx_word16_t tmp; #ifdef EPIC_48K @@ -1535,7 +1526,11 @@ int nb_decode(void *state, SpeexBits *bits, void *vout) #ifdef EPIC_48K } #endif - + /* Ensuring that things aren't blowing up as would happen if e.g. an encoder is + crafting packets to make us produce NaNs and slow down the decoder (vague DoS threat). + We can probably be even more aggressive and limit to 15000 or so. */ + sanitize_values32(exc32, NEG32(QCONST32(32000,SIG_SHIFT-1)), QCONST32(32000,SIG_SHIFT-1), st->subframeSize); + tmp = gain_3tap_to_1tap(pitch_gain); pitch_average += tmp; @@ -1576,16 +1571,38 @@ int nb_decode(void *state, SpeexBits *bits, void *vout) { /*Fixed codebook contribution*/ SUBMODE(innovation_unquant)(innov, SUBMODE(innovation_params), st->subframeSize, bits, stack, &st->seed); + /* De-normalize innovation and update excitation */ +#ifdef FIXED_POINT + signal_mul(innov, innov, ener, st->subframeSize); +#else + signal_mul(innov, innov, ener, st->subframeSize); +#endif + /* Decode second codebook (only for some modes) */ + if (SUBMODE(double_codebook)) + { + char *tmp_stack=stack; + VARDECL(spx_sig_t *innov2); + ALLOC(innov2, st->subframeSize, spx_sig_t); + for (i=0;i<st->subframeSize;i++) + innov2[i]=0; + SUBMODE(innovation_unquant)(innov2, SUBMODE(innovation_params), st->subframeSize, bits, stack, &st->seed); + signal_mul(innov2, innov2, MULT16_32_Q15(QCONST16(0.454545f,15),ener), st->subframeSize); + for (i=0;i<st->subframeSize;i++) + innov[i] = ADD32(innov[i], innov2[i]); + stack = tmp_stack; + } + for (i=0;i<st->subframeSize;i++) + exc[i]=EXTRACT16(SATURATE32(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT),32767)); + /*print_vec(exc, 40, "innov");*/ + if (innov_save) + { + for (i=0;i<st->subframeSize;i++) + innov_save[i] = EXTRACT16(PSHR32(innov[i], SIG_SHIFT)); + } } else { speex_error("No fixed codebook"); } - /* De-normalize innovation and update excitation */ -#ifdef FIXED_POINT - signal_mul(innov, innov, ener, st->subframeSize); -#else - signal_mul(innov, innov, ener, st->subframeSize); -#endif /*Vocoder mode*/ if (st->submodeID==1) { @@ -1617,35 +1634,8 @@ int nb_decode(void *state, SpeexBits *bits, void *vout) st->voc_mean = .95*st->voc_mean + .05*exc[i]; exc[i]-=st->voc_mean; } - } else { - for (i=0;i<st->subframeSize;i++) - exc[i]=PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT); - /*print_vec(exc, 40, "innov");*/ - } - if (innov_save) - { - for (i=0;i<st->subframeSize;i++) - innov_save[i] = innov[i]; - } - /* Decode second codebook (only for some modes) */ - if (SUBMODE(double_codebook)) - { - char *tmp_stack=stack; - VARDECL(spx_sig_t *innov2); - ALLOC(innov2, st->subframeSize, spx_sig_t); - for (i=0;i<st->subframeSize;i++) - innov2[i]=0; - SUBMODE(innovation_unquant)(innov2, SUBMODE(innovation_params), st->subframeSize, bits, stack, &st->seed); - signal_mul(innov2, innov2, MULT16_32_Q15(QCONST16(0.454545,15),ener), st->subframeSize); - for (i=0;i<st->subframeSize;i++) - exc[i] = ADD16(exc[i],PSHR32(innov2[i],SIG_SHIFT)); - if (innov_save) - { - for (i=0;i<st->subframeSize;i++) - innov_save[i] = ADD32(innov_save[i],innov2[i]); - } - stack = tmp_stack; } + } } @@ -1712,7 +1702,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout) for (i=0;i<st->lpcSize;i+=2) { /*pi_g += -st->interp_qlpc[i] + st->interp_qlpc[i+1];*/ - pi_g = ADD32(pi_g, SUB32(EXTEND32(st->interp_qlpc[i+1]),EXTEND32(st->interp_qlpc[i]))); + pi_g = ADD32(pi_g, SUB32(EXTEND32(ak[i+1]),EXTEND32(ak[i]))); } st->pi_gain[sub] = pi_g; } @@ -1759,40 +1749,40 @@ int nb_encoder_ctl(void *state, int request, void *ptr) switch(request) { case SPEEX_GET_FRAME_SIZE: - (*(int*)ptr) = st->frameSize; + (*(spx_int32_t*)ptr) = st->frameSize; break; case SPEEX_SET_LOW_MODE: case SPEEX_SET_MODE: - st->submodeSelect = st->submodeID = (*(int*)ptr); + st->submodeSelect = st->submodeID = (*(spx_int32_t*)ptr); break; case SPEEX_GET_LOW_MODE: case SPEEX_GET_MODE: - (*(int*)ptr) = st->submodeID; + (*(spx_int32_t*)ptr) = st->submodeID; break; case SPEEX_SET_VBR: - st->vbr_enabled = (*(int*)ptr); + st->vbr_enabled = (*(spx_int32_t*)ptr); break; case SPEEX_GET_VBR: - (*(int*)ptr) = st->vbr_enabled; + (*(spx_int32_t*)ptr) = st->vbr_enabled; break; case SPEEX_SET_VAD: - st->vad_enabled = (*(int*)ptr); + st->vad_enabled = (*(spx_int32_t*)ptr); break; case SPEEX_GET_VAD: - (*(int*)ptr) = st->vad_enabled; + (*(spx_int32_t*)ptr) = st->vad_enabled; break; case SPEEX_SET_DTX: - st->dtx_enabled = (*(int*)ptr); + st->dtx_enabled = (*(spx_int32_t*)ptr); break; case SPEEX_GET_DTX: - (*(int*)ptr) = st->dtx_enabled; + (*(spx_int32_t*)ptr) = st->dtx_enabled; break; case SPEEX_SET_ABR: st->abr_enabled = (*(spx_int32_t*)ptr); st->vbr_enabled = st->abr_enabled!=0; if (st->vbr_enabled) { - int i=10; + spx_int32_t i=10; spx_int32_t rate, target; float vbr_qual; target = (*(spx_int32_t*)ptr); @@ -1825,7 +1815,7 @@ int nb_encoder_ctl(void *state, int request, void *ptr) break; case SPEEX_SET_QUALITY: { - int quality = (*(int*)ptr); + int quality = (*(spx_int32_t*)ptr); if (quality < 0) quality = 0; if (quality > 10) @@ -1834,7 +1824,7 @@ int nb_encoder_ctl(void *state, int request, void *ptr) } break; case SPEEX_SET_COMPLEXITY: - st->complexity = (*(int*)ptr); + st->complexity = (*(spx_int32_t*)ptr); if (st->complexity<0) st->complexity=0; break; @@ -1843,7 +1833,7 @@ int nb_encoder_ctl(void *state, int request, void *ptr) break; case SPEEX_SET_BITRATE: { - int i=10; + spx_int32_t i=10; spx_int32_t rate, target; target = (*(spx_int32_t*)ptr); while (i>=0) @@ -1884,21 +1874,21 @@ int nb_encoder_ctl(void *state, int request, void *ptr) } break; case SPEEX_SET_SUBMODE_ENCODING: - st->encode_submode = (*(int*)ptr); + st->encode_submode = (*(spx_int32_t*)ptr); break; case SPEEX_GET_SUBMODE_ENCODING: - (*(int*)ptr) = st->encode_submode; + (*(spx_int32_t*)ptr) = st->encode_submode; break; case SPEEX_GET_LOOKAHEAD: - (*(int*)ptr)=(st->windowSize-st->frameSize); + (*(spx_int32_t*)ptr)=(st->windowSize-st->frameSize); break; case SPEEX_SET_PLC_TUNING: - st->plc_tuning = (*(int*)ptr); + st->plc_tuning = (*(spx_int32_t*)ptr); if (st->plc_tuning>100) st->plc_tuning=100; break; case SPEEX_GET_PLC_TUNING: - (*(int*)ptr)=(st->plc_tuning); + (*(spx_int32_t*)ptr)=(st->plc_tuning); break; case SPEEX_SET_VBR_MAX_BITRATE: st->vbr_max = (*(spx_int32_t*)ptr); @@ -1925,19 +1915,21 @@ int nb_encoder_ctl(void *state, int request, void *ptr) case SPEEX_GET_EXC: { int i; - spx_word16_t *e = (spx_word16_t*)ptr; - for (i=0;i<st->frameSize;i++) - e[i]=st->exc[i]; + for (i=0;i<st->nbSubframes;i++) + ((spx_word16_t*)ptr)[i] = compute_rms16(st->exc+i*st->subframeSize, st->subframeSize); } break; case SPEEX_GET_RELATIVE_QUALITY: (*(float*)ptr)=st->relative_quality; break; case SPEEX_SET_INNOVATION_SAVE: - st->innov_save = (spx_sig_t*)ptr; + st->innov_rms_save = (spx_word16_t*)ptr; break; case SPEEX_SET_WIDEBAND: - st->isWideband = *((int*)ptr); + st->isWideband = *((spx_int32_t*)ptr); + break; + case SPEEX_GET_STACK: + *((char**)ptr) = st->stack; break; default: speex_warning_int("Unknown nb_ctl request: ", request); @@ -1954,20 +1946,20 @@ int nb_decoder_ctl(void *state, int request, void *ptr) { case SPEEX_SET_LOW_MODE: case SPEEX_SET_MODE: - st->submodeID = (*(int*)ptr); + st->submodeID = (*(spx_int32_t*)ptr); break; case SPEEX_GET_LOW_MODE: case SPEEX_GET_MODE: - (*(int*)ptr) = st->submodeID; + (*(spx_int32_t*)ptr) = st->submodeID; break; case SPEEX_SET_ENH: - st->lpc_enh_enabled = *((int*)ptr); + st->lpc_enh_enabled = *((spx_int32_t*)ptr); break; case SPEEX_GET_ENH: - *((int*)ptr) = st->lpc_enh_enabled; + *((spx_int32_t*)ptr) = st->lpc_enh_enabled; break; case SPEEX_GET_FRAME_SIZE: - (*(int*)ptr) = st->frameSize; + (*(spx_int32_t*)ptr) = st->frameSize; break; case SPEEX_GET_BITRATE: if (st->submodes[st->submodeID]) @@ -2007,13 +1999,13 @@ int nb_decoder_ctl(void *state, int request, void *ptr) } break; case SPEEX_SET_SUBMODE_ENCODING: - st->encode_submode = (*(int*)ptr); + st->encode_submode = (*(spx_int32_t*)ptr); break; case SPEEX_GET_SUBMODE_ENCODING: - (*(int*)ptr) = st->encode_submode; + (*(spx_int32_t*)ptr) = st->encode_submode; break; case SPEEX_GET_LOOKAHEAD: - (*(int*)ptr)=st->subframeSize; + (*(spx_int32_t*)ptr)=st->subframeSize; break; case SPEEX_SET_HIGHPASS: st->highpass_enabled = (*(spx_int32_t*)ptr); @@ -2033,19 +2025,21 @@ int nb_decoder_ctl(void *state, int request, void *ptr) case SPEEX_GET_EXC: { int i; - spx_word16_t *e = (spx_word16_t*)ptr; - for (i=0;i<st->frameSize;i++) - e[i]=st->exc[i]; + for (i=0;i<st->nbSubframes;i++) + ((spx_word16_t*)ptr)[i] = compute_rms16(st->exc+i*st->subframeSize, st->subframeSize); } break; case SPEEX_GET_DTX_STATUS: - *((int*)ptr) = st->dtx_enabled; + *((spx_int32_t*)ptr) = st->dtx_enabled; break; case SPEEX_SET_INNOVATION_SAVE: - st->innov_save = (spx_sig_t*)ptr; + st->innov_save = (spx_word16_t*)ptr; break; case SPEEX_SET_WIDEBAND: - st->isWideband = *((int*)ptr); + st->isWideband = *((spx_int32_t*)ptr); + break; + case SPEEX_GET_STACK: + *((char**)ptr) = st->stack; break; default: speex_warning_int("Unknown nb_ctl request: ", request); diff --git a/libspeex/nb_celp.h b/libspeex/nb_celp.h index a72c2b1..1ebf717 100644 --- a/libspeex/nb_celp.h +++ b/libspeex/nb_celp.h @@ -96,12 +96,12 @@ typedef struct EncState { spx_mem_t *mem_exc2; /**< Filter memory for excitation (whole frame) */ spx_mem_t mem_hp[2]; /**< High-pass filter memory */ spx_word32_t *pi_gain; /**< Gain of LPC filter at theta=pi (fe/2) */ - spx_sig_t *innov_save; /**< If non-NULL, innovation is copied here */ + spx_word16_t *innov_rms_save; /**< If non-NULL, innovation RMS is copied here */ VBRState *vbr; /**< State of the VBR data */ float vbr_quality; /**< Quality setting for VBR encoding */ float relative_quality; /**< Relative quality that will be needed by VBR */ - int vbr_enabled; /**< 1 for enabling VBR, 0 otherwise */ + spx_int32_t vbr_enabled; /**< 1 for enabling VBR, 0 otherwise */ spx_int32_t vbr_max; /**< Max bit-rate allowed in VBR mode */ int vad_enabled; /**< 1 for enabling VAD, 0 otherwise */ int dtx_enabled; /**< 1 for enabling DTX, 0 otherwise */ @@ -148,7 +148,7 @@ typedef struct DecState { spx_mem_t *mem_sp; /**< Filter memory for synthesis signal */ spx_mem_t mem_hp[2]; /**< High-pass filter memory */ spx_word32_t *pi_gain; /**< Gain of LPC filter at theta=pi (fe/2) */ - spx_sig_t *innov_save; /** If non-NULL, innovation is copied here */ + spx_word16_t *innov_save; /** If non-NULL, innovation is copied here */ /* This is used in packet loss concealment */ int last_pitch; /**< Pitch of last correctly decoded frame */ diff --git a/libspeex/preprocess.c b/libspeex/preprocess.c index 02724f2..b5caf4b 100644 --- a/libspeex/preprocess.c +++ b/libspeex/preprocess.c @@ -1,6 +1,6 @@ -/* Copyright (C) 2003 Epic Games - Written by Jean-Marc Valin - +/* Copyright (C) 2003 Epic Games (written by Jean-Marc Valin) + Copyright (C) 2004-2006 Epic Games + File: preprocess.c Preprocessor with denoising based on the algorithm by Ephraim and Malah @@ -31,96 +31,369 @@ POSSIBILITY OF SUCH DAMAGE. */ + +/* + Recommended papers: + + Y. Ephraim and D. Malah, "Speech enhancement using minimum mean-square error + short-time spectral amplitude estimator". IEEE Transactions on Acoustics, + Speech and Signal Processing, vol. ASSP-32, no. 6, pp. 1109-1121, 1984. + + Y. Ephraim and D. Malah, "Speech enhancement using minimum mean-square error + log-spectral amplitude estimator". IEEE Transactions on Acoustics, Speech and + Signal Processing, vol. ASSP-33, no. 2, pp. 443-445, 1985. + + I. Cohen and B. Berdugo, "Speech enhancement for non-stationary noise environments". + Signal Processing, vol. 81, no. 2, pp. 2403-2418, 2001. + + Stefan Gustafsson, Rainer Martin, Peter Jax, and Peter Vary. "A psychoacoustic + approach to combined acoustic echo cancellation and noise reduction". IEEE + Transactions on Speech and Audio Processing, 2002. + + J.-M. Valin, J. Rouat, and F. Michaud, "Microphone array post-filter for separation + of simultaneous non-stationary sources". In Proceedings IEEE International + Conference on Acoustics, Speech, and Signal Processing, 2004. +*/ + #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <math.h> #include "speex/speex_preprocess.h" +#include "speex/speex_echo.h" #include "misc.h" -#include "smallft.h" - -#define max(a,b) ((a) > (b) ? (a) : (b)) -#define min(a,b) ((a) < (b) ? (a) : (b)) +#include "fftwrap.h" +#include "filterbank.h" +#include "math_approx.h" #ifndef M_PI #define M_PI 3.14159263 #endif -#define SQRT_M_PI_2 0.88623 -#define LOUDNESS_EXP 2.5 +#define LOUDNESS_EXP 5.f +#define AMP_SCALE .001f +#define AMP_SCALE_1 1000.f + +#define NB_BANDS 24 + +#define SPEECH_PROB_START_DEFAULT QCONST16(0.35f,15) +#define SPEECH_PROB_CONTINUE_DEFAULT QCONST16(0.20f,15) +#define NOISE_SUPPRESS_DEFAULT -15 +#define ECHO_SUPPRESS_DEFAULT -40 +#define ECHO_SUPPRESS_ACTIVE_DEFAULT -15 + +#ifndef NULL +#define NULL 0 +#endif + +#define SQR(x) ((x)*(x)) +#define SQR16(x) (MULT16_16((x),(x))) +#define SQR16_Q15(x) (MULT16_16_Q15((x),(x))) + +#ifdef FIXED_POINT +static inline spx_word16_t DIV32_16_Q8(spx_word32_t a, spx_word32_t b) +{ + if (SHR32(a,7) >= b) + { + return 32767; + } else { + if (b>=QCONST32(1,23)) + { + a = SHR32(a,8); + b = SHR32(b,8); + } + if (b>=QCONST32(1,19)) + { + a = SHR32(a,4); + b = SHR32(b,4); + } + if (b>=QCONST32(1,15)) + { + a = SHR32(a,4); + b = SHR32(b,4); + } + a = SHL32(a,8); + return PDIV32_16(a,b); + } + +} +static inline spx_word16_t DIV32_16_Q15(spx_word32_t a, spx_word32_t b) +{ + if (SHR32(a,15) >= b) + { + return 32767; + } else { + if (b>=QCONST32(1,23)) + { + a = SHR32(a,8); + b = SHR32(b,8); + } + if (b>=QCONST32(1,19)) + { + a = SHR32(a,4); + b = SHR32(b,4); + } + if (b>=QCONST32(1,15)) + { + a = SHR32(a,4); + b = SHR32(b,4); + } + a = SHL32(a,15)-a; + return DIV32_16(a,b); + } +} +#define SNR_SCALING 256.f +#define SNR_SCALING_1 0.0039062f +#define SNR_SHIFT 8 + +#define FRAC_SCALING 32767.f +#define FRAC_SCALING_1 3.0518e-05 +#define FRAC_SHIFT 1 + +#define EXPIN_SCALING 2048.f +#define EXPIN_SCALING_1 0.00048828f +#define EXPIN_SHIFT 11 +#define EXPOUT_SCALING_1 1.5259e-05 + +#define NOISE_SHIFT 7 -#define NB_BANDS 8 +#else + +#define DIV32_16_Q8(a,b) ((a)/(b)) +#define DIV32_16_Q15(a,b) ((a)/(b)) +#define SNR_SCALING 1.f +#define SNR_SCALING_1 1.f +#define SNR_SHIFT 0 +#define FRAC_SCALING 1.f +#define FRAC_SCALING_1 1.f +#define FRAC_SHIFT 0 +#define NOISE_SHIFT 0 -#define SPEEX_PROB_START_DEFAULT 0.35f -#define SPEEX_PROB_CONTINUE_DEFAULT 0.20f +#define EXPIN_SCALING 1.f +#define EXPIN_SCALING_1 1.f +#define EXPOUT_SCALING_1 1.f -#define ZMIN .1 -#define ZMAX .316 -#define ZMIN_1 10 -#define LOG_MIN_MAX_1 0.86859 +#endif -static void conj_window(float *w, int len) +/** Speex pre-processor state. */ +struct SpeexPreprocessState_ { + /* Basic info */ + int frame_size; /**< Number of samples processed each time */ + int ps_size; /**< Number of points in the power spectrum */ + int sampling_rate; /**< Sampling rate of the input/output */ + int nbands; + FilterBank *bank; + + /* Parameters */ + int denoise_enabled; + int vad_enabled; + int dereverb_enabled; + spx_word16_t reverb_decay; + spx_word16_t reverb_level; + spx_word16_t speech_prob_start; + spx_word16_t speech_prob_continue; + int noise_suppress; + int echo_suppress; + int echo_suppress_active; + SpeexEchoState *echo_state; + + /* DSP-related arrays */ + spx_word16_t *frame; /**< Processing frame (2*ps_size) */ + spx_word16_t *ft; /**< Processing frame in freq domain (2*ps_size) */ + spx_word32_t *ps; /**< Current power spectrum */ + spx_word16_t *gain2; /**< Adjusted gains */ + spx_word16_t *gain_floor; /**< Minimum gain allowed */ + spx_word16_t *window; /**< Analysis/Synthesis window */ + spx_word32_t *noise; /**< Noise estimate */ + spx_word32_t *reverb_estimate; /**< Estimate of reverb energy */ + spx_word32_t *old_ps; /**< Power spectrum for last frame */ + spx_word16_t *gain; /**< Ephraim Malah gain */ + spx_word16_t *prior; /**< A-priori SNR */ + spx_word16_t *post; /**< A-posteriori SNR */ + + spx_word32_t *S; /**< Smoothed power spectrum */ + spx_word32_t *Smin; /**< See Cohen paper */ + spx_word32_t *Stmp; /**< See Cohen paper */ + int *update_prob; /**< Propability of speech presence for noise update */ + + spx_word16_t *zeta; /**< Smoothed a priori SNR */ + spx_word32_t *echo_noise; + spx_word32_t *residual_echo; + + /* Misc */ + spx_word16_t *inbuf; /**< Input buffer (overlapped analysis) */ + spx_word16_t *outbuf; /**< Output buffer (for overlap and add) */ + + /* AGC stuff, only for floating point for now */ +#ifndef FIXED_POINT + int agc_enabled; + float agc_level; + float loudness_accum; + float *loudness_weight; /**< Perceptual loudness curve */ + float loudness; /**< Loudness estimate */ + float agc_gain; /**< Current AGC gain */ + int nb_loudness_adapt; /**< Number of frames used for loudness adaptation so far */ + float max_gain; /**< Maximum gain allowed */ + float max_increase_step; /**< Maximum increase in gain from one frame to another */ + float max_decrease_step; /**< Maximum decrease in gain from one frame to another */ + float prev_loudness; /**< Loudness of previous frame */ + float init_max; /**< Current gain limit during initialisation */ +#endif + int nb_adapt; /**< Number of frames used for adaptation so far */ + int was_speech; + int min_count; /**< Number of frames processed so far */ + void *fft_lookup; /**< Lookup table for the FFT */ +#ifdef FIXED_POINT + int frame_shift; +#endif +}; + + +static void conj_window(spx_word16_t *w, int len) { int i; for (i=0;i<len;i++) { - float x=4*((float)i)/len; + spx_word16_t tmp; +#ifdef FIXED_POINT + spx_word16_t x = DIV32_16(MULT16_16(32767,i),len); +#else + spx_word16_t x = DIV32_16(MULT16_16(QCONST16(4.f,13),i),len); +#endif int inv=0; - if (x<1) + if (x<QCONST16(1.f,13)) { - } else if (x<2) + } else if (x<QCONST16(2.f,13)) { - x=2-x; + x=QCONST16(2.f,13)-x; inv=1; - } else if (x<3) + } else if (x<QCONST16(3.f,13)) { - x=x-2; + x=x-QCONST16(2.f,13); inv=1; } else { - x=4-x; + x=QCONST16(2.f,13)-x+QCONST16(2.f,13); /* 4 - x */ } - x*=1.9979; - w[i]=(.5-.5*cos(x))*(.5-.5*cos(x)); + x = MULT16_16_Q14(QCONST16(1.271903f,14), x); + tmp = SQR16_Q15(QCONST16(.5f,15)-MULT16_16_P15(QCONST16(.5f,15),spx_cos_norm(QCONST32(x,2)))); if (inv) - w[i]=1-w[i]; - w[i]=sqrt(w[i]); + tmp=SUB16(Q15_ONE,tmp); + w[i]=spx_sqrt(SHL32(EXTEND32(tmp),15)); } } + +#ifdef FIXED_POINT /* This function approximates the gain function y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x) which multiplied by xi/(1+xi) is the optimal gain in the loudness domain ( sqrt[amplitude] ) + Input in Q11 format, output in Q15 */ -static inline float hypergeom_gain(float x) +static inline spx_word32_t hypergeom_gain(spx_word32_t xx) +{ + int ind; + spx_word16_t frac; + /* Q13 table */ + static const spx_word16_t table[21] = { + 6730, 8357, 9868, 11267, 12563, 13770, 14898, + 15959, 16961, 17911, 18816, 19682, 20512, 21311, + 22082, 22827, 23549, 24250, 24931, 25594, 26241}; + ind = SHR32(xx,10); + if (ind<0) + return Q15_ONE; + if (ind>19) + return ADD32(EXTEND32(Q15_ONE),EXTEND32(DIV32_16(QCONST32(.1296,23), SHR32(xx,EXPIN_SHIFT-SNR_SHIFT)))); + frac = SHL32(xx-SHL32(ind,10),5); + return SHL32(DIV32_16(PSHR32(MULT16_16(Q15_ONE-frac,table[ind]) + MULT16_16(frac,table[ind+1]),7),(spx_sqrt(SHL32(xx,15)+6711))),7); +} + +static inline spx_word16_t qcurve(spx_word16_t x) +{ + x = MAX16(x, 1); + return DIV32_16(SHL32(EXTEND32(32767),9),ADD16(512,MULT16_16_Q15(QCONST16(.60f,15),DIV32_16(32767,x)))); +} + +/* Compute the gain floor based on different floors for the background noise and residual echo */ +static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, spx_word32_t *noise, spx_word32_t *echo, spx_word16_t *gain_floor, int len) +{ + int i; + + if (noise_suppress > effective_echo_suppress) + { + spx_word16_t noise_gain, gain_ratio; + noise_gain = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(0.11513,11),noise_suppress)),1))); + gain_ratio = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(.2302585f,11),effective_echo_suppress-noise_suppress)),1))); + + /* gain_floor = sqrt [ (noise*noise_floor + echo*echo_floor) / (noise+echo) ] */ + for (i=0;i<len;i++) + gain_floor[i] = MULT16_16_Q15(noise_gain, + spx_sqrt(SHL32(EXTEND32(DIV32_16_Q15(PSHR32(noise[i],NOISE_SHIFT) + MULT16_32_Q15(gain_ratio,echo[i]), + (1+PSHR32(noise[i],NOISE_SHIFT) + echo[i]) )),15))); + } else { + spx_word16_t echo_gain, gain_ratio; + echo_gain = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(0.11513,11),effective_echo_suppress)),1))); + gain_ratio = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(.2302585f,11),noise_suppress-effective_echo_suppress)),1))); + + /* gain_floor = sqrt [ (noise*noise_floor + echo*echo_floor) / (noise+echo) ] */ + for (i=0;i<len;i++) + gain_floor[i] = MULT16_16_Q15(echo_gain, + spx_sqrt(SHL32(EXTEND32(DIV32_16_Q15(MULT16_32_Q15(gain_ratio,PSHR32(noise[i],NOISE_SHIFT)) + echo[i], + (1+PSHR32(noise[i],NOISE_SHIFT) + echo[i]) )),15))); + } +} + +#else +/* This function approximates the gain function + y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x) + which multiplied by xi/(1+xi) is the optimal gain + in the loudness domain ( sqrt[amplitude] ) +*/ +static inline spx_word32_t hypergeom_gain(spx_word32_t xx) { int ind; float integer, frac; + float x; static const float table[21] = { 0.82157f, 1.02017f, 1.20461f, 1.37534f, 1.53363f, 1.68092f, 1.81865f, 1.94811f, 2.07038f, 2.18638f, 2.29688f, 2.40255f, 2.50391f, 2.60144f, 2.69551f, 2.78647f, 2.87458f, 2.96015f, 3.04333f, 3.12431f, 3.20326f}; - - integer = floor(2*x); - ind = (int)integer; - if (ind<0) - return 1; - if (ind>19) - return 1+.1296/x; - frac = 2*x-integer; - return ((1-frac)*table[ind] + frac*table[ind+1])/sqrt(x+.0001f); + x = EXPIN_SCALING_1*xx; + integer = floor(2*x); + ind = (int)integer; + if (ind<0) + return FRAC_SCALING; + if (ind>19) + return FRAC_SCALING*(1+.1296/x); + frac = 2*x-integer; + return FRAC_SCALING*((1-frac)*table[ind] + frac*table[ind+1])/sqrt(x+.0001f); } -static inline float qcurve(float x) +static inline spx_word16_t qcurve(spx_word16_t x) { - return 1.f/(1.f+.1f/(x*x)); + return 1.f/(1.f+.15f/(SNR_SCALING_1*x)); +} + +static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, spx_word32_t *noise, spx_word32_t *echo, spx_word16_t *gain_floor, int len) +{ + int i; + float echo_floor; + float noise_floor; + + noise_floor = exp(.2302585f*noise_suppress); + echo_floor = exp(.2302585f*effective_echo_suppress); + + /* Compute the gain floor based on different floors for the background noise and residual echo */ + for (i=0;i<len;i++) + gain_floor[i] = FRAC_SCALING*sqrt(noise_floor*PSHR32(noise[i],NOISE_SHIFT) + echo_floor*echo[i])/sqrt(1+PSHR32(noise[i],NOISE_SHIFT) + echo[i]); } +#endif SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate) { int i; - int N, N3, N4; + int N, N3, N4, M; SpeexPreprocessState *st = (SpeexPreprocessState *)speex_alloc(sizeof(SpeexPreprocessState)); st->frame_size = frame_size; @@ -153,49 +426,51 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r st->sampling_rate = sampling_rate; st->denoise_enabled = 1; - st->agc_enabled = 0; - st->agc_level = 8000; st->vad_enabled = 0; st->dereverb_enabled = 0; - st->reverb_decay = .5; - st->reverb_level = .2; - - st->speech_prob_start = SPEEX_PROB_START_DEFAULT; - st->speech_prob_continue = SPEEX_PROB_CONTINUE_DEFAULT; - - st->frame = (float*)speex_alloc(2*N*sizeof(float)); - st->ps = (float*)speex_alloc(N*sizeof(float)); - st->gain2 = (float*)speex_alloc(N*sizeof(float)); - st->window = (float*)speex_alloc(2*N*sizeof(float)); - st->noise = (float*)speex_alloc(N*sizeof(float)); - st->reverb_estimate = (float*)speex_alloc(N*sizeof(float)); - st->old_ps = (float*)speex_alloc(N*sizeof(float)); - st->gain = (float*)speex_alloc(N*sizeof(float)); - st->prior = (float*)speex_alloc(N*sizeof(float)); - st->post = (float*)speex_alloc(N*sizeof(float)); - st->loudness_weight = (float*)speex_alloc(N*sizeof(float)); - st->inbuf = (float*)speex_alloc(N3*sizeof(float)); - st->outbuf = (float*)speex_alloc(N3*sizeof(float)); - st->echo_noise = (float*)speex_alloc(N*sizeof(float)); - - st->S = (float*)speex_alloc(N*sizeof(float)); - st->Smin = (float*)speex_alloc(N*sizeof(float)); - st->Stmp = (float*)speex_alloc(N*sizeof(float)); - st->update_prob = (float*)speex_alloc(N*sizeof(float)); + st->reverb_decay = 0; + st->reverb_level = 0; + st->noise_suppress = NOISE_SUPPRESS_DEFAULT; + st->echo_suppress = ECHO_SUPPRESS_DEFAULT; + st->echo_suppress_active = ECHO_SUPPRESS_ACTIVE_DEFAULT; - st->zeta = (float*)speex_alloc(N*sizeof(float)); - st->Zpeak = 0; - st->Zlast = 0; + st->speech_prob_start = SPEECH_PROB_START_DEFAULT; + st->speech_prob_continue = SPEECH_PROB_CONTINUE_DEFAULT; - st->noise_bands = (float*)speex_alloc(NB_BANDS*sizeof(float)); - st->noise_bands2 = (float*)speex_alloc(NB_BANDS*sizeof(float)); - st->speech_bands = (float*)speex_alloc(NB_BANDS*sizeof(float)); - st->speech_bands2 = (float*)speex_alloc(NB_BANDS*sizeof(float)); - st->noise_bandsN = st->speech_bandsN = 1; + st->echo_state = NULL; + + st->nbands = NB_BANDS; + M = st->nbands; + st->bank = filterbank_new(M, sampling_rate, N, 1); + + st->frame = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); + st->window = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); + st->ft = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); + + st->ps = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); + st->noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); + st->echo_noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); + st->residual_echo = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); + st->reverb_estimate = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); + st->old_ps = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); + st->prior = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); + st->post = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); + st->gain = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); + st->gain2 = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); + st->gain_floor = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); + st->zeta = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); + + st->S = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); + st->Smin = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); + st->Stmp = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); + st->update_prob = (int*)speex_alloc(N*sizeof(int)); + + st->inbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t)); + st->outbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t)); conj_window(st->window, 2*N3); for (i=2*N3;i<2*st->ps_size;i++) - st->window[i]=1; + st->window[i]=Q15_ONE; if (N4>0) { @@ -205,51 +480,62 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r st->window[i+N3]=1; } } - for (i=0;i<N;i++) + for (i=0;i<N+M;i++) { - st->noise[i]=1e4; - st->reverb_estimate[i]=0.; - st->old_ps[i]=1e4; - st->gain[i]=1; - st->post[i]=1; - st->prior[i]=1; + st->noise[i]=QCONST32(1.f,NOISE_SHIFT); + st->reverb_estimate[i]=0; + st->old_ps[i]=1; + st->gain[i]=Q15_ONE; + st->post[i]=SHL16(1, SNR_SHIFT); + st->prior[i]=SHL16(1, SNR_SHIFT); } + for (i=0;i<N;i++) + st->update_prob[i] = 1; for (i=0;i<N3;i++) { st->inbuf[i]=0; st->outbuf[i]=0; } - +#ifndef FIXED_POINT + st->agc_enabled = 0; + st->agc_level = 8000; + st->loudness_weight = (float*)speex_alloc(N*sizeof(float)); for (i=0;i<N;i++) { float ff=((float)i)*.5*sampling_rate/((float)N); + /*st->loudness_weight[i] = .5f*(1.f/(1.f+ff/8000.f))+1.f*exp(-.5f*(ff-3800.f)*(ff-3800.f)/9e5f);*/ st->loudness_weight[i] = .35f-.35f*ff/16000.f+.73f*exp(-.5f*(ff-3800)*(ff-3800)/9e5f); if (st->loudness_weight[i]<.01f) st->loudness_weight[i]=.01f; st->loudness_weight[i] *= st->loudness_weight[i]; } - - st->speech_prob = 0; - st->last_speech = 1000; - st->loudness = pow(6000,LOUDNESS_EXP); - st->loudness2 = 6000; + /*st->loudness = pow(AMP_SCALE*st->agc_level,LOUDNESS_EXP);*/ + st->loudness = 1e-15; + st->agc_gain = 1; st->nb_loudness_adapt = 0; + st->max_gain = 30; + st->max_increase_step = exp(0.11513f * 12.*st->frame_size / st->sampling_rate); + st->max_decrease_step = exp(-0.11513f * 40.*st->frame_size / st->sampling_rate); + st->prev_loudness = 1; + st->init_max = 1; +#endif + st->was_speech = 0; - st->fft_lookup = (struct drft_lookup*)speex_alloc(sizeof(struct drft_lookup)); - spx_drft_init(st->fft_lookup,2*N); + st->fft_lookup = spx_fft_init(2*N); st->nb_adapt=0; - st->consec_noise=0; - st->nb_preprocess=0; + st->min_count=0; return st; } void speex_preprocess_state_destroy(SpeexPreprocessState *st) { speex_free(st->frame); + speex_free(st->ft); speex_free(st->ps); speex_free(st->gain2); + speex_free(st->gain_floor); speex_free(st->window); speex_free(st->noise); speex_free(st->reverb_estimate); @@ -257,8 +543,11 @@ void speex_preprocess_state_destroy(SpeexPreprocessState *st) speex_free(st->gain); speex_free(st->prior); speex_free(st->post); +#ifndef FIXED_POINT speex_free(st->loudness_weight); +#endif speex_free(st->echo_noise); + speex_free(st->residual_echo); speex_free(st->S); speex_free(st->Smin); @@ -266,298 +555,65 @@ void speex_preprocess_state_destroy(SpeexPreprocessState *st) speex_free(st->update_prob); speex_free(st->zeta); - speex_free(st->noise_bands); - speex_free(st->noise_bands2); - speex_free(st->speech_bands); - speex_free(st->speech_bands2); - speex_free(st->inbuf); speex_free(st->outbuf); - spx_drft_clear(st->fft_lookup); - speex_free(st->fft_lookup); - + spx_fft_destroy(st->fft_lookup); + filterbank_destroy(st->bank); speex_free(st); } -static void update_noise(SpeexPreprocessState *st, float *ps, spx_int32_t *echo) +/* FIXME: The AGC doesn't work yet with fixed-point*/ +#ifndef FIXED_POINT +static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx_word16_t *ft) { int i; - float beta; - st->nb_adapt++; - beta=1.0f/st->nb_adapt; - if (beta < .05f) - beta=.05f; - - if (!echo) - { - for (i=0;i<st->ps_size;i++) - st->noise[i] = (1.f-beta)*st->noise[i] + beta*ps[i]; - } else { - for (i=0;i<st->ps_size;i++) - st->noise[i] = (1.f-beta)*st->noise[i] + beta*max(1.f,ps[i]-st->frame_size*st->frame_size*1.0*echo[i]); -#if 0 - for (i=0;i<st->ps_size;i++) - st->noise[i] = 0; -#endif - } -} - -static int speex_compute_vad(SpeexPreprocessState *st, float *ps, float mean_prior, float mean_post) -{ - int i, is_speech=0; int N = st->ps_size; - float scale=.5f/N; - - /* FIXME: Clean this up a bit */ - { - float bands[NB_BANDS]; - int j; - float p0, p1; - float tot_loudness=0; - float x = sqrt(mean_post); - - for (i=5;i<N-10;i++) - { - tot_loudness += scale*st->ps[i] * st->loudness_weight[i]; - } - - for (i=0;i<NB_BANDS;i++) - { - bands[i]=1e4f; - for (j=i*N/NB_BANDS;j<(i+1)*N/NB_BANDS;j++) - { - bands[i] += ps[j]; - } - bands[i]=log(bands[i]); - } - - /*p1 = .0005+.6*exp(-.5*(x-.4)*(x-.4)*11)+.1*exp(-1.2*x); - if (x<1.5) - p0=.1*exp(2*(x-1.5)); - else - p0=.02+.1*exp(-.2*(x-1.5)); - */ - - p0=1.f/(1.f+exp(3.f*(1.5f-x))); - p1=1.f-p0; - - /*fprintf (stderr, "%f %f ", p0, p1);*/ - /*p0 *= .99*st->speech_prob + .01*(1-st->speech_prob); - p1 *= .01*st->speech_prob + .99*(1-st->speech_prob); - - st->speech_prob = p0/(p1+p0); - */ - - if (st->noise_bandsN < 50 || st->speech_bandsN < 50) - { - if (mean_post > 5.f) - { - float adapt = 1./st->speech_bandsN++; - if (adapt<.005f) - adapt = .005f; - for (i=0;i<NB_BANDS;i++) - { - st->speech_bands[i] = (1.f-adapt)*st->speech_bands[i] + adapt*bands[i]; - /*st->speech_bands2[i] = (1-adapt)*st->speech_bands2[i] + adapt*bands[i]*bands[i];*/ - st->speech_bands2[i] = (1.f-adapt)*st->speech_bands2[i] + adapt*(bands[i]-st->speech_bands[i])*(bands[i]-st->speech_bands[i]); - } - } else { - float adapt = 1./st->noise_bandsN++; - if (adapt<.005f) - adapt = .005f; - for (i=0;i<NB_BANDS;i++) - { - st->noise_bands[i] = (1.f-adapt)*st->noise_bands[i] + adapt*bands[i]; - /*st->noise_bands2[i] = (1-adapt)*st->noise_bands2[i] + adapt*bands[i]*bands[i];*/ - st->noise_bands2[i] = (1.f-adapt)*st->noise_bands2[i] + adapt*(bands[i]-st->noise_bands[i])*(bands[i]-st->noise_bands[i]); - } - } - } - p0=p1=1; - for (i=0;i<NB_BANDS;i++) - { - float noise_var, speech_var; - float noise_mean, speech_mean; - float tmp1, tmp2, pr; - - /*noise_var = 1.01*st->noise_bands2[i] - st->noise_bands[i]*st->noise_bands[i]; - speech_var = 1.01*st->speech_bands2[i] - st->speech_bands[i]*st->speech_bands[i];*/ - noise_var = st->noise_bands2[i]; - speech_var = st->speech_bands2[i]; - if (noise_var < .1f) - noise_var = .1f; - if (speech_var < .1f) - speech_var = .1f; - - /*speech_var = sqrt(speech_var*noise_var); - noise_var = speech_var;*/ - if (noise_var < .05f*speech_var) - noise_var = .05f*speech_var; - if (speech_var < .05f*noise_var) - speech_var = .05f*noise_var; - - if (bands[i] < st->noise_bands[i]) - speech_var = noise_var; - if (bands[i] > st->speech_bands[i]) - noise_var = speech_var; - - speech_mean = st->speech_bands[i]; - noise_mean = st->noise_bands[i]; - if (noise_mean < speech_mean - 5.f) - noise_mean = speech_mean - 5.f; - - tmp1 = exp(-.5f*(bands[i]-speech_mean)*(bands[i]-speech_mean)/speech_var)/sqrt(2.f*M_PI*speech_var); - tmp2 = exp(-.5f*(bands[i]-noise_mean)*(bands[i]-noise_mean)/noise_var)/sqrt(2.f*M_PI*noise_var); - /*fprintf (stderr, "%f ", (float)(p0/(.01+p0+p1)));*/ - /*fprintf (stderr, "%f ", (float)(bands[i]));*/ - pr = tmp1/(1e-25+tmp1+tmp2); - /*if (bands[i] < st->noise_bands[i]) - pr=.01; - if (bands[i] > st->speech_bands[i] && pr < .995) - pr=.995;*/ - if (pr>.999f) - pr=.999f; - if (pr<.001f) - pr=.001f; - /*fprintf (stderr, "%f ", pr);*/ - p0 *= pr; - p1 *= (1-pr); - } - - p0 = pow(p0,.2); - p1 = pow(p1,.2); - -#if 1 - p0 *= 2.f; - p0=p0/(p1+p0); - if (st->last_speech>20) - { - float tmp = sqrt(tot_loudness)/st->loudness2; - tmp = 1.f-exp(-10.f*tmp); - if (p0>tmp) - p0=tmp; - } - p1=1-p0; -#else - if (sqrt(tot_loudness) < .6f*st->loudness2 && p0>15.f*p1) - p0=15.f*p1; - if (sqrt(tot_loudness) < .45f*st->loudness2 && p0>7.f*p1) - p0=7.f*p1; - if (sqrt(tot_loudness) < .3f*st->loudness2 && p0>3.f*p1) - p0=3.f*p1; - if (sqrt(tot_loudness) < .15f*st->loudness2 && p0>p1) - p0=p1; - /*fprintf (stderr, "%f %f ", (float)(sqrt(tot_loudness) /( .25*st->loudness2)), p0/(p1+p0));*/ -#endif - - p0 *= .99f*st->speech_prob + .01f*(1-st->speech_prob); - p1 *= .01f*st->speech_prob + .99f*(1-st->speech_prob); - - st->speech_prob = p0/(1e-25f+p1+p0); - /*fprintf (stderr, "%f %f %f ", tot_loudness, st->loudness2, st->speech_prob);*/ - - if (st->speech_prob > st->speech_prob_start - || (st->last_speech < 20 && st->speech_prob > st->speech_prob_continue)) - { - is_speech = 1; - st->last_speech = 0; - } else { - st->last_speech++; - if (st->last_speech<20) - is_speech = 1; - } - - if (st->noise_bandsN > 50 && st->speech_bandsN > 50) - { - if (mean_post > 5) - { - float adapt = 1./st->speech_bandsN++; - if (adapt<.005f) - adapt = .005f; - for (i=0;i<NB_BANDS;i++) - { - st->speech_bands[i] = (1-adapt)*st->speech_bands[i] + adapt*bands[i]; - /*st->speech_bands2[i] = (1-adapt)*st->speech_bands2[i] + adapt*bands[i]*bands[i];*/ - st->speech_bands2[i] = (1-adapt)*st->speech_bands2[i] + adapt*(bands[i]-st->speech_bands[i])*(bands[i]-st->speech_bands[i]); - } - } else { - float adapt = 1./st->noise_bandsN++; - if (adapt<.005f) - adapt = .005f; - for (i=0;i<NB_BANDS;i++) - { - st->noise_bands[i] = (1-adapt)*st->noise_bands[i] + adapt*bands[i]; - /*st->noise_bands2[i] = (1-adapt)*st->noise_bands2[i] + adapt*bands[i]*bands[i];*/ - st->noise_bands2[i] = (1-adapt)*st->noise_bands2[i] + adapt*(bands[i]-st->noise_bands[i])*(bands[i]-st->noise_bands[i]); - } - } - } - - - } - - return is_speech; -} - -static void speex_compute_agc(SpeexPreprocessState *st, float mean_prior) -{ - int i; - int N = st->ps_size; - float scale=.5f/N; - float agc_gain; - int freq_start, freq_end; - float active_bands = 0; - - freq_start = (int)(300.0f*2*N/st->sampling_rate); - freq_end = (int)(2000.0f*2*N/st->sampling_rate); - for (i=freq_start;i<freq_end;i++) + float target_gain; + float loudness=1.f; + float rate; + + for (i=2;i<N;i++) { - if (st->S[i] > 20.f*st->Smin[i]+1000.f) - active_bands+=1; + loudness += 2.f*N*st->ps[i]* st->loudness_weight[i]; } - active_bands /= (freq_end-freq_start+1); - - if (active_bands > .2f) + loudness=sqrt(loudness); + /*if (loudness < 2*pow(st->loudness, 1.0/LOUDNESS_EXP) && + loudness*2 > pow(st->loudness, 1.0/LOUDNESS_EXP))*/ + if (Pframe>.3f) { - float loudness=0.f; - float rate, rate2=.2f; st->nb_loudness_adapt++; - rate=2.0f/(1+st->nb_loudness_adapt); - if (rate < .05f) - rate = .05f; - if (rate < .1f && pow(loudness, LOUDNESS_EXP) > st->loudness) - rate = .1f; - if (rate < .2f && pow(loudness, LOUDNESS_EXP) > 3.f*st->loudness) - rate = .2f; - if (rate < .4f && pow(loudness, LOUDNESS_EXP) > 10.f*st->loudness) - rate = .4f; - - for (i=2;i<N;i++) - { - loudness += scale*st->ps[i] * st->gain2[i] * st->gain2[i] * st->loudness_weight[i]; - } - loudness=sqrt(loudness); - /*if (loudness < 2*pow(st->loudness, 1.0/LOUDNESS_EXP) && - loudness*2 > pow(st->loudness, 1.0/LOUDNESS_EXP))*/ - st->loudness = (1-rate)*st->loudness + (rate)*pow(loudness, LOUDNESS_EXP); - - st->loudness2 = (1-rate2)*st->loudness2 + rate2*pow(st->loudness, 1.0f/LOUDNESS_EXP); - - loudness = pow(st->loudness, 1.0f/LOUDNESS_EXP); - - /*fprintf (stderr, "%f %f %f\n", loudness, st->loudness2, rate);*/ + /*rate=2.0f*Pframe*Pframe/(1+st->nb_loudness_adapt);*/ + rate = .03*Pframe*Pframe; + st->loudness = (1-rate)*st->loudness + (rate)*pow(AMP_SCALE*loudness, LOUDNESS_EXP); + st->loudness_accum = (1-rate)*st->loudness_accum + rate; + if (st->init_max < st->max_gain && st->nb_adapt > 20) + st->init_max *= 1.f + .1f*Pframe*Pframe; } + /*printf ("%f %f %f %f\n", Pframe, loudness, pow(st->loudness, 1.0f/LOUDNESS_EXP), st->loudness2);*/ - agc_gain = st->agc_level/st->loudness2; - /*fprintf (stderr, "%f %f %f %f\n", active_bands, st->loudness, st->loudness2, agc_gain);*/ - if (agc_gain>200) - agc_gain = 200; + target_gain = AMP_SCALE*st->agc_level*pow(st->loudness/(1e-4+st->loudness_accum), -1.0f/LOUDNESS_EXP); - for (i=0;i<N;i++) - st->gain2[i] *= agc_gain; + if ((Pframe>.5 && st->nb_adapt > 20) || target_gain < st->agc_gain) + { + if (target_gain > st->max_increase_step*st->agc_gain) + target_gain = st->max_increase_step*st->agc_gain; + if (target_gain < st->max_decrease_step*st->agc_gain && loudness < 10*st->prev_loudness) + target_gain = st->max_decrease_step*st->agc_gain; + if (target_gain > st->max_gain) + target_gain = st->max_gain; + if (target_gain > st->init_max) + target_gain = st->init_max; + st->agc_gain = target_gain; + } + /*fprintf (stderr, "%f %f %f\n", loudness, (float)AMP_SCALE_1*pow(st->loudness, 1.0f/LOUDNESS_EXP), st->agc_gain);*/ + + for (i=0;i<2*N;i++) + ft[i] *= st->agc_gain; + st->prev_loudness = loudness; } +#endif static void preprocess_analysis(SpeexPreprocessState *st, spx_int16_t *x) { @@ -565,7 +621,7 @@ static void preprocess_analysis(SpeexPreprocessState *st, spx_int16_t *x) int N = st->ps_size; int N3 = 2*N - st->frame_size; int N4 = st->frame_size - N3; - float *ps=st->ps; + spx_word32_t *ps=st->ps; /* 'Build' input frame */ for (i=0;i<N3;i++) @@ -579,295 +635,333 @@ static void preprocess_analysis(SpeexPreprocessState *st, spx_int16_t *x) /* Windowing */ for (i=0;i<2*N;i++) - st->frame[i] *= st->window[i]; + st->frame[i] = MULT16_16_Q15(st->frame[i], st->window[i]); +#ifdef FIXED_POINT + { + spx_word16_t max_val=0; + for (i=0;i<2*N;i++) + max_val = MAX16(max_val, ABS16(st->frame[i])); + st->frame_shift = 14-spx_ilog2(EXTEND32(max_val)); + for (i=0;i<2*N;i++) + st->frame[i] = SHL16(st->frame[i], st->frame_shift); + } +#endif + /* Perform FFT */ - spx_drft_forward(st->fft_lookup, st->frame); - + spx_fft(st->fft_lookup, st->frame, st->ft); + /* Power spectrum */ - ps[0]=1; + ps[0]=MULT16_16(st->ft[0],st->ft[0]); for (i=1;i<N;i++) - ps[i]=1+st->frame[2*i-1]*st->frame[2*i-1] + st->frame[2*i]*st->frame[2*i]; + ps[i]=MULT16_16(st->ft[2*i-1],st->ft[2*i-1]) + MULT16_16(st->ft[2*i],st->ft[2*i]); + for (i=0;i<N;i++) + st->ps[i] = PSHR32(st->ps[i], 2*st->frame_shift); + filterbank_compute_bank32(st->bank, ps, ps+N); } static void update_noise_prob(SpeexPreprocessState *st) { int i; + int min_range; int N = st->ps_size; for (i=1;i<N-1;i++) - st->S[i] = 100.f+ .8f*st->S[i] + .05f*st->ps[i-1]+.1f*st->ps[i]+.05f*st->ps[i+1]; + st->S[i] = MULT16_32_Q15(QCONST16(.8f,15),st->S[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i-1]) + + MULT16_32_Q15(QCONST16(.1f,15),st->ps[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i+1]); + st->S[0] = MULT16_32_Q15(QCONST16(.8f,15),st->S[0]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[0]); + st->S[N-1] = MULT16_32_Q15(QCONST16(.8f,15),st->S[N-1]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[N-1]); - if (st->nb_preprocess<1) + if (st->nb_adapt==1) { - for (i=1;i<N-1;i++) - st->Smin[i] = st->Stmp[i] = st->S[i]+100.f; + for (i=0;i<N;i++) + st->Smin[i] = st->Stmp[i] = 0; } - if (st->nb_preprocess%200==0) + if (st->nb_adapt < 100) + min_range = 15; + else if (st->nb_adapt < 1000) + min_range = 50; + else if (st->nb_adapt < 10000) + min_range = 150; + else + min_range = 300; + if (st->min_count > min_range) { - for (i=1;i<N-1;i++) + st->min_count = 0; + for (i=0;i<N;i++) { - st->Smin[i] = min(st->Stmp[i], st->S[i]); + st->Smin[i] = MIN32(st->Stmp[i], st->S[i]); st->Stmp[i] = st->S[i]; } } else { - for (i=1;i<N-1;i++) + for (i=0;i<N;i++) { - st->Smin[i] = min(st->Smin[i], st->S[i]); - st->Stmp[i] = min(st->Stmp[i], st->S[i]); + st->Smin[i] = MIN32(st->Smin[i], st->S[i]); + st->Stmp[i] = MIN32(st->Stmp[i], st->S[i]); } } - for (i=1;i<N-1;i++) + for (i=0;i<N;i++) { - st->update_prob[i] *= .2f; - if (st->S[i] > 2.5*st->Smin[i]) - st->update_prob[i] += .8f; + if (MULT16_32_Q15(QCONST16(.4f,15),st->S[i]) > ADD32(st->Smin[i],EXTEND32(20))) + st->update_prob[i] = 1; + else + st->update_prob[i] = 0; /*fprintf (stderr, "%f ", st->S[i]/st->Smin[i]);*/ /*fprintf (stderr, "%f ", st->update_prob[i]);*/ } } -#define NOISE_OVERCOMPENS 1.4 +#define NOISE_OVERCOMPENS 1. + +void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len); int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo) { + return speex_preprocess_run(st, x); +} + +int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) +{ int i; - int is_speech=1; - float mean_post=0; - float mean_prior=0; + int M; int N = st->ps_size; int N3 = 2*N - st->frame_size; int N4 = st->frame_size - N3; - float scale=.5f/N; - float *ps=st->ps; - float Zframe=0, Pframe; - + spx_word32_t *ps=st->ps; + spx_word32_t Zframe; + spx_word16_t Pframe; + spx_word16_t beta, beta_1; + spx_word16_t effective_echo_suppress; + + st->nb_adapt++; + st->min_count++; + + beta = MAX16(QCONST16(.03,15),DIV32_16(Q15_ONE,st->nb_adapt)); + beta_1 = Q15_ONE-beta; + M = st->nbands; + /* Deal with residual echo if provided */ + if (st->echo_state) + { + speex_echo_get_residual(st->echo_state, st->residual_echo, N); +#ifndef FIXED_POINT + /* If there are NaNs or ridiculous values, it'll show up in the DC and we just reset everything to zero */ + if (!(st->residual_echo[0] >=0 && st->residual_echo[0]<N*1e9f)) + { + for (i=0;i<N;i++) + st->residual_echo[i] = 0; + } +#endif + for (i=0;i<N;i++) + st->echo_noise[i] = MAX32(MULT16_32_Q15(QCONST16(.6f,15),st->echo_noise[i]), st->residual_echo[i]); + filterbank_compute_bank32(st->bank, st->echo_noise, st->echo_noise+N); + } else { + for (i=0;i<N+M;i++) + st->echo_noise[i] = 0; + } preprocess_analysis(st, x); update_noise_prob(st); - st->nb_preprocess++; - - /* Noise estimation always updated for the 20 first times */ - if (st->nb_adapt<10) + /* Noise estimation always updated for the 10 first frames */ + /*if (st->nb_adapt<10) { - update_noise(st, ps, echo); + for (i=1;i<N-1;i++) + st->update_prob[i] = 0; } - - /* Deal with residual echo if provided */ - if (echo) - for (i=1;i<N;i++) - st->echo_noise[i] = (.3f*st->echo_noise[i] + st->frame_size*st->frame_size*1.0*echo[i]); - - /* Compute a posteriori SNR */ - for (i=1;i<N;i++) + */ + + /* Update the noise estimate for the frequencies where it can be */ + for (i=0;i<N;i++) { - float tot_noise = 1.f+ NOISE_OVERCOMPENS*st->noise[i] + st->echo_noise[i] + st->reverb_estimate[i]; - st->post[i] = ps[i]/tot_noise - 1.f; - if (st->post[i]>100.f) - st->post[i]=100.f; - /*if (st->post[i]<0) - st->post[i]=0;*/ - mean_post+=st->post[i]; + if (!st->update_prob[i] || st->ps[i] < PSHR32(st->noise[i], NOISE_SHIFT)) + st->noise[i] = MAX32(EXTEND32(0),MULT16_32_Q15(beta_1,st->noise[i]) + MULT16_32_Q15(beta,SHL32(st->ps[i],NOISE_SHIFT))); } - mean_post /= N; - if (mean_post<0.f) - mean_post=0.f; + filterbank_compute_bank32(st->bank, st->noise, st->noise+N); /* Special case for first frame */ if (st->nb_adapt==1) - for (i=1;i<N;i++) + for (i=0;i<N+M;i++) st->old_ps[i] = ps[i]; - /* Compute a priori SNR */ - { - /* A priori update rate */ - for (i=1;i<N;i++) - { - float gamma = .15+.85*st->prior[i]*st->prior[i]/((1+st->prior[i])*(1+st->prior[i])); - float tot_noise = 1.f+ NOISE_OVERCOMPENS*st->noise[i] + st->echo_noise[i] + st->reverb_estimate[i]; - /* A priori SNR update */ - st->prior[i] = gamma*max(0.0f,st->post[i]) + - (1.f-gamma)* (.8*st->gain[i]*st->gain[i]*st->old_ps[i]/tot_noise + .2*st->prior[i]); - - if (st->prior[i]>100.f) - st->prior[i]=100.f; - - mean_prior+=st->prior[i]; - } - } - mean_prior /= N; - -#if 0 - for (i=0;i<N;i++) - { - fprintf (stderr, "%f ", st->prior[i]); - } - fprintf (stderr, "\n"); -#endif - /*fprintf (stderr, "%f %f\n", mean_prior,mean_post);*/ - - if (st->nb_preprocess>=20) + /* Compute a posteriori SNR */ + for (i=0;i<N+M;i++) { - int do_update = 0; - float noise_ener=0, sig_ener=0; - /* If SNR is low (both a priori and a posteriori), update the noise estimate*/ - /*if (mean_prior<.23 && mean_post < .5)*/ - if (mean_prior<.23f && mean_post < .5f) - do_update = 1; - for (i=1;i<N;i++) - { - noise_ener += st->noise[i]; - sig_ener += ps[i]; - } - if (noise_ener > 3.f*sig_ener) - do_update = 1; - /*do_update = 0;*/ - if (do_update) - { - st->consec_noise++; - } else { - st->consec_noise=0; - } + spx_word16_t gamma; + + /* Total noise estimate including residual echo and reverberation */ + spx_word32_t tot_noise = ADD32(ADD32(ADD32(EXTEND32(1), PSHR32(st->noise[i],NOISE_SHIFT)) , st->echo_noise[i]) , st->reverb_estimate[i]); + + /* A posteriori SNR = ps/noise - 1*/ + st->post[i] = SUB16(DIV32_16_Q8(ps[i],tot_noise), QCONST16(1.f,SNR_SHIFT)); + st->post[i]=MIN16(st->post[i], QCONST16(100.f,SNR_SHIFT)); + + /* Computing update gamma = .1 + .9*(old/(old+noise))^2 */ + gamma = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.89f,15),SQR16_Q15(DIV32_16_Q15(st->old_ps[i],ADD32(st->old_ps[i],tot_noise)))); + + /* A priori SNR update = gamma*max(0,post) + (1-gamma)*old/noise */ + st->prior[i] = EXTRACT16(PSHR32(ADD32(MULT16_16(gamma,MAX16(0,st->post[i])), MULT16_16(Q15_ONE-gamma,DIV32_16_Q8(st->old_ps[i],tot_noise))), 15)); + st->prior[i]=MIN16(st->prior[i], QCONST16(100.f,SNR_SHIFT)); } - if (st->vad_enabled) - is_speech = speex_compute_vad(st, ps, mean_prior, mean_post); - + /*print_vec(st->post, N+M, "");*/ - if (st->consec_noise>=3) + /* Recursive average of the a priori SNR. A bit smoothed for the psd components */ + st->zeta[0] = PSHR32(ADD32(MULT16_16(QCONST16(.7f,15),st->zeta[0]), MULT16_16(QCONST16(.3f,15),st->prior[0])),15); + for (i=1;i<N-1;i++) + st->zeta[i] = PSHR32(ADD32(ADD32(ADD32(MULT16_16(QCONST16(.7f,15),st->zeta[i]), MULT16_16(QCONST16(.15f,15),st->prior[i])), + MULT16_16(QCONST16(.075f,15),st->prior[i-1])), MULT16_16(QCONST16(.075f,15),st->prior[i+1])),15); + for (i=N-1;i<N+M;i++) + st->zeta[i] = PSHR32(ADD32(MULT16_16(QCONST16(.7f,15),st->zeta[i]), MULT16_16(QCONST16(.3f,15),st->prior[i])),15); + + /* Speech probability of presence for the entire frame is based on the average filterbank a priori SNR */ + Zframe = 0; + for (i=N;i<N+M;i++) + Zframe = ADD32(Zframe, EXTEND32(st->zeta[i])); + Pframe = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.899f,15),qcurve(DIV32_16(Zframe,st->nbands))); + + effective_echo_suppress = EXTRACT16(PSHR32(ADD32(MULT16_16(SUB16(Q15_ONE,Pframe), st->echo_suppress), MULT16_16(Pframe, st->echo_suppress_active)),15)); + + compute_gain_floor(st->noise_suppress, effective_echo_suppress, st->noise+N, st->echo_noise+N, st->gain_floor+N, M); + + /* Compute Ephraim & Malah gain speech probability of presence for each critical band (Bark scale) + Technically this is actually wrong because the EM gaim assumes a slightly different probability + distribution */ + for (i=N;i<N+M;i++) { - update_noise(st, st->old_ps, echo); - } else { - for (i=1;i<N-1;i++) - { - if (st->update_prob[i]<.5f/* || st->ps[i] < st->noise[i]*/) - { - if (echo) - st->noise[i] = .95f*st->noise[i] + .05f*max(1.0f,st->ps[i]-st->frame_size*st->frame_size*1.0*echo[i]); - else - st->noise[i] = .95f*st->noise[i] + .05f*st->ps[i]; - } - } - } + /* See EM and Cohen papers*/ + spx_word32_t theta; + /* Gain from hypergeometric function */ + spx_word32_t MM; + /* Weiner filter gain */ + spx_word16_t prior_ratio; + /* a priority probability of speech presence based on Bark sub-band alone */ + spx_word16_t P1; + /* Speech absence a priori probability (considering sub-band and frame) */ + spx_word16_t q; +#ifdef FIXED_POINT + spx_word16_t tmp; +#endif + + prior_ratio = PDIV32_16(SHL32(EXTEND32(st->prior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT))); + theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT)); - for (i=1;i<N;i++) - { - st->zeta[i] = .7f*st->zeta[i] + .3f*st->prior[i]; + MM = hypergeom_gain(theta); + /* Gain with bound */ + st->gain[i] = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM))); + /* Save old Bark power spectrum */ + st->old_ps[i] = MULT16_32_P15(QCONST16(.2f,15),st->old_ps[i]) + MULT16_32_P15(MULT16_16_P15(QCONST16(.8f,15),SQR16_Q15(st->gain[i])),ps[i]); + + P1 = QCONST16(.199f,15)+MULT16_16_Q15(QCONST16(.8f,15),qcurve (st->zeta[i])); + q = Q15_ONE-MULT16_16_Q15(Pframe,P1); +#ifdef FIXED_POINT + theta = MIN32(theta, EXTEND32(32767)); +/*Q8*/tmp = MULT16_16_Q15((SHL32(1,SNR_SHIFT)+st->prior[i]),EXTRACT16(MIN32(Q15ONE,SHR32(spx_exp(-EXTRACT16(theta)),1)))); + tmp = MIN16(QCONST16(3.,SNR_SHIFT), tmp); /* Prevent overflows in the next line*/ +/*Q8*/tmp = EXTRACT16(PSHR32(MULT16_16(PDIV32_16(SHL32(EXTEND32(q),8),(Q15_ONE-q)),tmp),8)); + st->gain2[i]=DIV32_16(SHL32(EXTEND32(32767),SNR_SHIFT), ADD16(256,tmp)); +#else + st->gain2[i]=1/(1.f + (q/(1.f-q))*(1+st->prior[i])*exp(-theta)); +#endif } - + /* Convert the EM gains and speech prob to linear frequency */ + filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2); + filterbank_compute_psd16(st->bank,st->gain+N, st->gain); + + /* Use 1 for linear gain resolution (best) or 0 for Bark gain resolution (faster) */ + if (1) { - int freq_start = (int)(300.0f*2.f*N/st->sampling_rate); - int freq_end = (int)(2000.0f*2.f*N/st->sampling_rate); - for (i=freq_start;i<freq_end;i++) + filterbank_compute_psd16(st->bank,st->gain_floor+N, st->gain_floor); + + /* Compute gain according to the Ephraim-Malah algorithm -- linear frequency */ + for (i=0;i<N;i++) { - Zframe += st->zeta[i]; - } - Zframe /= (freq_end-freq_start); - } - st->Zlast = Zframe; - - Pframe = qcurve(Zframe); + spx_word32_t MM; + spx_word32_t theta; + spx_word16_t prior_ratio; + spx_word16_t tmp; + spx_word16_t p; + spx_word16_t g; + + /* Wiener filter gain */ + prior_ratio = PDIV32_16(SHL32(EXTEND32(st->prior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT))); + theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT)); + + /* Optimal estimator for loudness domain */ + MM = hypergeom_gain(theta); + /* EM gain with bound */ + g = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM))); + /* Interpolated speech probability of presence */ + p = st->gain2[i]; + + /* Constrain the gain to be close to the Bark scale gain */ + if (MULT16_16_Q15(QCONST16(.333f,15),g) > st->gain[i]) + g = MULT16_16(3,st->gain[i]); + st->gain[i] = g; + + /* Save old power spectrum */ + st->old_ps[i] = MULT16_32_P15(QCONST16(.2f,15),st->old_ps[i]) + MULT16_32_P15(MULT16_16_P15(QCONST16(.8f,15),SQR16_Q15(st->gain[i])),ps[i]); + + /* Apply gain floor */ + if (st->gain[i] < st->gain_floor[i]) + st->gain[i] = st->gain_floor[i]; - /*fprintf (stderr, "%f\n", Pframe);*/ - /* Compute gain according to the Ephraim-Malah algorithm */ - for (i=1;i<N;i++) - { - float MM; - float theta; - float prior_ratio; - float p, q; - float zeta1; - float P1; - - prior_ratio = st->prior[i]/(1.0001f+st->prior[i]); - theta = (1.f+st->post[i])*prior_ratio; - - if (i==1 || i==N-1) - zeta1 = st->zeta[i]; - else - zeta1 = .25f*st->zeta[i-1] + .5f*st->zeta[i] + .25f*st->zeta[i+1]; - P1 = qcurve (zeta1); - - /* FIXME: add global prob (P2) */ - q = 1-Pframe*P1; - q = 1-P1; - if (q>.95f) - q=.95f; - p=1.f/(1.f + (q/(1.f-q))*(1.f+st->prior[i])*exp(-theta)); - /*p=1;*/ - - /* Optimal estimator for loudness domain */ - MM = hypergeom_gain(theta); + /* Exponential decay model for reverberation (unused) */ + /*st->reverb_estimate[i] = st->reverb_decay*st->reverb_estimate[i] + st->reverb_decay*st->reverb_level*st->gain[i]*st->gain[i]*st->ps[i];*/ + + /* Take into account speech probability of presence (loudness domain MMSE estimator) */ + /* gain2 = [p*sqrt(gain)+(1-p)*sqrt(gain _floor) ]^2 */ + tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15))); + st->gain2[i]=SQR16_Q15(tmp); - st->gain[i] = prior_ratio * MM; - /*Put some (very arbitraty) limit on the gain*/ - if (st->gain[i]>2.f) - { - st->gain[i]=2.f; + /* Use this if you want a log-domain MMSE estimator instead */ + /*st->gain2[i] = pow(st->gain[i], p) * pow(st->gain_floor[i],1.f-p);*/ } - - st->reverb_estimate[i] = st->reverb_decay*st->reverb_estimate[i] + st->reverb_decay*st->reverb_level*st->gain[i]*st->gain[i]*st->ps[i]; - if (st->denoise_enabled) + } else { + for (i=N;i<N+M;i++) { - /*st->gain2[i] = p*p*st->gain[i];*/ - st->gain2[i]=(p*sqrt(st->gain[i])+.2*(1-p)) * (p*sqrt(st->gain[i])+.2*(1-p)); - /*st->gain2[i] = pow(st->gain[i], p) * pow(.1f,1.f-p);*/ - } else { - st->gain2[i]=1.f; + spx_word16_t tmp; + spx_word16_t p = st->gain2[i]; + st->gain[i] = MAX16(st->gain[i], st->gain_floor[i]); + tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15))); + st->gain2[i]=SQR16_Q15(tmp); } + filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2); } - st->gain2[0]=st->gain[0]=0.f; - st->gain2[N-1]=st->gain[N-1]=0.f; - /* - for (i=30;i<N-2;i++) + /* If noise suppression is off, don't apply the gain (but then why call this in the first place!) */ + if (!st->denoise_enabled) { - st->gain[i] = st->gain2[i]*st->gain2[i] + (1-st->gain2[i])*.333*(.6*st->gain2[i-1]+st->gain2[i]+.6*st->gain2[i+1]+.4*st->gain2[i-2]+.4*st->gain2[i+2]); - } - for (i=30;i<N-2;i++) - st->gain2[i] = st->gain[i]; - */ - if (st->agc_enabled) - speex_compute_agc(st, mean_prior); - -#if 0 - if (!is_speech) - { - for (i=0;i<N;i++) - st->gain2[i] = 0; + for (i=0;i<N+M;i++) + st->gain2[i]=Q15_ONE; } -#if 0 - else { - for (i=0;i<N;i++) - st->gain2[i] = 1; - } -#endif -#endif - + /* Apply computed gain */ for (i=1;i<N;i++) { - st->frame[2*i-1] *= st->gain2[i]; - st->frame[2*i] *= st->gain2[i]; + st->ft[2*i-1] = MULT16_16_P15(st->gain2[i],st->ft[2*i-1]); + st->ft[2*i] = MULT16_16_P15(st->gain2[i],st->ft[2*i]); } - - /* Get rid of the DC and very low frequencies */ - st->frame[0]=0; - st->frame[1]=0; - st->frame[2]=0; - /* Nyquist frequency is mostly useless too */ - st->frame[2*N-1]=0; + st->ft[0] = MULT16_16_P15(st->gain2[0],st->ft[0]); + st->ft[2*N-1] = MULT16_16_P15(st->gain2[N-1],st->ft[2*N-1]); + + /*FIXME: This *will* not work for fixed-point */ +#ifndef FIXED_POINT + if (st->agc_enabled) + speex_compute_agc(st, Pframe, st->ft); +#endif /* Inverse FFT with 1/N scaling */ - spx_drft_backward(st->fft_lookup, st->frame); - + spx_ifft(st->fft_lookup, st->ft, st->frame); + /* Scale back to original (lower) amplitude */ for (i=0;i<2*N;i++) - st->frame[i] *= scale; + st->frame[i] = PSHR16(st->frame[i], st->frame_shift); + /*FIXME: This *will* not work for fixed-point */ +#ifndef FIXED_POINT + if (st->agc_enabled) { float max_sample=0; for (i=0;i<2*N;i++) @@ -880,9 +974,11 @@ int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo st->frame[i] *= damp; } } - +#endif + + /* Synthesis window (for WOLA) */ for (i=0;i<2*N;i++) - st->frame[i] *= st->window[i]; + st->frame[i] = MULT16_16_Q15(st->frame[i], st->window[i]); /* Perform overlap and add */ for (i=0;i<N3;i++) @@ -894,47 +990,55 @@ int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo for (i=0;i<N3;i++) st->outbuf[i] = st->frame[st->frame_size+i]; - /* Save old power spectrum */ - for (i=1;i<N;i++) - st->old_ps[i] = ps[i]; - - return is_speech; + /* FIXME: This VAD is a kludge */ + if (st->vad_enabled) + { + if (Pframe > st->speech_prob_start || (st->was_speech && Pframe > st->speech_prob_continue)) + { + st->was_speech=1; + return 1; + } else + { + st->was_speech=0; + return 0; + } + } else { + return 1; + } } -void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo) +void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x) { int i; int N = st->ps_size; int N3 = 2*N - st->frame_size; + int M; + spx_word32_t *ps=st->ps; - float *ps=st->ps; - + M = st->nbands; + st->min_count++; + preprocess_analysis(st, x); update_noise_prob(st); - - st->nb_preprocess++; for (i=1;i<N-1;i++) { - if (st->update_prob[i]<.5f || st->ps[i] < st->noise[i]) + if (!st->update_prob[i] || st->ps[i] < PSHR32(st->noise[i],NOISE_SHIFT)) { - if (echo) - st->noise[i] = .95f*st->noise[i] + .1f*max(1.0f,st->ps[i]-st->frame_size*st->frame_size*1.0*echo[i]); - else - st->noise[i] = .95f*st->noise[i] + .1f*st->ps[i]; + st->noise[i] = MULT16_32_Q15(QCONST16(.95f,15),st->noise[i]) + MULT16_32_Q15(QCONST16(.05f,15),SHL32(st->ps[i],NOISE_SHIFT)); } } for (i=0;i<N3;i++) - st->outbuf[i] = x[st->frame_size-N3+i]*st->window[st->frame_size+i]; + st->outbuf[i] = MULT16_16_Q15(x[st->frame_size-N3+i],st->window[st->frame_size+i]); /* Save old power spectrum */ - for (i=1;i<N;i++) + for (i=0;i<N+M;i++) st->old_ps[i] = ps[i]; - for (i=1;i<N;i++) - st->reverb_estimate[i] *= st->reverb_decay; + for (i=0;i<N;i++) + st->reverb_estimate[i] = MULT16_32_Q15(st->reverb_decay, st->reverb_estimate[i]); } @@ -946,17 +1050,17 @@ int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr) switch(request) { case SPEEX_PREPROCESS_SET_DENOISE: - st->denoise_enabled = (*(int*)ptr); + st->denoise_enabled = (*(spx_int32_t*)ptr); break; case SPEEX_PREPROCESS_GET_DENOISE: - (*(int*)ptr) = st->denoise_enabled; + (*(spx_int32_t*)ptr) = st->denoise_enabled; break; - +#ifndef FIXED_POINT case SPEEX_PREPROCESS_SET_AGC: - st->agc_enabled = (*(int*)ptr); + st->agc_enabled = (*(spx_int32_t*)ptr); break; case SPEEX_PREPROCESS_GET_AGC: - (*(int*)ptr) = st->agc_enabled; + (*(spx_int32_t*)ptr) = st->agc_enabled; break; case SPEEX_PREPROCESS_SET_AGC_LEVEL: @@ -969,21 +1073,40 @@ int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr) case SPEEX_PREPROCESS_GET_AGC_LEVEL: (*(float*)ptr) = st->agc_level; break; - + case SPEEX_PREPROCESS_SET_AGC_INCREMENT: + st->max_increase_step = exp(0.11513f * (*(spx_int32_t*)ptr)*st->frame_size / st->sampling_rate); + break; + case SPEEX_PREPROCESS_GET_AGC_INCREMENT: + (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->max_increase_step)*st->sampling_rate/st->frame_size); + break; + case SPEEX_PREPROCESS_SET_AGC_DECREMENT: + st->max_decrease_step = exp(0.11513f * (*(spx_int32_t*)ptr)*st->frame_size / st->sampling_rate); + break; + case SPEEX_PREPROCESS_GET_AGC_DECREMENT: + (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->max_decrease_step)*st->sampling_rate/st->frame_size); + break; + case SPEEX_PREPROCESS_SET_AGC_MAX_GAIN: + st->max_gain = exp(0.11513f * (*(spx_int32_t*)ptr)); + break; + case SPEEX_PREPROCESS_GET_AGC_MAX_GAIN: + (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->max_gain)); + break; +#endif case SPEEX_PREPROCESS_SET_VAD: - st->vad_enabled = (*(int*)ptr); + speex_warning("The VAD has been replaced by a hack pending a complete rewrite"); + st->vad_enabled = (*(spx_int32_t*)ptr); break; case SPEEX_PREPROCESS_GET_VAD: - (*(int*)ptr) = st->vad_enabled; + (*(spx_int32_t*)ptr) = st->vad_enabled; break; case SPEEX_PREPROCESS_SET_DEREVERB: - st->dereverb_enabled = (*(int*)ptr); + st->dereverb_enabled = (*(spx_int32_t*)ptr); for (i=0;i<st->ps_size;i++) st->reverb_estimate[i]=0; break; case SPEEX_PREPROCESS_GET_DEREVERB: - (*(int*)ptr) = st->dereverb_enabled; + (*(spx_int32_t*)ptr) = st->dereverb_enabled; break; case SPEEX_PREPROCESS_SET_DEREVERB_LEVEL: @@ -1001,24 +1124,47 @@ int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr) break; case SPEEX_PREPROCESS_SET_PROB_START: - st->speech_prob_start = (*(int*)ptr) / 100.0; - if ( st->speech_prob_start > 1 || st->speech_prob_start < 0 ) - st->speech_prob_start = SPEEX_PROB_START_DEFAULT; + *(spx_int32_t*)ptr = MIN32(Q15_ONE,MAX32(0, *(spx_int32_t*)ptr)); + st->speech_prob_start = DIV32_16(MULT16_16(32767,*(spx_int32_t*)ptr), 100); break; case SPEEX_PREPROCESS_GET_PROB_START: - (*(int*)ptr) = st->speech_prob_start * 100; + (*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob_start, 100); break; case SPEEX_PREPROCESS_SET_PROB_CONTINUE: - st->speech_prob_continue = (*(int*)ptr) / 100.0; - if ( st->speech_prob_continue > 1 || st->speech_prob_continue < 0 ) - st->speech_prob_continue = SPEEX_PROB_CONTINUE_DEFAULT; + *(spx_int32_t*)ptr = MIN32(Q15_ONE,MAX32(0, *(spx_int32_t*)ptr)); + st->speech_prob_continue = DIV32_16(MULT16_16(32767,*(spx_int32_t*)ptr), 100); break; case SPEEX_PREPROCESS_GET_PROB_CONTINUE: - (*(int*)ptr) = st->speech_prob_continue * 100; + (*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob_continue, 100); + break; + + case SPEEX_PREPROCESS_SET_NOISE_SUPPRESS: + st->noise_suppress = -ABS(*(spx_int32_t*)ptr); + break; + case SPEEX_PREPROCESS_GET_NOISE_SUPPRESS: + (*(spx_int32_t*)ptr) = st->noise_suppress; + break; + case SPEEX_PREPROCESS_SET_ECHO_SUPPRESS: + st->echo_suppress = -ABS(*(spx_int32_t*)ptr); + break; + case SPEEX_PREPROCESS_GET_ECHO_SUPPRESS: + (*(spx_int32_t*)ptr) = st->echo_suppress; + break; + case SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE: + st->echo_suppress_active = -ABS(*(spx_int32_t*)ptr); + break; + case SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE: + (*(spx_int32_t*)ptr) = st->echo_suppress_active; + break; + case SPEEX_PREPROCESS_SET_ECHO_STATE: + st->echo_state = (SpeexEchoState*)ptr; + break; + case SPEEX_PREPROCESS_GET_ECHO_STATE: + ptr = (void*)st->echo_state; break; - default: + default: speex_warning_int("Unknown speex_preprocess_ctl request: ", request); return -1; } diff --git a/libspeex/pseudofloat.h b/libspeex/pseudofloat.h index 9ff1b75..a6c4762 100644 --- a/libspeex/pseudofloat.h +++ b/libspeex/pseudofloat.h @@ -2,6 +2,15 @@ /** @file pseudofloat.h @brief Pseudo-floating point + * This header file provides a lightweight floating point type for + * use on fixed-point platforms when a large dynamic range is + * required. The new type is not compatible with the 32-bit IEEE format, + * it is not even remotely as accurate as 32-bit floats, and is not + * even guaranteed to produce even remotely correct results for code + * other than Speex. It makes all kinds of shortcuts that are acceptable + * for Speex, but may not be acceptable for your application. You're + * quite welcome to reuse this code and improve it, but don't assume + * it works out of the box. Most likely, it doesn't. */ /* Redistribution and use in source and binary forms, with or without @@ -65,18 +74,8 @@ static inline spx_float_t PSEUDOFLOAT(spx_int32_t x) spx_float_t r = {0,0}; return r; } - while (x>32767) - { - x >>= 1; - /*x *= .5;*/ - e++; - } - while (x<16383) - { - x <<= 1; - /*x *= 2;*/ - e--; - } + e = spx_ilog2(ABS32(x))-14; + x = VSHR32(x, e); if (sign) { spx_float_t r; @@ -167,9 +166,9 @@ static inline spx_float_t FLOAT_SUB(spx_float_t a, spx_float_t b) static inline int FLOAT_LT(spx_float_t a, spx_float_t b) { if (a.m==0) - return b.m<0; + return b.m>0; else if (b.m==0) - return a.m>0; + return a.m<0; if ((a).e > (b).e) return ((a).m>>1) < ((b).m>>MIN(15,(a).e-(b).e+1)); else @@ -205,6 +204,14 @@ static inline spx_float_t FLOAT_MULT(spx_float_t a, spx_float_t b) return r; } +static inline spx_float_t FLOAT_AMULT(spx_float_t a, spx_float_t b) +{ + spx_float_t r; + r.m = (spx_int16_t)((spx_int32_t)(a).m*(b).m>>15); + r.e = (a).e+(b).e+15; + return r; +} + static inline spx_float_t FLOAT_SHL(spx_float_t a, int b) { @@ -217,68 +224,53 @@ static inline spx_float_t FLOAT_SHL(spx_float_t a, int b) static inline spx_int16_t FLOAT_EXTRACT16(spx_float_t a) { if (a.e<0) - return EXTRACT16((EXTEND32(a.m)+(1<<(-a.e-1)))>>-a.e); + return EXTRACT16((EXTEND32(a.m)+(EXTEND32(1)<<(-a.e-1)))>>-a.e); else return a.m<<a.e; } -static inline spx_int32_t FLOAT_MUL32(spx_float_t a, spx_word32_t b) +static inline spx_int32_t FLOAT_EXTRACT32(spx_float_t a) { - if (a.e<-15) - return SHR32(MULT16_32_Q15(a.m, b),-a.e-15); + if (a.e<0) + return (EXTEND32(a.m)+(EXTEND32(1)<<(-a.e-1)))>>-a.e; else - return SHL32(MULT16_32_Q15(a.m, b),15+a.e); + return EXTEND32(a.m)<<a.e; +} + +static inline spx_int32_t FLOAT_MUL32(spx_float_t a, spx_word32_t b) +{ + return VSHR32(MULT16_32_Q15(a.m, b),-a.e-15); } static inline spx_float_t FLOAT_MUL32U(spx_word32_t a, spx_word32_t b) { - int e=0; + int e1, e2; spx_float_t r; - /* FIXME: Handle the sign */ - if (a==0) + if (a==0 || b==0) { return FLOAT_ZERO; } - while (a>32767) - { - a >>= 1; - e++; - } - while (a<16384) - { - a <<= 1; - e--; - } - while (b>32767) - { - b >>= 1; - e++; - } - while (b<16384) - { - b <<= 1; - e--; - } + e1 = spx_ilog2(ABS32(a)); + a = VSHR32(a, e1-14); + e2 = spx_ilog2(ABS32(b)); + b = VSHR32(b, e2-14); r.m = MULT16_16_Q15(a,b); - r.e = e+15; + r.e = e1+e2-13; return r; } +/* Do NOT attempt to divide by a negative number */ static inline spx_float_t FLOAT_DIV32_FLOAT(spx_word32_t a, spx_float_t b) { int e=0; spx_float_t r; - /* FIXME: Handle the sign */ if (a==0) { return FLOAT_ZERO; } - while (a<SHL32(EXTEND32(b.m),14)) - { - a <<= 1; - e--; - } - while (a>=SHL32(EXTEND32(b.m-1),15)) + e = spx_ilog2(ABS32(a))-spx_ilog2(b.m-1)-15; + a = VSHR32(a, e); + if (ABS32(a)>=SHL32(EXTEND32(b.m-1),15)) { a >>= 1; e++; @@ -289,41 +281,47 @@ static inline spx_float_t FLOAT_DIV32_FLOAT(spx_word32_t a, spx_float_t b) } +/* Do NOT attempt to divide by a negative number */ static inline spx_float_t FLOAT_DIV32(spx_word32_t a, spx_word32_t b) { - int e=0; + int e0=0,e=0; spx_float_t r; - /* FIXME: Handle the sign */ if (a==0) { return FLOAT_ZERO; } - while (b>32767) + if (b>32767) { - b >>= 1; - e--; + e0 = spx_ilog2(b)-14; + b = VSHR32(b, e0); + e0 = -e0; } - while (a<SHL32(b,14)) - { - a <<= 1; - e--; - } - while (a>=SHL32(b-1,15)) + e = spx_ilog2(ABS32(a))-spx_ilog2(b-1)-15; + a = VSHR32(a, e); + if (ABS32(a)>=SHL32(EXTEND32(b-1),15)) { a >>= 1; e++; } + e += e0; r.m = DIV32_16(a,b); r.e = e; return r; } +/* Do NOT attempt to divide by a negative number */ static inline spx_float_t FLOAT_DIVU(spx_float_t a, spx_float_t b) { int e=0; spx_int32_t num; spx_float_t r; + if (b.m<=0) + { + speex_warning_int("Attempted to divide by", b.m); + return FLOAT_ONE; + } num = a.m; + a.m = ABS16(a.m); while (a.m >= b.m) { e++; @@ -339,7 +337,7 @@ static inline spx_float_t FLOAT_SQRT(spx_float_t a) { spx_float_t r; spx_int32_t m; - m = a.m << 14; + m = SHL32(EXTEND32(a.m), 14); r.e = a.e - 14; if (r.e & 1) { @@ -359,9 +357,11 @@ static inline spx_float_t FLOAT_SQRT(spx_float_t a) #define FLOAT_HALF 0.5f #define PSEUDOFLOAT(x) (x) #define FLOAT_MULT(a,b) ((a)*(b)) +#define FLOAT_AMULT(a,b) ((a)*(b)) #define FLOAT_MUL32(a,b) ((a)*(b)) #define FLOAT_DIV32(a,b) ((a)/(b)) #define FLOAT_EXTRACT16(a) (a) +#define FLOAT_EXTRACT32(a) (a) #define FLOAT_ADD(a,b) ((a)+(b)) #define FLOAT_SUB(a,b) ((a)-(b)) #define REALFLOAT(x) (x) diff --git a/libspeex/quant_lsp.c b/libspeex/quant_lsp.c index bfca587..d907b98 100644 --- a/libspeex/quant_lsp.c +++ b/libspeex/quant_lsp.c @@ -417,7 +417,7 @@ void lsp_quant_48k(spx_lsp_t *lsp, spx_lsp_t *qlsp, int order, SpeexBits *bits) #ifdef FIXED_POINT for (i=0;i<order;i++) - qlsp[i]=PSHR(qlsp[i],2); + qlsp[i]=PSHR16(qlsp[i],2); #else for (i=0;i<order;i++) qlsp[i]=qlsp[i]*0.00097655; diff --git a/libspeex/resample.c b/libspeex/resample.c new file mode 100644 index 0000000..7135a29 --- /dev/null +++ b/libspeex/resample.c @@ -0,0 +1,1062 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: resample.c + Arbitrary resampling code + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ + +/* + The design goals of this code are: + - Very fast algorithm + - SIMD-friendly algorithm + - Low memory requirement + - Good *perceptual* quality (and not best SNR) + + The code is working, but it's in a very early stage, so it may have + artifacts, noise or subliminal messages from satan. Also, the API + isn't stable and I can actually promise that I *will* change the API + some time in the future. + +TODO list: + - Variable calculation resolution depending on quality setting + - Single vs double in float mode + - 16-bit vs 32-bit (sinc only) in fixed-point mode + - Make sure the filter update works even when changing params + after only a few samples procesed +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef OUTSIDE_SPEEX +#include <stdlib.h> +static void *speex_alloc (int size) {return calloc(size,1);} +static void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);} +static void speex_free (void *ptr) {free(ptr);} +#include "speex_resampler.h" +#include "arch.h" +#else /* OUTSIDE_SPEEX */ + +#include "speex/speex_resampler.h" +#include "misc.h" +#endif /* OUTSIDE_SPEEX */ + +#include <math.h> + +#ifndef M_PI +#define M_PI 3.14159263 +#endif + +#ifdef FIXED_POINT +#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) +#else +#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) +#endif + +/*#define float double*/ +#define FILTER_SIZE 64 +#define OVERSAMPLE 8 + +#define IMAX(a,b) ((a) > (b) ? (a) : (b)) + +#ifndef NULL +#define NULL 0 +#endif + +typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *); + +struct SpeexResamplerState_ { + spx_uint32_t in_rate; + spx_uint32_t out_rate; + spx_uint32_t num_rate; + spx_uint32_t den_rate; + + int quality; + spx_uint32_t nb_channels; + spx_uint32_t filt_len; + spx_uint32_t mem_alloc_size; + int int_advance; + int frac_advance; + float cutoff; + spx_uint32_t oversample; + int initialised; + int started; + + /* These are per-channel */ + spx_int32_t *last_sample; + spx_uint32_t *samp_frac_num; + spx_uint32_t *magic_samples; + + spx_word16_t *mem; + spx_word16_t *sinc_table; + spx_uint32_t sinc_table_length; + resampler_basic_func resampler_ptr; + + int in_stride; + int out_stride; +} ; + +static double kaiser12_table[68] = { + 0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076, + 0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014, + 0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601, + 0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014, + 0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490, + 0.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546, + 0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178, + 0.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947, + 0.02584161, 0.02127838, 0.01736250, 0.01402878, 0.01121463, 0.00886058, + 0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438, + 0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734, + 0.00001000, 0.00000000}; +/* +static double kaiser12_table[36] = { + 0.99440475, 1.00000000, 0.99440475, 0.97779076, 0.95066529, 0.91384741, + 0.86843014, 0.81573067, 0.75723148, 0.69451601, 0.62920216, 0.56287762, + 0.49704014, 0.43304576, 0.37206735, 0.31506490, 0.26276832, 0.21567274, + 0.17404546, 0.13794294, 0.10723616, 0.08164178, 0.06075685, 0.04409466, + 0.03111947, 0.02127838, 0.01402878, 0.00886058, 0.00531256, 0.00298291, + 0.00153438, 0.00069463, 0.00025272, 0.0000527734, 0.00000500, 0.00000000}; +*/ +static double kaiser10_table[36] = { + 0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446, + 0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347, + 0.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962, + 0.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451, + 0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739, + 0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000}; + +static double kaiser8_table[36] = { + 0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200, + 0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126, + 0.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272, + 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758, + 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490, + 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000}; + +static double kaiser6_table[36] = { + 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003, + 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565, + 0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561, + 0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058, + 0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600, + 0.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000}; + +struct FuncDef { + double *table; + int oversample; +}; + +static struct FuncDef _KAISER12 = {kaiser12_table, 64}; +#define KAISER12 (&_KAISER12) +/*static struct FuncDef _KAISER12 = {kaiser12_table, 32}; +#define KAISER12 (&_KAISER12)*/ +static struct FuncDef _KAISER10 = {kaiser10_table, 32}; +#define KAISER10 (&_KAISER10) +static struct FuncDef _KAISER8 = {kaiser8_table, 32}; +#define KAISER8 (&_KAISER8) +static struct FuncDef _KAISER6 = {kaiser6_table, 32}; +#define KAISER6 (&_KAISER6) + +struct QualityMapping { + int base_length; + int oversample; + float downsample_bandwidth; + float upsample_bandwidth; + struct FuncDef *window_func; +}; + + +/* This table maps conversion quality to internal parameters. There are two + reasons that explain why the up-sampling bandwidth is larger than the + down-sampling bandwidth: + 1) When up-sampling, we can assume that the spectrum is already attenuated + close to the Nyquist rate (from an A/D or a previous resampling filter) + 2) Any aliasing that occurs very close to the Nyquist rate will be masked + by the sinusoids/noise just below the Nyquist rate (guaranteed only for + up-sampling). +*/ +static const struct QualityMapping quality_map[11] = { + { 8, 4, 0.830f, 0.860f, KAISER6 }, /* Q0 */ + { 16, 4, 0.850f, 0.880f, KAISER6 }, /* Q1 */ + { 32, 4, 0.882f, 0.910f, KAISER6 }, /* Q2 */ /* 82.3% cutoff ( ~60 dB stop) 6 */ + { 48, 8, 0.895f, 0.917f, KAISER8 }, /* Q3 */ /* 84.9% cutoff ( ~80 dB stop) 8 */ + { 64, 8, 0.921f, 0.940f, KAISER8 }, /* Q4 */ /* 88.7% cutoff ( ~80 dB stop) 8 */ + { 80, 16, 0.922f, 0.940f, KAISER10}, /* Q5 */ /* 89.1% cutoff (~100 dB stop) 10 */ + { 96, 16, 0.940f, 0.945f, KAISER10}, /* Q6 */ /* 91.5% cutoff (~100 dB stop) 10 */ + {128, 16, 0.950f, 0.950f, KAISER10}, /* Q7 */ /* 93.1% cutoff (~100 dB stop) 10 */ + {160, 16, 0.960f, 0.960f, KAISER10}, /* Q8 */ /* 94.5% cutoff (~100 dB stop) 10 */ + {192, 32, 0.968f, 0.968f, KAISER12}, /* Q9 */ /* 95.5% cutoff (~100 dB stop) 10 */ + {256, 32, 0.975f, 0.975f, KAISER12}, /* Q10 */ /* 96.6% cutoff (~100 dB stop) 10 */ +}; +/*8,24,40,56,80,104,128,160,200,256,320*/ +static double compute_func(float x, struct FuncDef *func) +{ + float y, frac; + double interp[4]; + int ind; + y = x*func->oversample; + ind = (int)floor(y); + frac = (y-ind); + /* CSE with handle the repeated powers */ + interp[3] = -0.1666666667*frac + 0.1666666667*(frac*frac*frac); + interp[2] = frac + 0.5*(frac*frac) - 0.5*(frac*frac*frac); + /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/ + interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac); + /* Just to make sure we don't have rounding problems */ + interp[1] = 1.f-interp[3]-interp[2]-interp[0]; + + /*sum = frac*accum[1] + (1-frac)*accum[2];*/ + return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3]; +} + +#if 0 +#include <stdio.h> +int main(int argc, char **argv) +{ + int i; + for (i=0;i<256;i++) + { + printf ("%f\n", compute_func(i/256., KAISER12)); + } + return 0; +} +#endif + +#ifdef FIXED_POINT +/* The slow way of computing a sinc for the table. Should improve that some day */ +static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func) +{ + /*fprintf (stderr, "%f ", x);*/ + float xx = x * cutoff; + if (fabs(x)<1e-6f) + return WORD2INT(32768.*cutoff); + else if (fabs(x) > .5f*N) + return 0; + /*FIXME: Can it really be any slower than this? */ + return WORD2INT(32768.*cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func)); +} +#else +/* The slow way of computing a sinc for the table. Should improve that some day */ +static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func) +{ + /*fprintf (stderr, "%f ", x);*/ + float xx = x * cutoff; + if (fabs(x)<1e-6) + return cutoff; + else if (fabs(x) > .5*N) + return 0; + /*FIXME: Can it really be any slower than this? */ + return cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func); +} +#endif + +#ifdef FIXED_POINT +static void cubic_coef(spx_word16_t x, spx_word16_t interp[4]) +{ + /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation + but I know it's MMSE-optimal on a sinc */ + spx_word16_t x2, x3; + x2 = MULT16_16_P15(x, x); + x3 = MULT16_16_P15(x, x2); + interp[0] = PSHR32(MULT16_16(QCONST16(-0.16667f, 15),x) + MULT16_16(QCONST16(0.16667f, 15),x3),15); + interp[1] = EXTRACT16(EXTEND32(x) + SHR32(SUB32(EXTEND32(x2),EXTEND32(x3)),1)); + interp[3] = PSHR32(MULT16_16(QCONST16(-0.33333f, 15),x) + MULT16_16(QCONST16(.5f,15),x2) - MULT16_16(QCONST16(0.16667f, 15),x3),15); + /* Just to make sure we don't have rounding problems */ + interp[2] = Q15_ONE-interp[0]-interp[1]-interp[3]; + if (interp[2]<32767) + interp[2]+=1; +} +#else +static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4]) +{ + /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation + but I know it's MMSE-optimal on a sinc */ + interp[0] = -0.16667f*frac + 0.16667f*frac*frac*frac; + interp[1] = frac + 0.5f*frac*frac - 0.5f*frac*frac*frac; + /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/ + interp[3] = -0.33333f*frac + 0.5f*frac*frac - 0.16667f*frac*frac*frac; + /* Just to make sure we don't have rounding problems */ + interp[2] = 1.-interp[0]-interp[1]-interp[3]; +} +#endif + +static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + int N = st->filt_len; + int out_sample = 0; + spx_word16_t *mem; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + mem = st->mem + channel_index * st->mem_alloc_size; + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + int j; + spx_word32_t sum=0; + + /* We already have all the filter coefficients pre-computed in the table */ + const spx_word16_t *ptr; + /* Do the memory part */ + for (j=0;last_sample-N+1+j < 0;j++) + { + sum += MULT16_16(mem[last_sample+j],st->sinc_table[samp_frac_num*st->filt_len+j]); + } + + /* Do the new part */ + ptr = in+st->in_stride*(last_sample-N+1+j); + for (;j<N;j++) + { + sum += MULT16_16(*ptr,st->sinc_table[samp_frac_num*st->filt_len+j]); + ptr += st->in_stride; + } + + *out = PSHR32(sum,15); + out += st->out_stride; + out_sample++; + last_sample += st->int_advance; + samp_frac_num += st->frac_advance; + if (samp_frac_num >= st->den_rate) + { + samp_frac_num -= st->den_rate; + last_sample++; + } + } + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} + +#ifdef FIXED_POINT +#else +/* This is the same as the previous function, except with a double-precision accumulator */ +static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + int N = st->filt_len; + int out_sample = 0; + spx_word16_t *mem; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + mem = st->mem + channel_index * st->mem_alloc_size; + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + int j; + double sum=0; + + /* We already have all the filter coefficients pre-computed in the table */ + const spx_word16_t *ptr; + /* Do the memory part */ + for (j=0;last_sample-N+1+j < 0;j++) + { + sum += MULT16_16(mem[last_sample+j],(double)st->sinc_table[samp_frac_num*st->filt_len+j]); + } + + /* Do the new part */ + ptr = in+st->in_stride*(last_sample-N+1+j); + for (;j<N;j++) + { + sum += MULT16_16(*ptr,(double)st->sinc_table[samp_frac_num*st->filt_len+j]); + ptr += st->in_stride; + } + + *out = sum; + out += st->out_stride; + out_sample++; + last_sample += st->int_advance; + samp_frac_num += st->frac_advance; + if (samp_frac_num >= st->den_rate) + { + samp_frac_num -= st->den_rate; + last_sample++; + } + } + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} +#endif + +static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + int N = st->filt_len; + int out_sample = 0; + spx_word16_t *mem; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + mem = st->mem + channel_index * st->mem_alloc_size; + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + int j; + spx_word32_t sum=0; + + /* We need to interpolate the sinc filter */ + spx_word32_t accum[4] = {0.f,0.f, 0.f, 0.f}; + spx_word16_t interp[4]; + const spx_word16_t *ptr; + int offset; + spx_word16_t frac; + offset = samp_frac_num*st->oversample/st->den_rate; +#ifdef FIXED_POINT + frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); +#else + frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; +#endif + /* This code is written like this to make it easy to optimise with SIMD. + For most DSPs, it would be best to split the loops in two because most DSPs + have only two accumulators */ + for (j=0;last_sample-N+1+j < 0;j++) + { + spx_word16_t curr_mem = mem[last_sample+j]; + accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]); + accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]); + accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]); + accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]); + } + ptr = in+st->in_stride*(last_sample-N+1+j); + /* Do the new part */ + for (;j<N;j++) + { + spx_word16_t curr_in = *ptr; + ptr += st->in_stride; + accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]); + accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); + accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); + accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); + } + cubic_coef(frac, interp); + sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]); + + *out = PSHR32(sum,15); + out += st->out_stride; + out_sample++; + last_sample += st->int_advance; + samp_frac_num += st->frac_advance; + if (samp_frac_num >= st->den_rate) + { + samp_frac_num -= st->den_rate; + last_sample++; + } + } + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} + +#ifdef FIXED_POINT +#else +/* This is the same as the previous function, except with a double-precision accumulator */ +static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + int N = st->filt_len; + int out_sample = 0; + spx_word16_t *mem; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + mem = st->mem + channel_index * st->mem_alloc_size; + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + int j; + spx_word32_t sum=0; + + /* We need to interpolate the sinc filter */ + double accum[4] = {0.f,0.f, 0.f, 0.f}; + float interp[4]; + const spx_word16_t *ptr; + float alpha = ((float)samp_frac_num)/st->den_rate; + int offset = samp_frac_num*st->oversample/st->den_rate; + float frac = alpha*st->oversample - offset; + /* This code is written like this to make it easy to optimise with SIMD. + For most DSPs, it would be best to split the loops in two because most DSPs + have only two accumulators */ + for (j=0;last_sample-N+1+j < 0;j++) + { + double curr_mem = mem[last_sample+j]; + accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]); + accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]); + accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]); + accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]); + } + ptr = in+st->in_stride*(last_sample-N+1+j); + /* Do the new part */ + for (;j<N;j++) + { + double curr_in = *ptr; + ptr += st->in_stride; + accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]); + accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); + accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); + accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); + } + cubic_coef(frac, interp); + sum = interp[0]*accum[0] + interp[1]*accum[1] + interp[2]*accum[2] + interp[3]*accum[3]; + + *out = PSHR32(sum,15); + out += st->out_stride; + out_sample++; + last_sample += st->int_advance; + samp_frac_num += st->frac_advance; + if (samp_frac_num >= st->den_rate) + { + samp_frac_num -= st->den_rate; + last_sample++; + } + } + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} +#endif + +static void update_filter(SpeexResamplerState *st) +{ + spx_uint32_t old_length; + + old_length = st->filt_len; + st->oversample = quality_map[st->quality].oversample; + st->filt_len = quality_map[st->quality].base_length; + + if (st->num_rate > st->den_rate) + { + /* down-sampling */ + st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate; + /* FIXME: divide the numerator and denominator by a certain amount if they're too large */ + st->filt_len = st->filt_len*st->num_rate / st->den_rate; + /* Round down to make sure we have a multiple of 4 */ + st->filt_len &= (~0x3); + if (2*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (4*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (8*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (16*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (st->oversample < 1) + st->oversample = 1; + } else { + /* up-sampling */ + st->cutoff = quality_map[st->quality].upsample_bandwidth; + } + + /* Choose the resampling type that requires the least amount of memory */ + if (st->den_rate <= st->oversample) + { + spx_uint32_t i; + if (!st->sinc_table) + st->sinc_table = (spx_word16_t *)speex_alloc(st->filt_len*st->den_rate*sizeof(spx_word16_t)); + else if (st->sinc_table_length < st->filt_len*st->den_rate) + { + st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,st->filt_len*st->den_rate*sizeof(spx_word16_t)); + st->sinc_table_length = st->filt_len*st->den_rate; + } + for (i=0;i<st->den_rate;i++) + { + spx_uint32_t j; + for (j=0;j<st->filt_len;j++) + { + st->sinc_table[i*st->filt_len+j] = sinc(st->cutoff,((j-st->filt_len/2+1)-((float)i)/st->den_rate), st->filt_len, quality_map[st->quality].window_func); + } + } +#ifdef FIXED_POINT + st->resampler_ptr = resampler_basic_direct_single; +#else + if (st->quality>8) + st->resampler_ptr = resampler_basic_direct_double; + else + st->resampler_ptr = resampler_basic_direct_single; +#endif + /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/ + } else { + spx_int32_t i; + if (!st->sinc_table) + st->sinc_table = (spx_word16_t *)speex_alloc((st->filt_len*st->oversample+8)*sizeof(spx_word16_t)); + else if (st->sinc_table_length < st->filt_len*st->oversample+8) + { + st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,(st->filt_len*st->oversample+8)*sizeof(spx_word16_t)); + st->sinc_table_length = st->filt_len*st->oversample+8; + } + for (i=-4;i<(spx_int32_t)(st->oversample*st->filt_len+4);i++) + st->sinc_table[i+4] = sinc(st->cutoff,(i/(float)st->oversample - st->filt_len/2), st->filt_len, quality_map[st->quality].window_func); +#ifdef FIXED_POINT + st->resampler_ptr = resampler_basic_interpolate_single; +#else + if (st->quality>8) + st->resampler_ptr = resampler_basic_interpolate_double; + else + st->resampler_ptr = resampler_basic_interpolate_single; +#endif + /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/ + } + st->int_advance = st->num_rate/st->den_rate; + st->frac_advance = st->num_rate%st->den_rate; + + if (!st->mem) + { + spx_uint32_t i; + st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); + for (i=0;i<st->nb_channels*(st->filt_len-1);i++) + st->mem[i] = 0; + st->mem_alloc_size = st->filt_len-1; + /*speex_warning("init filter");*/ + } else if (!st->started) + { + spx_uint32_t i; + st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); + for (i=0;i<st->nb_channels*(st->filt_len-1);i++) + st->mem[i] = 0; + st->mem_alloc_size = st->filt_len-1; + /*speex_warning("reinit filter");*/ + } else if (st->filt_len > old_length) + { + spx_uint32_t i; + /* Increase the filter length */ + /*speex_warning("increase filter size");*/ + int old_alloc_size = st->mem_alloc_size; + if (st->filt_len-1 > st->mem_alloc_size) + { + st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); + st->mem_alloc_size = st->filt_len-1; + } + for (i=0;i<st->nb_channels;i++) + { + spx_uint32_t j; + /* Copy data going backward */ + for (j=0;j<old_length-1;j++) + st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*old_alloc_size+(old_length-2-j)]; + /* Then put zeros for lack of anything better */ + for (;j<st->filt_len-1;j++) + st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0; + /* Adjust last_sample */ + st->last_sample[i] += (st->filt_len - old_length)/2; + } + } else if (st->filt_len < old_length) + { + spx_uint32_t i; + /* Reduce filter length, this a bit tricky */ + /*speex_warning("decrease filter size (unimplemented)");*/ + /* Adjust last_sample (which will likely end up negative) */ + /*st->last_sample += (st->filt_len - old_length)/2;*/ + for (i=0;i<st->nb_channels;i++) + { + spx_uint32_t j; + st->magic_samples[i] = (old_length - st->filt_len)/2; + /* Copy data going backward */ + for (j=0;j<st->filt_len-1+st->magic_samples[i];j++) + st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]]; + } + } + +} + +SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) +{ + return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err); +} + +SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) +{ + spx_uint32_t i; + SpeexResamplerState *st; + if (quality > 10 || quality < 0) + { + if (err) + *err = RESAMPLER_ERR_INVALID_ARG; + return NULL; + } + st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState)); + st->initialised = 0; + st->started = 0; + st->in_rate = 0; + st->out_rate = 0; + st->num_rate = 0; + st->den_rate = 0; + st->quality = -1; + st->sinc_table_length = 0; + st->mem_alloc_size = 0; + st->filt_len = 0; + st->mem = 0; + st->resampler_ptr = 0; + + st->cutoff = 1.f; + st->nb_channels = nb_channels; + st->in_stride = 1; + st->out_stride = 1; + + /* Per channel data */ + st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int)); + st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int)); + st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int)); + for (i=0;i<nb_channels;i++) + { + st->last_sample[i] = 0; + st->magic_samples[i] = 0; + st->samp_frac_num[i] = 0; + } + + speex_resampler_set_quality(st, quality); + speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate); + + + update_filter(st); + + st->initialised = 1; + if (err) + *err = RESAMPLER_ERR_SUCCESS; + + return st; +} + +void speex_resampler_destroy(SpeexResamplerState *st) +{ + speex_free(st->mem); + speex_free(st->sinc_table); + speex_free(st->last_sample); + speex_free(st->magic_samples); + speex_free(st->samp_frac_num); + speex_free(st); +} + + + +static int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + int j=0; + int N = st->filt_len; + int out_sample = 0; + spx_word16_t *mem; + spx_uint32_t tmp_out_len = 0; + mem = st->mem + channel_index * st->mem_alloc_size; + st->started = 1; + + /* Handle the case where we have samples left from a reduction in filter length */ + if (st->magic_samples[channel_index]) + { + spx_uint32_t tmp_in_len; + spx_uint32_t tmp_magic; + tmp_in_len = st->magic_samples[channel_index]; + tmp_out_len = *out_len; + /* FIXME: Need to handle the case where the out array is too small */ + /* magic_samples needs to be set to zero to avoid infinite recursion */ + tmp_magic = st->magic_samples[channel_index]; + st->magic_samples[channel_index] = 0; + speex_resampler_process_native(st, channel_index, mem+N-1, &tmp_in_len, out, &tmp_out_len); + /*speex_warning_int("extra samples:", tmp_out_len);*/ + /* If we couldn't process all "magic" input samples, save the rest for next time */ + if (tmp_in_len < tmp_magic) + { + spx_uint32_t i; + st->magic_samples[channel_index] = tmp_magic-tmp_in_len; + for (i=0;i<st->magic_samples[channel_index];i++) + mem[N-1+i]=mem[N-1+i+tmp_in_len]; + } + out += tmp_out_len; + } + + /* Call the right resampler through the function ptr */ + out_sample = st->resampler_ptr(st, channel_index, in, in_len, out, out_len); + + if (st->last_sample[channel_index] < (spx_int32_t)*in_len) + *in_len = st->last_sample[channel_index]; + *out_len = out_sample+tmp_out_len; + st->last_sample[channel_index] -= *in_len; + + for (j=0;j<N-1-(spx_int32_t)*in_len;j++) + mem[j] = mem[j+*in_len]; + for (;j<N-1;j++) + mem[j] = in[st->in_stride*(j+*in_len-N+1)]; + + return RESAMPLER_ERR_SUCCESS; +} + +#define FIXED_STACK_ALLOC 1024 + +#ifdef FIXED_POINT +int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) +{ + spx_uint32_t i; + int istride_save, ostride_save; +#ifdef VAR_ARRAYS + spx_word16_t x[*in_len]; + spx_word16_t y[*out_len]; + /*VARDECL(spx_word16_t *x); + VARDECL(spx_word16_t *y); + ALLOC(x, *in_len, spx_word16_t); + ALLOC(y, *out_len, spx_word16_t);*/ + istride_save = st->in_stride; + ostride_save = st->out_stride; + for (i=0;i<*in_len;i++) + x[i] = WORD2INT(in[i*st->in_stride]); + st->in_stride = st->out_stride = 1; + speex_resampler_process_native(st, channel_index, x, in_len, y, out_len); + st->in_stride = istride_save; + st->out_stride = ostride_save; + for (i=0;i<*out_len;i++) + out[i*st->out_stride] = y[i]; +#else + spx_word16_t x[FIXED_STACK_ALLOC]; + spx_word16_t y[FIXED_STACK_ALLOC]; + spx_uint32_t ilen=*in_len, olen=*out_len; + istride_save = st->in_stride; + ostride_save = st->out_stride; + while (ilen && olen) + { + spx_uint32_t ichunk, ochunk; + ichunk = ilen; + ochunk = olen; + if (ichunk>FIXED_STACK_ALLOC) + ichunk=FIXED_STACK_ALLOC; + if (ochunk>FIXED_STACK_ALLOC) + ochunk=FIXED_STACK_ALLOC; + for (i=0;i<ichunk;i++) + x[i] = WORD2INT(in[i*st->in_stride]); + st->in_stride = st->out_stride = 1; + speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk); + st->in_stride = istride_save; + st->out_stride = ostride_save; + for (i=0;i<ochunk;i++) + out[i*st->out_stride] = y[i]; + out += ochunk; + in += ichunk; + ilen -= ichunk; + olen -= ochunk; + } + *in_len -= ilen; + *out_len -= olen; +#endif + return RESAMPLER_ERR_SUCCESS; +} +int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) +{ + return speex_resampler_process_native(st, channel_index, in, in_len, out, out_len); +} +#else +int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) +{ + return speex_resampler_process_native(st, channel_index, in, in_len, out, out_len); +} +int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) +{ + spx_uint32_t i; + int istride_save, ostride_save; +#ifdef VAR_ARRAYS + spx_word16_t x[*in_len]; + spx_word16_t y[*out_len]; + /*VARDECL(spx_word16_t *x); + VARDECL(spx_word16_t *y); + ALLOC(x, *in_len, spx_word16_t); + ALLOC(y, *out_len, spx_word16_t);*/ + istride_save = st->in_stride; + ostride_save = st->out_stride; + for (i=0;i<*in_len;i++) + x[i] = in[i*st->in_stride]; + st->in_stride = st->out_stride = 1; + speex_resampler_process_native(st, channel_index, x, in_len, y, out_len); + st->in_stride = istride_save; + st->out_stride = ostride_save; + for (i=0;i<*out_len;i++) + out[i*st->out_stride] = WORD2INT(y[i]); +#else + spx_word16_t x[FIXED_STACK_ALLOC]; + spx_word16_t y[FIXED_STACK_ALLOC]; + spx_uint32_t ilen=*in_len, olen=*out_len; + istride_save = st->in_stride; + ostride_save = st->out_stride; + while (ilen && olen) + { + spx_uint32_t ichunk, ochunk; + ichunk = ilen; + ochunk = olen; + if (ichunk>FIXED_STACK_ALLOC) + ichunk=FIXED_STACK_ALLOC; + if (ochunk>FIXED_STACK_ALLOC) + ochunk=FIXED_STACK_ALLOC; + for (i=0;i<ichunk;i++) + x[i] = in[i*st->in_stride]; + st->in_stride = st->out_stride = 1; + speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk); + st->in_stride = istride_save; + st->out_stride = ostride_save; + for (i=0;i<ochunk;i++) + out[i*st->out_stride] = WORD2INT(y[i]); + out += ochunk; + in += ichunk; + ilen -= ichunk; + olen -= ochunk; + } + *in_len -= ilen; + *out_len -= olen; +#endif + return RESAMPLER_ERR_SUCCESS; +} +#endif + +int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) +{ + spx_uint32_t i; + int istride_save, ostride_save; + istride_save = st->in_stride; + ostride_save = st->out_stride; + st->in_stride = st->out_stride = st->nb_channels; + for (i=0;i<st->nb_channels;i++) + { + speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len); + } + st->in_stride = istride_save; + st->out_stride = ostride_save; + return RESAMPLER_ERR_SUCCESS; +} + +int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) +{ + spx_uint32_t i; + int istride_save, ostride_save; + istride_save = st->in_stride; + ostride_save = st->out_stride; + st->in_stride = st->out_stride = st->nb_channels; + for (i=0;i<st->nb_channels;i++) + { + speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len); + } + st->in_stride = istride_save; + st->out_stride = ostride_save; + return RESAMPLER_ERR_SUCCESS; +} + +int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate) +{ + return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate); +} + +void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate) +{ + *in_rate = st->in_rate; + *out_rate = st->out_rate; +} + +int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate) +{ + int fact; + if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den) + return RESAMPLER_ERR_SUCCESS; + + st->in_rate = in_rate; + st->out_rate = out_rate; + st->num_rate = ratio_num; + st->den_rate = ratio_den; + /* FIXME: This is terribly inefficient, but who cares (at least for now)? */ + for (fact=2;fact<=sqrt(IMAX(in_rate, out_rate));fact++) + { + while ((st->num_rate % fact == 0) && (st->den_rate % fact == 0)) + { + st->num_rate /= fact; + st->den_rate /= fact; + } + } + + if (st->initialised) + update_filter(st); + return RESAMPLER_ERR_SUCCESS; +} + +void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den) +{ + *ratio_num = st->num_rate; + *ratio_den = st->den_rate; +} + +int speex_resampler_set_quality(SpeexResamplerState *st, int quality) +{ + if (quality > 10 || quality < 0) + return RESAMPLER_ERR_INVALID_ARG; + if (st->quality == quality) + return RESAMPLER_ERR_SUCCESS; + st->quality = quality; + if (st->initialised) + update_filter(st); + return RESAMPLER_ERR_SUCCESS; +} + +void speex_resampler_get_quality(SpeexResamplerState *st, int *quality) +{ + *quality = st->quality; +} + +void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride) +{ + st->in_stride = stride; +} + +void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride) +{ + *stride = st->in_stride; +} + +void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride) +{ + st->out_stride = stride; +} + +void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride) +{ + *stride = st->out_stride; +} + +int speex_resampler_skip_zeros(SpeexResamplerState *st) +{ + spx_uint32_t i; + for (i=0;i<st->nb_channels;i++) + st->last_sample[i] = st->filt_len/2; + return RESAMPLER_ERR_SUCCESS; +} + +int speex_resampler_reset_mem(SpeexResamplerState *st) +{ + spx_uint32_t i; + for (i=0;i<st->nb_channels*(st->filt_len-1);i++) + st->mem[i] = 0; + return RESAMPLER_ERR_SUCCESS; +} + +const char *speex_resampler_strerror(int err) +{ + switch (err) + { + case RESAMPLER_ERR_SUCCESS: + return "Success."; + case RESAMPLER_ERR_ALLOC_FAILED: + return "Memory allocation failed."; + case RESAMPLER_ERR_BAD_STATE: + return "Bad resampler state."; + case RESAMPLER_ERR_INVALID_ARG: + return "Invalid argument."; + case RESAMPLER_ERR_PTR_OVERLAP: + return "Input and output buffers overlap."; + default: + return "Unknown error. Bad error code or strange version mismatch."; + } +} diff --git a/libspeex/sb_celp.c b/libspeex/sb_celp.c index 89ba473..50b9824 100644 --- a/libspeex/sb_celp.c +++ b/libspeex/sb_celp.c @@ -45,6 +45,7 @@ #include "vq.h" #include "ltp.h" #include "misc.h" +#include "math_approx.h" /* Default size for the encoder and decoder stack (can be changed at compile time). This does not apply when using variable-size arrays or alloca. */ @@ -109,12 +110,26 @@ int sb_decoder_ctl(void *state, int request, void *ptr) #ifdef FIXED_POINT static const spx_word16_t gc_quant_bound[16] = {125, 164, 215, 282, 370, 484, 635, 832, 1090, 1428, 1871, 2452, 3213, 4210, 5516, 7228}; +static const spx_word16_t fold_quant_bound[32] = { + 39, 44, 50, 57, 64, 73, 83, 94, + 106, 120, 136, 154, 175, 198, 225, 255, + 288, 327, 370, 420, 476, 539, 611, 692, + 784, 889, 1007, 1141, 1293, 1465, 1660, 1881}; #define LSP_MARGIN 410 #define LSP_DELTA1 6553 #define LSP_DELTA2 1638 #else +static const spx_word16_t gc_quant_bound[16] = { + 0.97979, 1.28384, 1.68223, 2.20426, 2.88829, 3.78458, 4.95900, 6.49787, + 8.51428, 11.15642, 14.61846, 19.15484, 25.09895, 32.88761, 43.09325, 56.46588}; +static const spx_word16_t fold_quant_bound[32] = { + 0.30498, 0.34559, 0.39161, 0.44375, 0.50283, 0.56979, 0.64565, 0.73162, + 0.82903, 0.93942, 1.06450, 1.20624, 1.36685, 1.54884, 1.75506, 1.98875, + 2.25355, 2.55360, 2.89361, 3.27889, 3.71547, 4.21018, 4.77076, 5.40598, + 6.12577, 6.94141, 7.86565, 8.91295, 10.09969, 11.44445, 12.96826, 14.69497}; + #define LSP_MARGIN .05 #define LSP_DELTA1 .2 #define LSP_DELTA2 .05 @@ -126,122 +141,69 @@ static const spx_word16_t gc_quant_bound[16] = {125, 164, 215, 282, 370, 484, 63 #ifdef FIXED_POINT static const spx_word16_t h0[64] = {2, -7, -7, 18, 15, -39, -25, 75, 35, -130, -41, 212, 38, -327, -17, 483, -32, -689, 124, 956, -283, -1307, 543, 1780, -973, -2467, 1733, 3633, -3339, -6409, 9059, 30153, 30153, 9059, -6409, -3339, 3633, 1733, -2467, -973, 1780, 543, -1307, -283, 956, 124, -689, -32, 483, -17, -327, 38, 212, -41, -130, 35, 75, -25, -39, 15, 18, -7, -7, 2}; -static const spx_word16_t h1[64] = {2, 7, -7, -18, 15, 39, -25, -75, 35, 130, -41, -212, 38, 327, -17, -483, -32, 689, 124, -956, -283, 1307, 543, -1780, -973, 2467, 1733, -3633, -3339, 6409, 9059, -30153, 30153, -9059, -6409, 3339, 3633, -1733, -2467, 973, 1780, -543, -1307, 283, 956, -124, -689, 32, 483, 17, -327, -38, 212, 41, -130, -35, 75, 25, -39, -15, 18, 7, -7, -2}; - - #else static const float h0[64] = { - 3.596189e-05, -0.0001123515, - -0.0001104587, 0.0002790277, - 0.0002298438, -0.0005953563, - -0.0003823631, 0.00113826, - 0.0005308539, -0.001986177, - -0.0006243724, 0.003235877, - 0.0005743159, -0.004989147, - -0.0002584767, 0.007367171, - -0.0004857935, -0.01050689, - 0.001894714, 0.01459396, - -0.004313674, -0.01994365, - 0.00828756, 0.02716055, - -0.01485397, -0.03764973, - 0.026447, 0.05543245, - -0.05095487, -0.09779096, - 0.1382363, 0.4600981, - 0.4600981, 0.1382363, - -0.09779096, -0.05095487, - 0.05543245, 0.026447, - -0.03764973, -0.01485397, - 0.02716055, 0.00828756, - -0.01994365, -0.004313674, - 0.01459396, 0.001894714, - -0.01050689, -0.0004857935, - 0.007367171, -0.0002584767, - -0.004989147, 0.0005743159, - 0.003235877, -0.0006243724, - -0.001986177, 0.0005308539, - 0.00113826, -0.0003823631, - -0.0005953563, 0.0002298438, - 0.0002790277, -0.0001104587, - -0.0001123515, 3.596189e-05 + 3.596189e-05f, -0.0001123515f, + -0.0001104587f, 0.0002790277f, + 0.0002298438f, -0.0005953563f, + -0.0003823631f, 0.00113826f, + 0.0005308539f, -0.001986177f, + -0.0006243724f, 0.003235877f, + 0.0005743159f, -0.004989147f, + -0.0002584767f, 0.007367171f, + -0.0004857935f, -0.01050689f, + 0.001894714f, 0.01459396f, + -0.004313674f, -0.01994365f, + 0.00828756f, 0.02716055f, + -0.01485397f, -0.03764973f, + 0.026447f, 0.05543245f, + -0.05095487f, -0.09779096f, + 0.1382363f, 0.4600981f, + 0.4600981f, 0.1382363f, + -0.09779096f, -0.05095487f, + 0.05543245f, 0.026447f, + -0.03764973f, -0.01485397f, + 0.02716055f, 0.00828756f, + -0.01994365f, -0.004313674f, + 0.01459396f, 0.001894714f, + -0.01050689f, -0.0004857935f, + 0.007367171f, -0.0002584767f, + -0.004989147f, 0.0005743159f, + 0.003235877f, -0.0006243724f, + -0.001986177f, 0.0005308539f, + 0.00113826f, -0.0003823631f, + -0.0005953563f, 0.0002298438f, + 0.0002790277f, -0.0001104587f, + -0.0001123515f, 3.596189e-05f }; -static const float h1[64] = { - 3.596189e-05, 0.0001123515, - -0.0001104587, -0.0002790277, - 0.0002298438, 0.0005953563, - -0.0003823631, -0.00113826, - 0.0005308539, 0.001986177, - -0.0006243724, -0.003235877, - 0.0005743159, 0.004989147, - -0.0002584767, -0.007367171, - -0.0004857935, 0.01050689, - 0.001894714, -0.01459396, - -0.004313674, 0.01994365, - 0.00828756, -0.02716055, - -0.01485397, 0.03764973, - 0.026447, -0.05543245, - -0.05095487, 0.09779096, - 0.1382363, -0.4600981, - 0.4600981, -0.1382363, - -0.09779096, 0.05095487, - 0.05543245, -0.026447, - -0.03764973, 0.01485397, - 0.02716055, -0.00828756, - -0.01994365, 0.004313674, - 0.01459396, -0.001894714, - -0.01050689, 0.0004857935, - 0.007367171, 0.0002584767, - -0.004989147, -0.0005743159, - 0.003235877, 0.0006243724, - -0.001986177, -0.0005308539, - 0.00113826, 0.0003823631, - -0.0005953563, -0.0002298438, - 0.0002790277, 0.0001104587, - -0.0001123515, -3.596189e-05 -}; #endif extern const spx_word16_t lpc_window[]; -static void mix_and_saturate(spx_word32_t *x0, spx_word32_t *x1, spx_word16_t *out, int len) -{ - int i; - for (i=0;i<len;i++) - { - spx_word32_t tmp; -#ifdef FIXED_POINT - tmp=PSHR(x0[i]-x1[i],SIG_SHIFT-1); -#else - tmp=2*(x0[i]-x1[i]); -#endif - if (tmp>32767) - out[i] = 32767; - else if (tmp<-32767) - out[i] = -32767; - else - out[i] = tmp; - } -} void *sb_encoder_init(const SpeexMode *m) { int i; + spx_int32_t tmp; SBEncState *st; const SpeexSBMode *mode; st = (SBEncState*)speex_alloc(sizeof(SBEncState)); if (!st) return NULL; -#if defined(VAR_ARRAYS) || defined (USE_ALLOCA) - st->stack = NULL; -#else - st->stack = (char*)speex_alloc_scratch(SB_ENC_STACK); -#endif st->mode = m; mode = (const SpeexSBMode*)m->mode; st->st_low = speex_encoder_init(mode->nb_mode); +#if defined(VAR_ARRAYS) || defined (USE_ALLOCA) + st->stack = NULL; +#else + /*st->stack = (char*)speex_alloc_scratch(SB_ENC_STACK);*/ + speex_encoder_ctl(st->st_low, SPEEX_GET_STACK, &st->stack); +#endif + st->full_frame_size = 2*mode->frameSize; st->frame_size = mode->frameSize; st->subframeSize = mode->subframeSize; @@ -254,10 +216,10 @@ void *sb_encoder_init(const SpeexMode *m) st->submodes=mode->submodes; st->submodeSelect = st->submodeID=mode->defaultSubmode; - i=9; - speex_encoder_ctl(st->st_low, SPEEX_SET_QUALITY, &i); - i=1; - speex_encoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, &i); + tmp=9; + speex_encoder_ctl(st->st_low, SPEEX_SET_QUALITY, &tmp); + tmp=1; + speex_encoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, &tmp); st->lag_factor = mode->lag_factor; st->lpc_floor = mode->lpc_floor; @@ -265,49 +227,33 @@ void *sb_encoder_init(const SpeexMode *m) st->gamma2=mode->gamma2; st->first=1; - st->x0d=(spx_sig_t*)speex_alloc((st->frame_size)*sizeof(spx_sig_t)); - st->x1d=(spx_sig_t*)speex_alloc((st->frame_size)*sizeof(spx_sig_t)); - st->high=(spx_sig_t*)speex_alloc((st->full_frame_size)*sizeof(spx_sig_t)); - st->y0=(spx_sig_t*)speex_alloc((st->full_frame_size)*sizeof(spx_sig_t)); - st->y1=(spx_sig_t*)speex_alloc((st->full_frame_size)*sizeof(spx_sig_t)); + st->high=(spx_word16_t*)speex_alloc((st->windowSize-st->frame_size)*sizeof(spx_word16_t)); st->h0_mem=(spx_word16_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word16_t)); st->h1_mem=(spx_word16_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word16_t)); - st->g0_mem=(spx_word32_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word32_t)); - st->g1_mem=(spx_word32_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word32_t)); - - st->excBuf=(spx_sig_t*)speex_alloc((st->bufSize)*sizeof(spx_sig_t)); - st->exc = st->excBuf + st->bufSize - st->windowSize; - st->res=(spx_sig_t*)speex_alloc((st->frame_size)*sizeof(spx_sig_t)); - st->sw=(spx_sig_t*)speex_alloc((st->frame_size)*sizeof(spx_sig_t)); st->window= lpc_window; st->lagWindow = (spx_word16_t*)speex_alloc((st->lpcSize+1)*sizeof(spx_word16_t)); for (i=0;i<st->lpcSize+1;i++) st->lagWindow[i]=16384*exp(-.5*sqr(2*M_PI*st->lag_factor*i)); - st->autocorr = (spx_word16_t*)speex_alloc((st->lpcSize+1)*sizeof(spx_word16_t)); - st->lpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t)); - st->bw_lpc1 = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t)); - st->bw_lpc2 = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t)); - st->lsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t)); - st->qlsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t)); st->old_lsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t)); st->old_qlsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t)); - st->interp_lsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t)); - st->interp_qlsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t)); - st->interp_lpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t)); st->interp_qlpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t)); st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t)); - st->low_innov = (spx_word32_t*)speex_alloc((st->frame_size)*sizeof(spx_word32_t)); - speex_encoder_ctl(st->st_low, SPEEX_SET_INNOVATION_SAVE, st->low_innov); - st->innov_save = NULL; + st->exc_rms = (spx_word16_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word16_t)); + st->innov_rms_save = NULL; st->mem_sp = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); st->mem_sp2 = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); st->mem_sw = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + for (i=0;i<st->lpcSize;i++) + { + st->old_lsp[i]=LSP_SCALING*(M_PI*((float)(i+1)))/(st->lpcSize+1); + } + st->vbr_quality = 8; st->vbr_enabled = 0; st->vbr_max = 0; @@ -331,38 +277,21 @@ void sb_encoder_destroy(void *state) speex_encoder_destroy(st->st_low); #if !(defined(VAR_ARRAYS) || defined (USE_ALLOCA)) - speex_free_scratch(st->stack); + /*speex_free_scratch(st->stack);*/ #endif - speex_free(st->x0d); - speex_free(st->x1d); speex_free(st->high); - speex_free(st->y0); - speex_free(st->y1); speex_free(st->h0_mem); speex_free(st->h1_mem); - speex_free(st->g0_mem); - speex_free(st->g1_mem); - speex_free(st->excBuf); - speex_free(st->res); - speex_free(st->sw); speex_free(st->lagWindow); - speex_free(st->autocorr); - speex_free(st->lpc); - speex_free(st->bw_lpc1); - speex_free(st->bw_lpc2); - speex_free(st->lsp); - speex_free(st->qlsp); speex_free(st->old_lsp); speex_free(st->old_qlsp); - speex_free(st->interp_lsp); - speex_free(st->interp_qlsp); - speex_free(st->interp_lpc); speex_free(st->interp_qlpc); speex_free(st->pi_gain); + speex_free(st->exc_rms); speex_free(st->mem_sp); speex_free(st->mem_sp2); @@ -383,44 +312,56 @@ int sb_encode(void *state, void *vin, SpeexBits *bits) VARDECL(spx_word16_t *target); VARDECL(spx_word16_t *syn_resp); VARDECL(spx_word32_t *low_pi_gain); - VARDECL(spx_word16_t *low_exc); + spx_word16_t *low; + spx_word16_t *high; + VARDECL(spx_word16_t *low_exc_rms); + VARDECL(spx_word16_t *low_innov_rms); const SpeexSBMode *mode; - int dtx; + spx_int32_t dtx; spx_word16_t *in = (spx_word16_t*)vin; - + spx_word16_t e_low=0, e_high=0; + VARDECL(spx_coef_t *lpc); + VARDECL(spx_coef_t *interp_lpc); + VARDECL(spx_coef_t *bw_lpc1); + VARDECL(spx_coef_t *bw_lpc2); + VARDECL(spx_lsp_t *lsp); + VARDECL(spx_lsp_t *qlsp); + VARDECL(spx_lsp_t *interp_lsp); + VARDECL(spx_lsp_t *interp_qlsp); + st = (SBEncState*)state; stack=st->stack; mode = (const SpeexSBMode*)(st->mode->mode); - + low = in; + high = in+st->frame_size; + + /* High-band buffering / sync with low band */ + /* Compute the two sub-bands by filtering with QMF h0*/ + qmf_decomp(in, h0, low, high, st->full_frame_size, QMF_ORDER, st->h0_mem, stack); + + if (st->vbr_enabled || st->vad_enabled) { - VARDECL(spx_word16_t *low); - ALLOC(low, st->frame_size, spx_word16_t); - - /* Compute the two sub-bands by filtering with h0 and h1*/ - qmf_decomp(in, h0, st->x0d, st->x1d, st->full_frame_size, QMF_ORDER, st->h0_mem, stack); - - for (i=0;i<st->frame_size;i++) - low[i] = SATURATE(PSHR(st->x0d[i],SIG_SHIFT),32767); - - /* Encode the narrowband part*/ - speex_encode_native(st->st_low, low, bits); - - for (i=0;i<st->frame_size;i++) - st->x0d[i] = SHL(low[i],SIG_SHIFT); + /* Need to compute things here before the signal is trashed by the encoder */ + /*FIXME: Are the two signals (low, high) in sync? */ + e_low = compute_rms16(low, st->frame_size); + e_high = compute_rms16(high, st->frame_size); } - /* High-band buffering / sync with low band */ - for (i=0;i<st->windowSize-st->frame_size;i++) - st->high[i] = st->high[st->frame_size+i]; - for (i=0;i<st->frame_size;i++) - st->high[st->windowSize-st->frame_size+i]=SATURATE(st->x1d[i],536854528); - - speex_move(st->excBuf, st->excBuf+st->frame_size, (st->bufSize-st->frame_size)*sizeof(spx_sig_t)); + ALLOC(low_innov_rms, st->nbSubframes, spx_word16_t); + speex_encoder_ctl(st->st_low, SPEEX_SET_INNOVATION_SAVE, low_innov_rms); + /* Encode the narrowband part*/ + speex_encode_native(st->st_low, low, bits); + high = high - (st->windowSize-st->frame_size); + for (i=0;i<st->windowSize-st->frame_size;i++) + high[i] = st->high[i]; + for (i=0;i<st->windowSize-st->frame_size;i++) + st->high[i] = high[i+st->frame_size]; + ALLOC(low_pi_gain, st->nbSubframes, spx_word32_t); - ALLOC(low_exc, st->frame_size, spx_word16_t); + ALLOC(low_exc_rms, st->nbSubframes, spx_word16_t); speex_encoder_ctl(st->st_low, SPEEX_GET_PI_GAIN, low_pi_gain); - speex_encoder_ctl(st->st_low, SPEEX_GET_EXC, low_exc); + speex_encoder_ctl(st->st_low, SPEEX_GET_EXC, low_exc_rms); speex_encoder_ctl(st->st_low, SPEEX_GET_LOW_MODE, &dtx); @@ -429,35 +370,53 @@ int sb_encode(void *state, void *vin, SpeexBits *bits) else dtx=0; + ALLOC(lpc, st->lpcSize, spx_coef_t); + ALLOC(interp_lpc, st->lpcSize, spx_coef_t); + ALLOC(bw_lpc1, st->lpcSize, spx_coef_t); + ALLOC(bw_lpc2, st->lpcSize, spx_coef_t); + + ALLOC(lsp, st->lpcSize, spx_lsp_t); + ALLOC(qlsp, st->lpcSize, spx_lsp_t); + ALLOC(interp_lsp, st->lpcSize, spx_lsp_t); + ALLOC(interp_qlsp, st->lpcSize, spx_lsp_t); + { + VARDECL(spx_word16_t *autocorr); VARDECL(spx_word16_t *w_sig); + ALLOC(autocorr, st->lpcSize+1, spx_word16_t); ALLOC(w_sig, st->windowSize, spx_word16_t); /* Window for analysis */ - for (i=0;i<st->windowSize;i++) - w_sig[i] = SHR(MULT16_16(SHR((spx_word32_t)(st->high[i]),SIG_SHIFT),st->window[i]),SIG_SHIFT); - + /* FIXME: This is a kludge */ + if (st->subframeSize==80) + { + for (i=0;i<st->windowSize;i++) + w_sig[i] = EXTRACT16(SHR32(MULT16_16(high[i],st->window[i>>1]),SIG_SHIFT)); + } else { + for (i=0;i<st->windowSize;i++) + w_sig[i] = EXTRACT16(SHR32(MULT16_16(high[i],st->window[i]),SIG_SHIFT)); + } /* Compute auto-correlation */ - _spx_autocorr(w_sig, st->autocorr, st->lpcSize+1, st->windowSize); - } - st->autocorr[0] = ADD16(st->autocorr[0],MULT16_16_Q15(st->autocorr[0],st->lpc_floor)); /* Noise floor in auto-correlation domain */ + _spx_autocorr(w_sig, autocorr, st->lpcSize+1, st->windowSize); + autocorr[0] = ADD16(autocorr[0],MULT16_16_Q15(autocorr[0],st->lpc_floor)); /* Noise floor in auto-correlation domain */ - /* Lag windowing: equivalent to filtering in the power-spectrum domain */ - for (i=0;i<st->lpcSize+1;i++) - st->autocorr[i] = MULT16_16_Q14(st->autocorr[i],st->lagWindow[i]); + /* Lag windowing: equivalent to filtering in the power-spectrum domain */ + for (i=0;i<st->lpcSize+1;i++) + autocorr[i] = MULT16_16_Q14(autocorr[i],st->lagWindow[i]); - /* Levinson-Durbin */ - _spx_lpc(st->lpc, st->autocorr, st->lpcSize); + /* Levinson-Durbin */ + _spx_lpc(lpc, autocorr, st->lpcSize); + } /* LPC to LSPs (x-domain) transform */ - roots=lpc_to_lsp (st->lpc, st->lpcSize, st->lsp, 10, LSP_DELTA1, stack); + roots=lpc_to_lsp (lpc, st->lpcSize, lsp, 10, LSP_DELTA1, stack); if (roots!=st->lpcSize) { - roots = lpc_to_lsp (st->lpc, st->lpcSize, st->lsp, 10, LSP_DELTA2, stack); + roots = lpc_to_lsp (lpc, st->lpcSize, lsp, 10, LSP_DELTA2, stack); if (roots!=st->lpcSize) { /*If we can't find all LSP's, do some damage control and use a flat filter*/ for (i=0;i<st->lpcSize;i++) { - st->lsp[i]=LSP_SCALING*M_PI*((float)(i+1))/(st->lpcSize+1); + lsp[i]=st->old_lsp[i]; } } } @@ -465,7 +424,6 @@ int sb_encode(void *state, void *vin, SpeexBits *bits) /* VBR code */ if ((st->vbr_enabled || st->vad_enabled) && !dtx) { - float e_low=0, e_high=0; float ratio; if (st->abr_enabled) { @@ -487,10 +445,7 @@ int sb_encode(void *state, void *vin, SpeexBits *bits) } - /*FIXME: Are the two signals (low, high) in sync? */ - e_low = compute_rms(st->x0d, st->frame_size); - e_high = compute_rms(st->high, st->frame_size); - ratio = 2*log((1+e_high)/(1+e_low)); + ratio = 2*log((1.f+e_high)/(1.f+e_low)); speex_encoder_ctl(st->st_low, SPEEX_GET_RELATIVE_QUALITY, &st->relative_quality); if (ratio<-4) @@ -500,7 +455,7 @@ int sb_encode(void *state, void *vin, SpeexBits *bits) /*if (ratio>-2)*/ if (st->vbr_enabled) { - int modeid; + spx_int32_t modeid; modeid = mode->nb_modes-1; st->relative_quality+=1.0*(ratio+2); if (st->relative_quality<-1) @@ -522,7 +477,7 @@ int sb_encode(void *state, void *vin, SpeexBits *bits) speex_encoder_ctl(state, SPEEX_SET_HIGH_MODE, &modeid); if (st->abr_enabled) { - int bitrate; + spx_int32_t bitrate; speex_encoder_ctl(state, SPEEX_GET_BITRATE, &bitrate); st->abr_drift+=(bitrate-st->abr_enabled); st->abr_drift2 = .95*st->abr_drift2 + .05*(bitrate-st->abr_enabled); @@ -556,23 +511,14 @@ int sb_encode(void *state, void *vin, SpeexBits *bits) if (dtx || st->submodes[st->submodeID] == NULL) { for (i=0;i<st->frame_size;i++) - st->exc[i]=st->sw[i]=VERY_SMALL; + high[i]=VERY_SMALL; for (i=0;i<st->lpcSize;i++) st->mem_sw[i]=0; st->first=1; /* Final signal synthesis from excitation */ - iir_mem2(st->exc, st->interp_qlpc, st->high, st->frame_size, st->lpcSize, st->mem_sp); - -#ifdef RESYNTH - /* Reconstruct the original */ - fir_mem_up(st->x0d, h0, st->y0, st->full_frame_size, QMF_ORDER, st->g0_mem, stack); - fir_mem_up(st->high, h1, st->y1, st->full_frame_size, QMF_ORDER, st->g1_mem, stack); - - for (i=0;i<st->full_frame_size;i++) - in[i]=SHR(st->y0[i]-st->y1[i], SIG_SHIFT-1); -#endif + iir_mem16(high, st->interp_qlpc, high, st->frame_size, st->lpcSize, st->mem_sp, stack); if (dtx) return 0; @@ -582,14 +528,14 @@ int sb_encode(void *state, void *vin, SpeexBits *bits) /* LSP quantization */ - SUBMODE(lsp_quant)(st->lsp, st->qlsp, st->lpcSize, bits); + SUBMODE(lsp_quant)(lsp, qlsp, st->lpcSize, bits); if (st->first) { for (i=0;i<st->lpcSize;i++) - st->old_lsp[i] = st->lsp[i]; + st->old_lsp[i] = lsp[i]; for (i=0;i<st->lpcSize;i++) - st->old_qlsp[i] = st->qlsp[i]; + st->old_qlsp[i] = qlsp[i]; } ALLOC(mem, st->lpcSize, spx_mem_t); @@ -599,37 +545,33 @@ int sb_encode(void *state, void *vin, SpeexBits *bits) for (sub=0;sub<st->nbSubframes;sub++) { - spx_sig_t *exc, *sp, *res, *sw, *innov_save=NULL; - spx_word16_t filter_ratio; + VARDECL(spx_word16_t *exc); + VARDECL(spx_word16_t *res); + VARDECL(spx_word16_t *sw); + spx_word16_t *sp; + spx_word16_t filter_ratio; /*Q7*/ int offset; - spx_word32_t rl, rh; + spx_word32_t rl, rh; /*Q13*/ spx_word16_t eh=0; offset = st->subframeSize*sub; - sp=st->high+offset; - exc=st->exc+offset; - res=st->res+offset; - sw=st->sw+offset; - /* Pointer for saving innovation */ - if (st->innov_save) - { - innov_save = st->innov_save+2*offset; - for (i=0;i<2*st->subframeSize;i++) - innov_save[i]=0; - } + sp=high+offset; + ALLOC(exc, st->subframeSize, spx_word16_t); + ALLOC(res, st->subframeSize, spx_word16_t); + ALLOC(sw, st->subframeSize, spx_word16_t); /* LSP interpolation (quantized and unquantized) */ - lsp_interpolate(st->old_lsp, st->lsp, st->interp_lsp, st->lpcSize, sub, st->nbSubframes); - lsp_interpolate(st->old_qlsp, st->qlsp, st->interp_qlsp, st->lpcSize, sub, st->nbSubframes); + lsp_interpolate(st->old_lsp, lsp, interp_lsp, st->lpcSize, sub, st->nbSubframes); + lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpcSize, sub, st->nbSubframes); - lsp_enforce_margin(st->interp_lsp, st->lpcSize, LSP_MARGIN); - lsp_enforce_margin(st->interp_qlsp, st->lpcSize, LSP_MARGIN); + lsp_enforce_margin(interp_lsp, st->lpcSize, LSP_MARGIN); + lsp_enforce_margin(interp_qlsp, st->lpcSize, LSP_MARGIN); - lsp_to_lpc(st->interp_lsp, st->interp_lpc, st->lpcSize,stack); - lsp_to_lpc(st->interp_qlsp, st->interp_qlpc, st->lpcSize, stack); + lsp_to_lpc(interp_lsp, interp_lpc, st->lpcSize,stack); + lsp_to_lpc(interp_qlsp, st->interp_qlpc, st->lpcSize, stack); - bw_lpc(st->gamma1, st->interp_lpc, st->bw_lpc1, st->lpcSize); - bw_lpc(st->gamma2, st->interp_lpc, st->bw_lpc2, st->lpcSize); + bw_lpc(st->gamma1, interp_lpc, bw_lpc1, st->lpcSize); + bw_lpc(st->gamma2, interp_lpc, bw_lpc2, st->lpcSize); /* Compute mid-band (4000 Hz for wideband) response of low-band and high-band filters */ @@ -643,24 +585,24 @@ int sb_encode(void *state, void *vin, SpeexBits *bits) rl = low_pi_gain[sub]; #ifdef FIXED_POINT - filter_ratio=PDIV32_16(SHL(rl+82,2),SHR(82+rh,5)); + filter_ratio=EXTRACT16(SATURATE(PDIV32(SHL32(ADD32(rl,82),7),ADD32(82,rh)),32767)); #else filter_ratio=(rl+.01)/(rh+.01); #endif /* Compute "real excitation" */ - fir_mem2(sp, st->interp_qlpc, exc, st->subframeSize, st->lpcSize, st->mem_sp2); + fir_mem16(sp, st->interp_qlpc, exc, st->subframeSize, st->lpcSize, st->mem_sp2, stack); /* Compute energy of low-band and high-band excitation */ - eh = compute_rms(exc, st->subframeSize); + eh = compute_rms16(exc, st->subframeSize); if (!SUBMODE(innovation_quant)) {/* 1 for spectral folding excitation, 0 for stochastic */ - float g; - spx_word16_t el; - el = compute_rms(st->low_innov+offset, st->subframeSize); + spx_word32_t g; /*Q7*/ + spx_word16_t el; /*Q0*/ + el = low_innov_rms[sub]; /* Gain to use if we want to use the low-band excitation for high-band */ - g=eh/(1.+el); + g=PDIV32(MULT16_16(filter_ratio,eh),EXTEND32(ADD16(1,el))); #if 0 { @@ -678,15 +620,10 @@ int sb_encode(void *state, void *vin, SpeexBits *bits) } #endif -#ifdef FIXED_POINT - g *= filter_ratio/128.; -#else - g *= filter_ratio; -#endif /*print_vec(&g, 1, "gain factor");*/ /* Gain quantization */ { - int quant = (int) floor(.5 + 10 + 8.0 * log((g+.0001))); + int quant = scal_quant(g, fold_quant_bound, 32); /*speex_warning_int("tata", quant);*/ if (quant<0) quant=0; @@ -694,68 +631,57 @@ int sb_encode(void *state, void *vin, SpeexBits *bits) quant=31; speex_bits_pack(bits, quant, 5); } - + if (st->innov_rms_save) + { + st->innov_rms_save[sub] = eh; + } + st->exc_rms[sub] = eh; } else { - spx_word16_t gc; - spx_word32_t scale; - spx_word16_t el; - el = compute_rms16(low_exc+offset, st->subframeSize); + spx_word16_t gc; /*Q7*/ + spx_word32_t scale; /*Q14*/ + spx_word16_t el; /*Q0*/ + el = low_exc_rms[sub]; /*Q0*/ gc = PDIV32_16(MULT16_16(filter_ratio,1+eh),1+el); /* This is a kludge that cleans up a historical bug */ if (st->subframeSize==80) - gc *= 0.70711; + gc = MULT16_16_P15(QCONST16(0.70711f,15),gc); /*printf ("%f %f %f %f\n", el, eh, filter_ratio, gc);*/ -#ifdef FIXED_POINT { int qgc = scal_quant(gc, gc_quant_bound, 16); speex_bits_pack(bits, qgc, 4); - gc = MULT16_32_Q15(28626,gc_quant_bound[qgc]); + gc = MULT16_16_Q15(QCONST16(0.87360,15),gc_quant_bound[qgc]); } -#else - { - int qgc = (int)floor(.5+3.7*(log(gc)+0.15556)); - if (qgc<0) - qgc=0; - if (qgc>15) - qgc=15; - speex_bits_pack(bits, qgc, 4); - gc = exp((1/3.7)*qgc-0.15556); - } -#endif if (st->subframeSize==80) - gc *= 1.4142; + gc = MULT16_16_P14(QCONST16(1.4142f,14), gc); scale = SHL32(MULT16_16(PDIV32_16(SHL32(EXTEND32(gc),SIG_SHIFT-6),filter_ratio),(1+el)),6); - compute_impulse_response(st->interp_qlpc, st->bw_lpc1, st->bw_lpc2, syn_resp, st->subframeSize, st->lpcSize, stack); + compute_impulse_response(st->interp_qlpc, bw_lpc1, bw_lpc2, syn_resp, st->subframeSize, st->lpcSize, stack); /* Reset excitation */ for (i=0;i<st->subframeSize;i++) - exc[i]=VERY_SMALL; + res[i]=VERY_SMALL; /* Compute zero response (ringing) of A(z/g1) / ( A(z/g2) * Aq(z) ) */ for (i=0;i<st->lpcSize;i++) mem[i]=st->mem_sp[i]; - iir_mem2(exc, st->interp_qlpc, exc, st->subframeSize, st->lpcSize, mem); + iir_mem16(res, st->interp_qlpc, res, st->subframeSize, st->lpcSize, mem, stack); for (i=0;i<st->lpcSize;i++) mem[i]=st->mem_sw[i]; - filter_mem2(exc, st->bw_lpc1, st->bw_lpc2, res, st->subframeSize, st->lpcSize, mem); + filter_mem16(res, bw_lpc1, bw_lpc2, res, st->subframeSize, st->lpcSize, mem, stack); /* Compute weighted signal */ for (i=0;i<st->lpcSize;i++) mem[i]=st->mem_sw[i]; - filter_mem2(sp, st->bw_lpc1, st->bw_lpc2, sw, st->subframeSize, st->lpcSize, mem); + filter_mem16(sp, bw_lpc1, bw_lpc2, sw, st->subframeSize, st->lpcSize, mem, stack); /* Compute target signal */ for (i=0;i<st->subframeSize;i++) - target[i]=PSHR32(sw[i]-res[i],SIG_SHIFT); - - for (i=0;i<st->subframeSize;i++) - exc[i]=0; + target[i]=SUB16(sw[i],res[i]); signal_div(target, target, scale, st->subframeSize); @@ -764,22 +690,13 @@ int sb_encode(void *state, void *vin, SpeexBits *bits) innov[i]=0; /*print_vec(target, st->subframeSize, "\ntarget");*/ - SUBMODE(innovation_quant)(target, st->interp_qlpc, st->bw_lpc1, st->bw_lpc2, + SUBMODE(innovation_quant)(target, st->interp_qlpc, bw_lpc1, bw_lpc2, SUBMODE(innovation_params), st->lpcSize, st->subframeSize, innov, syn_resp, bits, stack, st->complexity, SUBMODE(double_codebook)); /*print_vec(target, st->subframeSize, "after");*/ signal_mul(innov, innov, scale, st->subframeSize); - for (i=0;i<st->subframeSize;i++) - exc[i] = ADD32(exc[i], innov[i]); - - if (st->innov_save) - { - for (i=0;i<st->subframeSize;i++) - innov_save[2*i]=innov[i]; - } - if (SUBMODE(double_codebook)) { char *tmp_stack=stack; VARDECL(spx_sig_t *innov2); @@ -787,42 +704,44 @@ int sb_encode(void *state, void *vin, SpeexBits *bits) for (i=0;i<st->subframeSize;i++) innov2[i]=0; for (i=0;i<st->subframeSize;i++) - target[i]*=2.5; - SUBMODE(innovation_quant)(target, st->interp_qlpc, st->bw_lpc1, st->bw_lpc2, + target[i]=MULT16_16_P13(QCONST16(2.5f,13), target[i]); + + SUBMODE(innovation_quant)(target, st->interp_qlpc, bw_lpc1, bw_lpc2, SUBMODE(innovation_params), st->lpcSize, st->subframeSize, innov2, syn_resp, bits, stack, st->complexity, 0); + signal_mul(innov2, innov2, MULT16_32_P15(QCONST16(0.4f,15),scale), st->subframeSize); + for (i=0;i<st->subframeSize;i++) - innov2[i]*=scale*(1/2.5)/SIG_SCALING; - for (i=0;i<st->subframeSize;i++) - exc[i] = ADD32(exc[i],innov2[i]); + innov[i] = ADD32(innov[i],innov2[i]); stack = tmp_stack; } + for (i=0;i<st->subframeSize;i++) + exc[i] = PSHR32(innov[i],SIG_SHIFT); + + if (st->innov_rms_save) + { + st->innov_rms_save[sub] = MULT16_16_Q15(QCONST16(.70711f, 15), compute_rms(innov, st->subframeSize)); + } + st->exc_rms[sub] = compute_rms16(exc, st->subframeSize); + } + /*Keep the previous memory*/ for (i=0;i<st->lpcSize;i++) mem[i]=st->mem_sp[i]; /* Final signal synthesis from excitation */ - iir_mem2(exc, st->interp_qlpc, sp, st->subframeSize, st->lpcSize, st->mem_sp); + iir_mem16(exc, st->interp_qlpc, sp, st->subframeSize, st->lpcSize, st->mem_sp, stack); /* Compute weighted signal again, from synthesized speech (not sure it's the right thing) */ - filter_mem2(sp, st->bw_lpc1, st->bw_lpc2, sw, st->subframeSize, st->lpcSize, st->mem_sw); + filter_mem16(sp, bw_lpc1, bw_lpc2, sw, st->subframeSize, st->lpcSize, st->mem_sw, stack); } - -#ifdef RESYNTH - /* Reconstruct the original */ - fir_mem_up(st->x0d, h0, st->y0, st->full_frame_size, QMF_ORDER, st->g0_mem, stack); - fir_mem_up(st->high, h1, st->y1, st->full_frame_size, QMF_ORDER, st->g1_mem, stack); - - for (i=0;i<st->full_frame_size;i++) - in[i]=SHR(st->y0[i]-st->y1[i], SIG_SHIFT-1); -#endif for (i=0;i<st->lpcSize;i++) - st->old_lsp[i] = st->lsp[i]; + st->old_lsp[i] = lsp[i]; for (i=0;i<st->lpcSize;i++) - st->old_qlsp[i] = st->qlsp[i]; + st->old_qlsp[i] = qlsp[i]; st->first=0; @@ -835,26 +754,24 @@ int sb_encode(void *state, void *vin, SpeexBits *bits) void *sb_decoder_init(const SpeexMode *m) { - int tmp; + spx_int32_t tmp; SBDecState *st; const SpeexSBMode *mode; st = (SBDecState*)speex_alloc(sizeof(SBDecState)); if (!st) return NULL; -#if defined(VAR_ARRAYS) || defined (USE_ALLOCA) - st->stack = NULL; -#else - st->stack = (char*)speex_alloc_scratch(SB_DEC_STACK); -#endif st->mode = m; mode=(const SpeexSBMode*)m->mode; - st->encode_submode = 1; - - - st->st_low = speex_decoder_init(mode->nb_mode); +#if defined(VAR_ARRAYS) || defined (USE_ALLOCA) + st->stack = NULL; +#else + /*st->stack = (char*)speex_alloc_scratch(SB_DEC_STACK);*/ + speex_decoder_ctl(st->st_low, SPEEX_GET_STACK, &st->stack); +#endif + st->full_frame_size = 2*mode->frameSize; st->frame_size = mode->frameSize; st->subframeSize = mode->subframeSize; @@ -870,29 +787,18 @@ void *sb_decoder_init(const SpeexMode *m) st->first=1; - - st->x0d = (spx_sig_t*)speex_alloc((st->frame_size)*sizeof(spx_sig_t)); - st->x1d = (spx_sig_t*)speex_alloc((st->frame_size)*sizeof(spx_sig_t)); - st->high = (spx_sig_t*)speex_alloc((st->full_frame_size)*sizeof(spx_sig_t)); - st->y0 = (spx_sig_t*)speex_alloc((st->full_frame_size)*sizeof(spx_sig_t)); - st->y1 = (spx_sig_t*)speex_alloc((st->full_frame_size)*sizeof(spx_sig_t)); - st->g0_mem = (spx_word32_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word32_t)); st->g1_mem = (spx_word32_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word32_t)); - st->exc = (spx_sig_t*)speex_alloc((st->frame_size)*sizeof(spx_sig_t)); - st->excBuf = (spx_sig_t*)speex_alloc((st->subframeSize)*sizeof(spx_sig_t)); + st->excBuf = (spx_word16_t*)speex_alloc((st->subframeSize)*sizeof(spx_word16_t)); - st->qlsp = (spx_lsp_t*)speex_alloc((st->lpcSize)*sizeof(spx_lsp_t)); st->old_qlsp = (spx_lsp_t*)speex_alloc((st->lpcSize)*sizeof(spx_lsp_t)); - st->interp_qlsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t)); st->interp_qlpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t)); st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t)); + st->exc_rms = (spx_word16_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word16_t)); st->mem_sp = (spx_mem_t*)speex_alloc((2*st->lpcSize)*sizeof(spx_mem_t)); - st->low_innov = (spx_word32_t*)speex_alloc((st->frame_size)*sizeof(spx_word32_t)); - speex_decoder_ctl(st->st_low, SPEEX_SET_INNOVATION_SAVE, st->low_innov); st->innov_save = NULL; @@ -911,23 +817,16 @@ void sb_decoder_destroy(void *state) st = (SBDecState*)state; speex_decoder_destroy(st->st_low); #if !(defined(VAR_ARRAYS) || defined (USE_ALLOCA)) - speex_free_scratch(st->stack); + /*speex_free_scratch(st->stack);*/ #endif - speex_free(st->x0d); - speex_free(st->x1d); - speex_free(st->high); - speex_free(st->y0); - speex_free(st->y1); speex_free(st->g0_mem); speex_free(st->g1_mem); - speex_free(st->exc); speex_free(st->excBuf); - speex_free(st->qlsp); speex_free(st->old_qlsp); - speex_free(st->interp_qlsp); speex_free(st->interp_qlpc); speex_free(st->pi_gain); + speex_free(st->exc_rms); speex_free(st->mem_sp); speex_free(state); @@ -943,7 +842,7 @@ static void sb_decode_lost(SBDecState *st, spx_word16_t *out, int dtx, char *sta saved_modeid=st->submodeID; st->submodeID=1; } else { - bw_lpc(GAMMA_SCALING*0.99, st->interp_qlpc, st->interp_qlpc, st->lpcSize); + bw_lpc(QCONST16(0.99f,15), st->interp_qlpc, st->interp_qlpc, st->lpcSize); } st->first=1; @@ -952,25 +851,17 @@ static void sb_decode_lost(SBDecState *st, spx_word16_t *out, int dtx, char *sta /* Final signal synthesis from excitation */ if (!dtx) { - spx_word16_t low_ener; - low_ener = .9*compute_rms(st->exc, st->frame_size); - for (i=0;i<st->frame_size;i++) - st->exc[i] = speex_rand(low_ener, &st->seed); + st->last_ener = MULT16_16_Q15(QCONST16(.9f,15),st->last_ener); } - for (i=0;i<st->frame_size;i++) - st->high[i]=st->exc[i]; + out[i+st->frame_size] = speex_rand(st->last_ener, &st->seed); - iir_mem2(st->high, st->interp_qlpc, st->high, st->frame_size, st->lpcSize, - st->mem_sp); + iir_mem16(out+st->frame_size, st->interp_qlpc, out+st->frame_size, st->frame_size, st->lpcSize, + st->mem_sp, stack); /* Reconstruct the original */ - fir_mem_up(st->x0d, h0, st->y0, st->full_frame_size, QMF_ORDER, st->g0_mem, stack); - fir_mem_up(st->high, h1, st->y1, st->full_frame_size, QMF_ORDER, st->g1_mem, stack); - - mix_and_saturate(st->y0, st->y1, out, st->full_frame_size); - + qmf_synth(out, out+st->frame_size, h0, out, st->full_frame_size, QMF_ORDER, st->g0_mem, st->g1_mem, stack); if (dtx) { st->submodeID=saved_modeid; @@ -987,26 +878,24 @@ int sb_decode(void *state, SpeexBits *bits, void *vout) int ret; char *stack; VARDECL(spx_word32_t *low_pi_gain); - VARDECL(spx_word16_t *low_exc); + VARDECL(spx_word16_t *low_exc_rms); VARDECL(spx_coef_t *ak); - int dtx; + VARDECL(spx_lsp_t *qlsp); + VARDECL(spx_lsp_t *interp_qlsp); + spx_int32_t dtx; const SpeexSBMode *mode; spx_word16_t *out = (spx_word16_t*)vout; + spx_word16_t *low_innov_alias; + spx_word32_t exc_ener_sum = 0; st = (SBDecState*)state; stack=st->stack; mode = (const SpeexSBMode*)(st->mode->mode); - { - VARDECL(spx_word16_t *low); - ALLOC(low, st->frame_size, spx_word16_t); - - /* Decode the low-band */ - ret = speex_decode_native(st->st_low, bits, low); - - for (i=0;i<st->frame_size;i++) - st->x0d[i] = SHL((spx_sig_t)low[i], SIG_SHIFT); - } + low_innov_alias = out+st->frame_size; + speex_decoder_ctl(st->st_low, SPEEX_SET_INNOVATION_SAVE, low_innov_alias); + /* Decode the low-band */ + ret = speex_decode_native(st->st_low, bits, out); speex_decoder_ctl(st->st_low, SPEEX_GET_DTX_STATUS, &dtx); @@ -1042,7 +931,7 @@ int sb_decode(void *state, SpeexBits *bits, void *vout) } if (st->submodeID != 0 && st->submodes[st->submodeID] == NULL) { - speex_warning("Invalid mode encountered: corrupted stream?"); + speex_notify("Invalid mode encountered. The stream is corrupted."); return -2; } } @@ -1057,51 +946,49 @@ int sb_decode(void *state, SpeexBits *bits, void *vout) } for (i=0;i<st->frame_size;i++) - st->exc[i]=VERY_SMALL; + out[st->frame_size+i]=VERY_SMALL; st->first=1; /* Final signal synthesis from excitation */ - iir_mem2(st->exc, st->interp_qlpc, st->high, st->frame_size, st->lpcSize, st->mem_sp); - - fir_mem_up(st->x0d, h0, st->y0, st->full_frame_size, QMF_ORDER, st->g0_mem, stack); - fir_mem_up(st->high, h1, st->y1, st->full_frame_size, QMF_ORDER, st->g1_mem, stack); + iir_mem16(out+st->frame_size, st->interp_qlpc, out+st->frame_size, st->frame_size, st->lpcSize, st->mem_sp, stack); - mix_and_saturate(st->y0, st->y1, out, st->full_frame_size); + qmf_synth(out, out+st->frame_size, h0, out, st->full_frame_size, QMF_ORDER, st->g0_mem, st->g1_mem, stack); return 0; } - for (i=0;i<st->frame_size;i++) - st->exc[i]=0; - ALLOC(low_pi_gain, st->nbSubframes, spx_word32_t); - ALLOC(low_exc, st->frame_size, spx_word16_t); + ALLOC(low_exc_rms, st->nbSubframes, spx_word16_t); speex_decoder_ctl(st->st_low, SPEEX_GET_PI_GAIN, low_pi_gain); - speex_decoder_ctl(st->st_low, SPEEX_GET_EXC, low_exc); + speex_decoder_ctl(st->st_low, SPEEX_GET_EXC, low_exc_rms); - SUBMODE(lsp_unquant)(st->qlsp, st->lpcSize, bits); + ALLOC(qlsp, st->lpcSize, spx_lsp_t); + ALLOC(interp_qlsp, st->lpcSize, spx_lsp_t); + SUBMODE(lsp_unquant)(qlsp, st->lpcSize, bits); if (st->first) { for (i=0;i<st->lpcSize;i++) - st->old_qlsp[i] = st->qlsp[i]; + st->old_qlsp[i] = qlsp[i]; } ALLOC(ak, st->lpcSize, spx_coef_t); for (sub=0;sub<st->nbSubframes;sub++) { - spx_sig_t *exc, *sp, *innov_save=NULL; + VARDECL(spx_word32_t *exc); + spx_word16_t *innov_save=NULL; + spx_word16_t *sp; spx_word16_t filter_ratio; spx_word16_t el=0; int offset; spx_word32_t rl=0,rh=0; offset = st->subframeSize*sub; - sp=st->high+offset; - exc=st->exc+offset; + sp=out+st->frame_size+offset; + ALLOC(exc, st->subframeSize, spx_word32_t); /* Pointer for saving innovation */ if (st->innov_save) { @@ -1111,12 +998,12 @@ int sb_decode(void *state, SpeexBits *bits, void *vout) } /* LSP interpolation */ - lsp_interpolate(st->old_qlsp, st->qlsp, st->interp_qlsp, st->lpcSize, sub, st->nbSubframes); + lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpcSize, sub, st->nbSubframes); - lsp_enforce_margin(st->interp_qlsp, st->lpcSize, LSP_MARGIN); + lsp_enforce_margin(interp_qlsp, st->lpcSize, LSP_MARGIN); /* LSP to LPC */ - lsp_to_lpc(st->interp_qlsp, ak, st->lpcSize, stack); + lsp_to_lpc(interp_qlsp, ak, st->lpcSize, stack); /* Calculate reponse ratio between the low and high filter in the middle of the band (4000 Hz) */ @@ -1125,13 +1012,13 @@ int sb_decode(void *state, SpeexBits *bits, void *vout) rh = LPC_SCALING; for (i=0;i<st->lpcSize;i+=2) { - rh += st->interp_qlpc[i+1] - st->interp_qlpc[i]; - st->pi_gain[sub] += st->interp_qlpc[i] + st->interp_qlpc[i+1]; + rh += ak[i+1] - ak[i]; + st->pi_gain[sub] += ak[i] + ak[i+1]; } rl = low_pi_gain[sub]; #ifdef FIXED_POINT - filter_ratio=PDIV32_16(SHL(rl+82,2),SHR(82+rh,5)); + filter_ratio=EXTRACT16(SATURATE(PDIV32(SHL32(ADD32(rl,82),7),ADD32(82,rh)),32767)); #else filter_ratio=(rl+.01)/(rh+.01); #endif @@ -1140,60 +1027,32 @@ int sb_decode(void *state, SpeexBits *bits, void *vout) exc[i]=0; if (!SUBMODE(innovation_unquant)) { - float g; + spx_word32_t g; int quant; quant = speex_bits_unpack_unsigned(bits, 5); - g= exp(((float)quant-10)/8.0); + g= spx_exp(MULT16_16(QCONST16(.125f,11),(quant-10))); -#ifdef FIXED_POINT - g /= filter_ratio/128.; -#else - g /= filter_ratio; -#endif - /* High-band excitation using the low-band excitation and a gain */ + g = PDIV32(g, filter_ratio); -#if 0 - for (i=0;i<st->subframeSize;i++) - exc[i]=mode->folding_gain*g*st->low_innov[offset+i]; -#else + for (i=0;i<st->subframeSize;i+=2) { - float tmp=1; - /*static tmp1=0,tmp2=0; - static int seed=1; - el = compute_rms(low_innov+offset, st->subframeSize);*/ - for (i=0;i<st->subframeSize;i++) - { - float e=tmp*g*mode->folding_gain*st->low_innov[offset+i]; - tmp *= -1; - exc[i] = e; - /*float r = speex_rand(g*el,&seed); - exc[i] = .5*(r+tmp2 + e-tmp1); - tmp1 = e; - tmp2 = r;*/ - } - + exc[i]=SHL32(MULT16_32_P15(MULT16_16_Q15(mode->folding_gain,low_innov_alias[offset+i]),SHL32(g,6)),SIG_SHIFT); + exc[i+1]=NEG32(SHL32(MULT16_32_P15(MULT16_16_Q15(mode->folding_gain,low_innov_alias[offset+i+1]),SHL32(g,6)),SIG_SHIFT)); } -#endif } else { spx_word16_t gc; spx_word32_t scale; int qgc = speex_bits_unpack_unsigned(bits, 4); - - el = compute_rms16(low_exc+offset, st->subframeSize); - -#ifdef FIXED_POINT - gc = MULT16_32_Q15(28626,gc_quant_bound[qgc]); -#else - gc = exp((1/3.7)*qgc-0.15556); -#endif + + el = low_exc_rms[sub]; + gc = MULT16_16_Q15(QCONST16(0.87360,15),gc_quant_bound[qgc]); if (st->subframeSize==80) - gc *= 1.4142; - - scale = SHL(MULT16_16(PDIV32_16(SHL(gc,SIG_SHIFT-6),filter_ratio),(1+el)),6); + gc = MULT16_16_P14(QCONST16(1.4142f,14),gc); + scale = SHL32(PDIV32(SHL32(MULT16_16(gc, el),3), filter_ratio),SIG_SHIFT-3); SUBMODE(innovation_unquant)(exc, SUBMODE(innovation_params), st->subframeSize, bits, stack, &st->seed); @@ -1207,8 +1066,7 @@ int sb_decode(void *state, SpeexBits *bits, void *vout) innov2[i]=0; SUBMODE(innovation_unquant)(innov2, SUBMODE(innovation_params), st->subframeSize, bits, stack, &st->seed); - for (i=0;i<st->subframeSize;i++) - innov2[i]*=scale/(float)SIG_SCALING*(1/2.5); + signal_mul(innov2, innov2, MULT16_32_P15(QCONST16(0.4f,15),scale), st->subframeSize); for (i=0;i<st->subframeSize;i++) exc[i] = ADD32(exc[i],innov2[i]); stack = tmp_stack; @@ -1219,27 +1077,25 @@ int sb_decode(void *state, SpeexBits *bits, void *vout) if (st->innov_save) { for (i=0;i<st->subframeSize;i++) - innov_save[2*i]=exc[i]; + innov_save[2*i]=EXTRACT16(PSHR32(exc[i],SIG_SHIFT)); } for (i=0;i<st->subframeSize;i++) sp[i]=st->excBuf[i]; - iir_mem2(sp, st->interp_qlpc, sp, st->subframeSize, st->lpcSize, - st->mem_sp); + iir_mem16(sp, st->interp_qlpc, sp, st->subframeSize, st->lpcSize, + st->mem_sp, stack); for (i=0;i<st->subframeSize;i++) - st->excBuf[i]=exc[i]; + st->excBuf[i]=EXTRACT16(PSHR32(exc[i],SIG_SHIFT)); for (i=0;i<st->lpcSize;i++) st->interp_qlpc[i] = ak[i]; - + st->exc_rms[sub] = compute_rms16(st->excBuf, st->subframeSize); + exc_ener_sum = ADD32(exc_ener_sum, DIV32(MULT16_16(st->exc_rms[sub],st->exc_rms[sub]), st->nbSubframes)); } - - fir_mem_up(st->x0d, h0, st->y0, st->full_frame_size, QMF_ORDER, st->g0_mem, stack); - fir_mem_up(st->high, h1, st->y1, st->full_frame_size, QMF_ORDER, st->g1_mem, stack); - - mix_and_saturate(st->y0, st->y1, out, st->full_frame_size); - + st->last_ener = spx_sqrt(exc_ener_sum); + + qmf_synth(out, out+st->frame_size, h0, out, st->full_frame_size, QMF_ORDER, st->g0_mem, st->g1_mem, stack); for (i=0;i<st->lpcSize;i++) - st->old_qlsp[i] = st->qlsp[i]; + st->old_qlsp[i] = qlsp[i]; st->first=0; @@ -1254,10 +1110,10 @@ int sb_encoder_ctl(void *state, int request, void *ptr) switch(request) { case SPEEX_GET_FRAME_SIZE: - (*(int*)ptr) = st->full_frame_size; + (*(spx_int32_t*)ptr) = st->full_frame_size; break; case SPEEX_SET_HIGH_MODE: - st->submodeSelect = st->submodeID = (*(int*)ptr); + st->submodeSelect = st->submodeID = (*(spx_int32_t*)ptr); break; case SPEEX_SET_LOW_MODE: speex_encoder_ctl(st->st_low, SPEEX_SET_LOW_MODE, ptr); @@ -1275,22 +1131,22 @@ int sb_encoder_ctl(void *state, int request, void *ptr) speex_encoder_ctl(st, SPEEX_SET_QUALITY, ptr); break; case SPEEX_SET_VBR: - st->vbr_enabled = (*(int*)ptr); + st->vbr_enabled = (*(spx_int32_t*)ptr); speex_encoder_ctl(st->st_low, SPEEX_SET_VBR, ptr); break; case SPEEX_GET_VBR: - (*(int*)ptr) = st->vbr_enabled; + (*(spx_int32_t*)ptr) = st->vbr_enabled; break; case SPEEX_SET_VAD: - st->vad_enabled = (*(int*)ptr); + st->vad_enabled = (*(spx_int32_t*)ptr); speex_encoder_ctl(st->st_low, SPEEX_SET_VAD, ptr); break; case SPEEX_GET_VAD: - (*(int*)ptr) = st->vad_enabled; + (*(spx_int32_t*)ptr) = st->vad_enabled; break; case SPEEX_SET_VBR_QUALITY: { - int q; + spx_int32_t q; float qual = (*(float*)ptr)+.6; st->vbr_quality = (*(float*)ptr); if (qual>10) @@ -1311,7 +1167,7 @@ int sb_encoder_ctl(void *state, int request, void *ptr) speex_encoder_ctl(st->st_low, SPEEX_SET_VBR, &st->vbr_enabled); if (st->vbr_enabled) { - int i=10, rate, target; + spx_int32_t i=10, rate, target; float vbr_qual; target = (*(spx_int32_t*)ptr); while (i>=0) @@ -1337,8 +1193,8 @@ int sb_encoder_ctl(void *state, int request, void *ptr) break; case SPEEX_SET_QUALITY: { - int nb_qual; - int quality = (*(int*)ptr); + spx_int32_t nb_qual; + int quality = (*(spx_int32_t*)ptr); if (quality < 0) quality = 0; if (quality > 10) @@ -1350,16 +1206,16 @@ int sb_encoder_ctl(void *state, int request, void *ptr) break; case SPEEX_SET_COMPLEXITY: speex_encoder_ctl(st->st_low, SPEEX_SET_COMPLEXITY, ptr); - st->complexity = (*(int*)ptr); + st->complexity = (*(spx_int32_t*)ptr); if (st->complexity<1) st->complexity=1; break; case SPEEX_GET_COMPLEXITY: - (*(int*)ptr) = st->complexity; + (*(spx_int32_t*)ptr) = st->complexity; break; case SPEEX_SET_BITRATE: { - int i=10; + spx_int32_t i=10; spx_int32_t rate, target; target = (*(spx_int32_t*)ptr); while (i>=0) @@ -1397,25 +1253,23 @@ int sb_encoder_ctl(void *state, int request, void *ptr) int i; st->first = 1; for (i=0;i<st->lpcSize;i++) - st->lsp[i]=(M_PI*((float)(i+1)))/(st->lpcSize+1); + st->old_lsp[i]=(M_PI*((float)(i+1)))/(st->lpcSize+1); for (i=0;i<st->lpcSize;i++) st->mem_sw[i]=st->mem_sp[i]=st->mem_sp2[i]=0; - for (i=0;i<st->bufSize;i++) - st->excBuf[i]=0; for (i=0;i<QMF_ORDER;i++) - st->h0_mem[i]=st->h1_mem[i]=st->g0_mem[i]=st->g1_mem[i]=0; + st->h0_mem[i]=st->h1_mem[i]=0; } break; case SPEEX_SET_SUBMODE_ENCODING: - st->encode_submode = (*(int*)ptr); - speex_encoder_ctl(st->st_low, SPEEX_SET_SUBMODE_ENCODING, &ptr); + st->encode_submode = (*(spx_int32_t*)ptr); + speex_encoder_ctl(st->st_low, SPEEX_SET_SUBMODE_ENCODING, ptr); break; case SPEEX_GET_SUBMODE_ENCODING: - (*(int*)ptr) = st->encode_submode; + (*(spx_int32_t*)ptr) = st->encode_submode; break; case SPEEX_GET_LOOKAHEAD: speex_encoder_ctl(st->st_low, SPEEX_GET_LOOKAHEAD, ptr); - (*(int*)ptr) = 2*(*(int*)ptr) + QMF_ORDER - 1; + (*(spx_int32_t*)ptr) = 2*(*(spx_int32_t*)ptr) + QMF_ORDER - 1; break; case SPEEX_SET_PLC_TUNING: speex_encoder_ctl(st->st_low, SPEEX_SET_PLC_TUNING, ptr); @@ -1474,33 +1328,22 @@ int sb_encoder_ctl(void *state, int request, void *ptr) case SPEEX_GET_EXC: { int i; - spx_sig_t *e = (spx_sig_t*)ptr; - for (i=0;i<st->full_frame_size;i++) - e[i]=0; - for (i=0;i<st->frame_size;i++) - e[2*i]=2*st->exc[i]; - } - break; - case SPEEX_GET_INNOV: - { - int i; - spx_sig_t *e = (spx_sig_t*)ptr; - for (i=0;i<st->full_frame_size;i++) - e[i]=0; - for (i=0;i<st->frame_size;i++) - e[2*i]=2*st->exc[i]; + for (i=0;i<st->nbSubframes;i++) + ((spx_word16_t*)ptr)[i] = st->exc_rms[i]; } break; case SPEEX_GET_RELATIVE_QUALITY: (*(float*)ptr)=st->relative_quality; break; case SPEEX_SET_INNOVATION_SAVE: - st->innov_save = (spx_sig_t*)ptr; + st->innov_rms_save = (spx_word16_t*)ptr; break; case SPEEX_SET_WIDEBAND: speex_encoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, ptr); break; - + case SPEEX_GET_STACK: + *((char**)ptr) = st->stack; + break; default: speex_warning_int("Unknown nb_ctl request: ", request); return -1; @@ -1515,7 +1358,7 @@ int sb_decoder_ctl(void *state, int request, void *ptr) switch(request) { case SPEEX_SET_HIGH_MODE: - st->submodeID = (*(int*)ptr); + st->submodeID = (*(spx_int32_t*)ptr); break; case SPEEX_SET_LOW_MODE: speex_decoder_ctl(st->st_low, SPEEX_SET_LOW_MODE, ptr); @@ -1524,20 +1367,20 @@ int sb_decoder_ctl(void *state, int request, void *ptr) speex_decoder_ctl(st->st_low, SPEEX_GET_LOW_MODE, ptr); break; case SPEEX_GET_FRAME_SIZE: - (*(int*)ptr) = st->full_frame_size; + (*(spx_int32_t*)ptr) = st->full_frame_size; break; case SPEEX_SET_ENH: speex_decoder_ctl(st->st_low, request, ptr); - st->lpc_enh_enabled = *((int*)ptr); + st->lpc_enh_enabled = *((spx_int32_t*)ptr); break; case SPEEX_GET_ENH: - *((int*)ptr) = st->lpc_enh_enabled; + *((spx_int32_t*)ptr) = st->lpc_enh_enabled; break; case SPEEX_SET_MODE: case SPEEX_SET_QUALITY: { - int nb_qual; - int quality = (*(int*)ptr); + spx_int32_t nb_qual; + int quality = (*(spx_int32_t*)ptr); if (quality < 0) quality = 0; if (quality > 10) @@ -1578,18 +1421,19 @@ int sb_decoder_ctl(void *state, int request, void *ptr) st->mem_sp[i]=0; for (i=0;i<QMF_ORDER;i++) st->g0_mem[i]=st->g1_mem[i]=0; + st->last_ener=0; } break; case SPEEX_SET_SUBMODE_ENCODING: - st->encode_submode = (*(int*)ptr); - speex_decoder_ctl(st->st_low, SPEEX_SET_SUBMODE_ENCODING, &ptr); + st->encode_submode = (*(spx_int32_t*)ptr); + speex_decoder_ctl(st->st_low, SPEEX_SET_SUBMODE_ENCODING, ptr); break; case SPEEX_GET_SUBMODE_ENCODING: - (*(int*)ptr) = st->encode_submode; + (*(spx_int32_t*)ptr) = st->encode_submode; break; case SPEEX_GET_LOOKAHEAD: speex_decoder_ctl(st->st_low, SPEEX_GET_LOOKAHEAD, ptr); - (*(int*)ptr) = 2*(*(int*)ptr); + (*(spx_int32_t*)ptr) = 2*(*(spx_int32_t*)ptr); break; case SPEEX_SET_HIGHPASS: speex_decoder_ctl(st->st_low, SPEEX_SET_HIGHPASS, ptr); @@ -1609,33 +1453,22 @@ int sb_decoder_ctl(void *state, int request, void *ptr) case SPEEX_GET_EXC: { int i; - spx_sig_t *e = (spx_sig_t*)ptr; - for (i=0;i<st->full_frame_size;i++) - e[i]=0; - for (i=0;i<st->frame_size;i++) - e[2*i]=2*st->exc[i]; - } - break; - case SPEEX_GET_INNOV: - { - int i; - spx_sig_t *e = (spx_sig_t*)ptr; - for (i=0;i<st->full_frame_size;i++) - e[i]=0; - for (i=0;i<st->frame_size;i++) - e[2*i]=2*st->exc[i]; + for (i=0;i<st->nbSubframes;i++) + ((spx_word16_t*)ptr)[i] = st->exc_rms[i]; } break; case SPEEX_GET_DTX_STATUS: speex_decoder_ctl(st->st_low, SPEEX_GET_DTX_STATUS, ptr); break; case SPEEX_SET_INNOVATION_SAVE: - st->innov_save = (spx_sig_t*)ptr; + st->innov_save = (spx_word16_t*)ptr; break; case SPEEX_SET_WIDEBAND: speex_decoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, ptr); break; - + case SPEEX_GET_STACK: + *((char**)ptr) = st->stack; + break; default: speex_warning_int("Unknown nb_ctl request: ", request); return -1; diff --git a/libspeex/sb_celp.h b/libspeex/sb_celp.h index 4da03e4..a0dc3af 100644 --- a/libspeex/sb_celp.h +++ b/libspeex/sb_celp.h @@ -58,37 +58,21 @@ typedef struct SBEncState { spx_word16_t gamma2; /**< Perceptual weighting coef 2 */ char *stack; /**< Temporary allocation stack */ - spx_sig_t *x0d, *x1d; /**< QMF filter signals*/ - spx_sig_t *high; /**< High-band signal (buffer) */ - spx_sig_t *y0, *y1; /**< QMF synthesis signals */ + spx_word16_t *high; /**< High-band signal (buffer) */ spx_word16_t *h0_mem, *h1_mem; - spx_word32_t *g0_mem, *g1_mem; /**< QMF memories */ - spx_sig_t *excBuf; /**< High-band excitation */ - spx_sig_t *exc; /**< High-band excitation (for QMF only)*/ - spx_sig_t *res; /**< Zero-input response (ringing) */ - spx_sig_t *sw; /**< Perceptually weighted signal */ const spx_word16_t *window; /**< LPC analysis window */ spx_word16_t *lagWindow; /**< Auto-correlation window */ - spx_word16_t *autocorr; /**< Auto-correlation (for LPC analysis) */ - spx_coef_t *lpc; /**< LPC coefficients */ - spx_lsp_t *lsp; /**< LSP coefficients */ - spx_lsp_t *qlsp; /**< Quantized LSPs */ spx_lsp_t *old_lsp; /**< LSPs of previous frame */ spx_lsp_t *old_qlsp; /**< Quantized LSPs of previous frame */ - spx_lsp_t *interp_lsp; /**< Interpolated LSPs for current sub-frame */ - spx_lsp_t *interp_qlsp; /**< Interpolated quantized LSPs for current sub-frame */ - spx_coef_t *interp_lpc; /**< Interpolated LPCs for current sub-frame */ spx_coef_t *interp_qlpc; /**< Interpolated quantized LPCs for current sub-frame */ - spx_coef_t *bw_lpc1; /**< Bandwidth-expanded version of LPCs (#1) */ - spx_coef_t *bw_lpc2; /**< Bandwidth-expanded version of LPCs (#2) */ spx_mem_t *mem_sp; /**< Synthesis signal memory */ spx_mem_t *mem_sp2; spx_mem_t *mem_sw; /**< Perceptual signal memory */ spx_word32_t *pi_gain; - spx_sig_t *innov_save; /**< If non-NULL, innovation is copied here */ - spx_sig_t *low_innov; /**< Lower-band innovation is copied here magically */ + spx_word16_t *exc_rms; + spx_word16_t *innov_rms_save; /**< If non-NULL, innovation is copied here */ float vbr_quality; /**< Quality setting for VBR encoding */ int vbr_enabled; /**< 1 for enabling VBR, 0 otherwise */ @@ -125,23 +109,18 @@ typedef struct SBDecState { int lpc_enh_enabled; char *stack; - spx_sig_t *x0d, *x1d; - spx_sig_t *high; - spx_sig_t *y0, *y1; spx_word32_t *g0_mem, *g1_mem; - spx_sig_t *exc; - spx_sig_t *excBuf; - spx_lsp_t *qlsp; + spx_word16_t *excBuf; spx_lsp_t *old_qlsp; - spx_lsp_t *interp_qlsp; spx_coef_t *interp_qlpc; spx_mem_t *mem_sp; spx_word32_t *pi_gain; - spx_sig_t *innov_save; /** If non-NULL, innovation is copied here */ - spx_sig_t *low_innov; /** Lower-band innovation is copied here magically */ + spx_word16_t *exc_rms; + spx_word16_t *innov_save; /** If non-NULL, innovation is copied here */ + spx_word16_t last_ener; spx_int32_t seed; int encode_submode; diff --git a/libspeex/speex.c b/libspeex/speex.c index 94829e6..846e021 100644 --- a/libspeex/speex.c +++ b/libspeex/speex.c @@ -86,7 +86,7 @@ int speex_decode_native(void *state, SpeexBits *bits, spx_word16_t *out) int speex_encode(void *state, float *in, SpeexBits *bits) { int i; - int N; + spx_int32_t N; spx_int16_t short_in[MAX_IN_SAMPLES]; speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N); for (i=0;i<N;i++) @@ -111,7 +111,7 @@ int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) int speex_decode(void *state, SpeexBits *bits, float *out) { int i, ret; - int N; + spx_int32_t N; spx_int16_t short_out[MAX_IN_SAMPLES]; speex_decoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N); ret = (*((SpeexMode**)state))->dec(state, bits, short_out); @@ -136,7 +136,7 @@ int speex_encode(void *state, float *in, SpeexBits *bits) int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) { int i; - int N; + spx_int32_t N; float float_in[MAX_IN_SAMPLES]; speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N); for (i=0;i<N;i++) @@ -152,7 +152,7 @@ int speex_decode(void *state, SpeexBits *bits, float *out) int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out) { int i; - int N; + spx_int32_t N; float float_out[MAX_IN_SAMPLES]; int ret; speex_decoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N); diff --git a/libspeex/speex_callbacks.c b/libspeex/speex_callbacks.c index 0b99188..682322e 100644 --- a/libspeex/speex_callbacks.c +++ b/libspeex/speex_callbacks.c @@ -73,7 +73,7 @@ int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *st int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data) { - int m; + spx_int32_t m; m = speex_bits_unpack_unsigned(bits, 4); speex_encoder_ctl(data, SPEEX_SET_MODE, &m); return 0; @@ -81,7 +81,7 @@ int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data) int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data) { - int m; + spx_int32_t m; m = speex_bits_unpack_unsigned(bits, 4); speex_encoder_ctl(data, SPEEX_SET_LOW_MODE, &m); return 0; @@ -89,7 +89,7 @@ int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data) int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data) { - int m; + spx_int32_t m; m = speex_bits_unpack_unsigned(bits, 4); speex_encoder_ctl(data, SPEEX_SET_HIGH_MODE, &m); return 0; @@ -97,7 +97,7 @@ int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data) { - int vbr; + spx_int32_t vbr; vbr = speex_bits_unpack_unsigned(bits, 1); speex_encoder_ctl(data, SPEEX_SET_VBR, &vbr); return 0; @@ -105,7 +105,7 @@ int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data) int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data) { - int enh; + spx_int32_t enh; enh = speex_bits_unpack_unsigned(bits, 1); speex_decoder_ctl(data, SPEEX_SET_ENH, &enh); return 0; @@ -113,7 +113,7 @@ int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data) int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data) { - int qual; + float qual; qual = speex_bits_unpack_unsigned(bits, 4); speex_encoder_ctl(data, SPEEX_SET_VBR_QUALITY, &qual); return 0; diff --git a/libspeex/speex_header.c b/libspeex/speex_header.c index 7fc2f5a..8e10851 100644 --- a/libspeex/speex_header.c +++ b/libspeex/speex_header.c @@ -133,14 +133,14 @@ SpeexHeader *speex_packet_to_header(char *packet, int size) for (i=0;i<8;i++) if (packet[i]!=h[i]) { - speex_warning ("This doesn't look like a Speex file"); + speex_notify("This doesn't look like a Speex file"); return NULL; } /*FIXME: Do we allow larger headers?*/ if (size < (int)sizeof(SpeexHeader)) { - speex_warning("Speex header too small"); + speex_notify("Speex header too small"); return NULL; } diff --git a/libspeex/testdenoise.c b/libspeex/testdenoise.c index 177227d..42644cb 100644 --- a/libspeex/testdenoise.c +++ b/libspeex/testdenoise.c @@ -24,9 +24,9 @@ int main() speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f); i=0; speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB, &i); - f=.4; + f=.0; speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f); - f=.3; + f=.0; speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f); while (1) { @@ -34,7 +34,7 @@ int main() fread(in, sizeof(short), NN, stdin); if (feof(stdin)) break; - vad = speex_preprocess(st, in, NULL); + vad = speex_preprocess_run(st, in); /*fprintf (stderr, "%d\n", vad);*/ fwrite(in, sizeof(short), NN, stdout); count++; diff --git a/libspeex/testecho.c b/libspeex/testecho.c index fc5bf34..60d76d5 100644 --- a/libspeex/testecho.c +++ b/libspeex/testecho.c @@ -18,7 +18,6 @@ int main(int argc, char **argv) { int echo_fd, ref_fd, e_fd; - spx_int32_t noise[NN+1]; short echo_buf[NN], ref_buf[NN], e_buf[NN]; SpeexEchoState *st; SpeexPreprocessState *den; @@ -36,12 +35,13 @@ int main(int argc, char **argv) den = speex_preprocess_state_init(NN, 8000); int tmp = 8000; mc_echo_ctl(st, SPEEX_ECHO_SET_SAMPLING_RATE, &tmp); + speex_preprocess_ctl(den, SPEEX_PREPROCESS_SET_ECHO_STATE, st); while (read(ref_fd, ref_buf, NN*2)) { read(echo_fd, echo_buf, NN*2); - mc_echo_cancel(st, ref_buf, echo_buf, e_buf, noise); - /*speex_preprocess(den, e_buf, noise);*/ + mc_echo_cancellation(st, ref_buf, echo_buf, e_buf); + speex_preprocess_run(den, e_buf); write(e_fd, e_buf, NN*2); } mc_echo_state_destroy(st); diff --git a/libspeex/testenc.c b/libspeex/testenc.c index a7ad409..eabd02c 100644 --- a/libspeex/testenc.c +++ b/libspeex/testenc.c @@ -27,9 +27,9 @@ int main(int argc, char **argv) void *st; void *dec; SpeexBits bits; - int tmp; + spx_int32_t tmp; int bitCount=0; - int skip_group_delay; + spx_int32_t skip_group_delay; SpeexCallback callback; sigpow = 0; diff --git a/libspeex/testenc_uwb.c b/libspeex/testenc_uwb.c index 7512336..e9bf18a 100644 --- a/libspeex/testenc_uwb.c +++ b/libspeex/testenc_uwb.c @@ -28,9 +28,9 @@ int main(int argc, char **argv) void *st; void *dec; SpeexBits bits; - int tmp; + spx_int32_t tmp; int bitCount=0; - int skip_group_delay; + spx_int32_t skip_group_delay; SpeexCallback callback; sigpow = 0; diff --git a/libspeex/testenc_wb.c b/libspeex/testenc_wb.c index 7a19189..8e515cb 100644 --- a/libspeex/testenc_wb.c +++ b/libspeex/testenc_wb.c @@ -28,9 +28,9 @@ int main(int argc, char **argv) void *st; void *dec; SpeexBits bits; - int tmp; + spx_int32_t tmp; int bitCount=0; - int skip_group_delay; + spx_int32_t skip_group_delay; SpeexCallback callback; sigpow = 0; diff --git a/libspeex/testresample.c b/libspeex/testresample.c new file mode 100644 index 0000000..71392cc --- /dev/null +++ b/libspeex/testresample.c @@ -0,0 +1,86 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: testresample.c + Testing the resampling code + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include "speex/speex_resampler.h" +#include <math.h> +#include <stdlib.h> + +#define NN 256 + +int main() +{ + spx_uint32_t i; + short *in; + short *out; + float *fin, *fout; + int count = 0; + SpeexResamplerState *st = speex_resampler_init(1, 8000, 12000, 10, NULL); + speex_resampler_set_rate(st, 96000, 44100); + speex_resampler_skip_zeros(st); + + in = malloc(NN*sizeof(short)); + out = malloc(2*NN*sizeof(short)); + fin = malloc(NN*sizeof(float)); + fout = malloc(2*NN*sizeof(float)); + while (1) + { + spx_uint32_t in_len; + spx_uint32_t out_len; + fread(in, sizeof(short), NN, stdin); + if (feof(stdin)) + break; + for (i=0;i<NN;i++) + fin[i]=in[i]; + in_len = NN; + out_len = 2*NN; + /*if (count==2) + speex_resampler_set_quality(st, 10);*/ + speex_resampler_process_float(st, 0, fin, &in_len, fout, &out_len); + for (i=0;i<out_len;i++) + out[i]=floor(.5+fout[i]); + /*speex_warning_int("writing", out_len);*/ + fwrite(out, sizeof(short), out_len, stdout); + count++; + } + speex_resampler_destroy(st); + free(in); + free(out); + free(fin); + free(fout); + return 0; +} + diff --git a/libspeex/vbr.c b/libspeex/vbr.c index bfd1fa6..d24ec0f 100644 --- a/libspeex/vbr.c +++ b/libspeex/vbr.c @@ -47,29 +47,29 @@ const float vbr_nb_thresh[9][11]={ - {-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0}, /* CNG */ - { 3.5, 2.5, 2.0, 1.2, 0.5, 0.0, -0.5, -0.7, -0.8, -0.9, -1.0}, /* 2 kbps */ - {10.0, 6.5, 5.2, 4.5, 3.9, 3.5, 3.0, 2.5, 2.3, 1.8, 1.0}, /* 6 kbps */ - {11.0, 8.8, 7.5, 6.5, 5.0, 3.9, 3.9, 3.9, 3.5, 3.0, 1.0}, /* 8 kbps */ - {11.0, 11.0, 9.9, 9.0, 8.0, 7.0, 6.5, 6.0, 5.0, 4.0, 2.0}, /* 11 kbps */ - {11.0, 11.0, 11.0, 11.0, 9.5, 9.0, 8.0, 7.0, 6.5, 5.0, 3.0}, /* 15 kbps */ - {11.0, 11.0, 11.0, 11.0, 11.0, 11.0, 9.5, 8.5, 8.0, 6.5, 4.0}, /* 18 kbps */ - {11.0, 11.0, 11.0, 11.0, 11.0, 11.0, 11.0, 11.0, 9.8, 7.5, 5.5}, /* 24 kbps */ - { 8.0, 5.0, 3.7, 3.0, 2.5, 2.0, 1.8, 1.5, 1.0, 0.0, 0.0} /* 4 kbps */ + {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /* CNG */ + { 3.5f, 2.5f, 2.0f, 1.2f, 0.5f, 0.0f, -0.5f, -0.7f, -0.8f, -0.9f, -1.0f}, /* 2 kbps */ + {10.0f, 6.5f, 5.2f, 4.5f, 3.9f, 3.5f, 3.0f, 2.5f, 2.3f, 1.8f, 1.0f}, /* 6 kbps */ + {11.0f, 8.8f, 7.5f, 6.5f, 5.0f, 3.9f, 3.9f, 3.9f, 3.5f, 3.0f, 1.0f}, /* 8 kbps */ + {11.0f, 11.0f, 9.9f, 9.0f, 8.0f, 7.0f, 6.5f, 6.0f, 5.0f, 4.0f, 2.0f}, /* 11 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 9.5f, 9.0f, 8.0f, 7.0f, 6.5f, 5.0f, 3.0f}, /* 15 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 9.5f, 8.5f, 8.0f, 6.5f, 4.0f}, /* 18 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 9.8f, 7.5f, 5.5f}, /* 24 kbps */ + { 8.0f, 5.0f, 3.7f, 3.0f, 2.5f, 2.0f, 1.8f, 1.5f, 1.0f, 0.0f, 0.0f} /* 4 kbps */ }; const float vbr_hb_thresh[5][11]={ - {-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0}, /* silence */ - {-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0}, /* 2 kbps */ - {11.0, 11.0, 9.5, 8.5, 7.5, 6.0, 5.0, 3.9, 3.0, 2.0, 1.0}, /* 6 kbps */ - {11.0, 11.0, 11.0, 11.0, 11.0, 9.5, 8.7, 7.8, 7.0, 6.5, 4.0}, /* 10 kbps */ - {11.0, 11.0, 11.0, 11.0, 11.0, 11.0, 11.0, 11.0, 9.8, 7.5, 5.5} /* 18 kbps */ + {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /* silence */ + {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /* 2 kbps */ + {11.0f, 11.0f, 9.5f, 8.5f, 7.5f, 6.0f, 5.0f, 3.9f, 3.0f, 2.0f, 1.0f}, /* 6 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 9.5f, 8.7f, 7.8f, 7.0f, 6.5f, 4.0f}, /* 10 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 9.8f, 7.5f, 5.5f} /* 18 kbps */ }; const float vbr_uhb_thresh[2][11]={ - {-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0}, /* silence */ - { 3.9, 2.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0} /* 2 kbps */ + {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /* silence */ + { 3.9f, 2.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f} /* 2 kbps */ }; void vbr_init(VBRState *vbr) diff --git a/libspeex/window.c b/libspeex/window.c index 3748f65..65b1917 100644 --- a/libspeex/window.c +++ b/libspeex/window.c @@ -65,30 +65,30 @@ const spx_word16_t lpc_window[200] = { }; #else const spx_word16_t lpc_window[200] = { - 0.080000, 0.080158, 0.080630, 0.081418, 0.082520, 0.083935, 0.085663, 0.087703, - 0.090052, 0.092710, 0.095674, 0.098943, 0.102514, 0.106385, 0.110553, 0.115015, - 0.119769, 0.124811, 0.130137, 0.135744, 0.141628, 0.147786, 0.154212, 0.160902, - 0.167852, 0.175057, 0.182513, 0.190213, 0.198153, 0.206328, 0.214731, 0.223357, - 0.232200, 0.241254, 0.250513, 0.259970, 0.269619, 0.279453, 0.289466, 0.299651, - 0.310000, 0.320507, 0.331164, 0.341965, 0.352901, 0.363966, 0.375151, 0.386449, - 0.397852, 0.409353, 0.420943, 0.432615, 0.444361, 0.456172, 0.468040, 0.479958, - 0.491917, 0.503909, 0.515925, 0.527959, 0.540000, 0.552041, 0.564075, 0.576091, - 0.588083, 0.600042, 0.611960, 0.623828, 0.635639, 0.647385, 0.659057, 0.670647, - 0.682148, 0.693551, 0.704849, 0.716034, 0.727099, 0.738035, 0.748836, 0.759493, - 0.770000, 0.780349, 0.790534, 0.800547, 0.810381, 0.820030, 0.829487, 0.838746, - 0.847800, 0.856643, 0.865269, 0.873672, 0.881847, 0.889787, 0.897487, 0.904943, - 0.912148, 0.919098, 0.925788, 0.932214, 0.938372, 0.944256, 0.949863, 0.955189, - 0.960231, 0.964985, 0.969447, 0.973615, 0.977486, 0.981057, 0.984326, 0.987290, - 0.989948, 0.992297, 0.994337, 0.996065, 0.997480, 0.998582, 0.999370, 0.999842, - 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, - 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, - 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, - 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, - 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, - 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, - 1.000000, 1.000000, 1.000000, 0.998640, 0.994566, 0.987787, 0.978324, 0.966203, - 0.951458, 0.934131, 0.914270, 0.891931, 0.867179, 0.840084, 0.810723, 0.779182, - 0.745551, 0.709930, 0.672424, 0.633148, 0.592223, 0.549781, 0.505964, 0.460932, - 0.414863, 0.367968, 0.320511, 0.272858, 0.225569, 0.179655, 0.137254, 0.103524 + 0.080000f, 0.080158f, 0.080630f, 0.081418f, 0.082520f, 0.083935f, 0.085663f, 0.087703f, + 0.090052f, 0.092710f, 0.095674f, 0.098943f, 0.102514f, 0.106385f, 0.110553f, 0.115015f, + 0.119769f, 0.124811f, 0.130137f, 0.135744f, 0.141628f, 0.147786f, 0.154212f, 0.160902f, + 0.167852f, 0.175057f, 0.182513f, 0.190213f, 0.198153f, 0.206328f, 0.214731f, 0.223357f, + 0.232200f, 0.241254f, 0.250513f, 0.259970f, 0.269619f, 0.279453f, 0.289466f, 0.299651f, + 0.310000f, 0.320507f, 0.331164f, 0.341965f, 0.352901f, 0.363966f, 0.375151f, 0.386449f, + 0.397852f, 0.409353f, 0.420943f, 0.432615f, 0.444361f, 0.456172f, 0.468040f, 0.479958f, + 0.491917f, 0.503909f, 0.515925f, 0.527959f, 0.540000f, 0.552041f, 0.564075f, 0.576091f, + 0.588083f, 0.600042f, 0.611960f, 0.623828f, 0.635639f, 0.647385f, 0.659057f, 0.670647f, + 0.682148f, 0.693551f, 0.704849f, 0.716034f, 0.727099f, 0.738035f, 0.748836f, 0.759493f, + 0.770000f, 0.780349f, 0.790534f, 0.800547f, 0.810381f, 0.820030f, 0.829487f, 0.838746f, + 0.847800f, 0.856643f, 0.865269f, 0.873672f, 0.881847f, 0.889787f, 0.897487f, 0.904943f, + 0.912148f, 0.919098f, 0.925788f, 0.932214f, 0.938372f, 0.944256f, 0.949863f, 0.955189f, + 0.960231f, 0.964985f, 0.969447f, 0.973615f, 0.977486f, 0.981057f, 0.984326f, 0.987290f, + 0.989948f, 0.992297f, 0.994337f, 0.996065f, 0.997480f, 0.998582f, 0.999370f, 0.999842f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 0.998640f, 0.994566f, 0.987787f, 0.978324f, 0.966203f, + 0.951458f, 0.934131f, 0.914270f, 0.891931f, 0.867179f, 0.840084f, 0.810723f, 0.779182f, + 0.745551f, 0.709930f, 0.672424f, 0.633148f, 0.592223f, 0.549781f, 0.505964f, 0.460932f, + 0.414863f, 0.367968f, 0.320511f, 0.272858f, 0.225569f, 0.179655f, 0.137254f, 0.103524f }; #endif diff --git a/macosx/Speex.xcodeproj/project.pbxproj b/macosx/Speex.xcodeproj/project.pbxproj index 12df677..ec111a6 100644 --- a/macosx/Speex.xcodeproj/project.pbxproj +++ b/macosx/Speex.xcodeproj/project.pbxproj @@ -50,34 +50,66 @@ 73814B990907FC9900C478FC /* stereo.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B4C0907FC9900C478FC /* stereo.c */; }; 73814B9F0907FC9900C478FC /* vbr.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B520907FC9900C478FC /* vbr.c */; }; 73814BA40907FC9900C478FC /* vq.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B570907FC9900C478FC /* vq.c */; }; + 738837440B1934D0005C7A69 /* mdf.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B390907FC9900C478FC /* mdf.c */; }; + 738837540B193581005C7A69 /* _kiss_fft_guts.h in Headers */ = {isa = PBXBuildFile; fileRef = 738837460B193581005C7A69 /* _kiss_fft_guts.h */; }; + 738837550B193581005C7A69 /* fftwrap.c in Sources */ = {isa = PBXBuildFile; fileRef = 738837470B193581005C7A69 /* fftwrap.c */; }; + 738837560B193581005C7A69 /* fftwrap.h in Headers */ = {isa = PBXBuildFile; fileRef = 738837480B193581005C7A69 /* fftwrap.h */; }; + 738837570B193581005C7A69 /* filterbank.c in Sources */ = {isa = PBXBuildFile; fileRef = 738837490B193581005C7A69 /* filterbank.c */; }; + 738837580B193581005C7A69 /* filterbank.h in Headers */ = {isa = PBXBuildFile; fileRef = 7388374A0B193581005C7A69 /* filterbank.h */; }; + 738837590B193581005C7A69 /* kiss_fft.c in Sources */ = {isa = PBXBuildFile; fileRef = 7388374B0B193581005C7A69 /* kiss_fft.c */; }; + 7388375A0B193581005C7A69 /* kiss_fft.h in Headers */ = {isa = PBXBuildFile; fileRef = 7388374C0B193581005C7A69 /* kiss_fft.h */; }; + 7388375B0B193581005C7A69 /* kiss_fftr.c in Sources */ = {isa = PBXBuildFile; fileRef = 7388374D0B193581005C7A69 /* kiss_fftr.c */; }; + 7388375C0B193581005C7A69 /* kiss_fftr.h in Headers */ = {isa = PBXBuildFile; fileRef = 7388374E0B193581005C7A69 /* kiss_fftr.h */; }; + 7388375D0B193581005C7A69 /* lsp_bfin.h in Headers */ = {isa = PBXBuildFile; fileRef = 7388374F0B193581005C7A69 /* lsp_bfin.h */; }; + 7388375E0B193581005C7A69 /* pseudofloat.h in Headers */ = {isa = PBXBuildFile; fileRef = 738837500B193581005C7A69 /* pseudofloat.h */; }; + 7388375F0B193581005C7A69 /* quant_lsp_bfin.h in Headers */ = {isa = PBXBuildFile; fileRef = 738837510B193581005C7A69 /* quant_lsp_bfin.h */; }; + 738837600B193581005C7A69 /* vorbis_psy.c in Sources */ = {isa = PBXBuildFile; fileRef = 738837520B193581005C7A69 /* vorbis_psy.c */; }; + 738837610B193581005C7A69 /* vorbis_psy.h in Headers */ = {isa = PBXBuildFile; fileRef = 738837530B193581005C7A69 /* vorbis_psy.h */; }; + 7388377B0B193784005C7A69 /* bits.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B0D0907FC9900C478FC /* bits.c */; }; + 7388377C0B193785005C7A69 /* cb_search.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B110907FC9900C478FC /* cb_search.c */; }; + 7388377D0B193788005C7A69 /* exc_10_16_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B160907FC9900C478FC /* exc_10_16_table.c */; }; + 7388377E0B193789005C7A69 /* exc_10_32_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B170907FC9900C478FC /* exc_10_32_table.c */; }; + 7388377F0B19378A005C7A69 /* exc_20_32_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B180907FC9900C478FC /* exc_20_32_table.c */; }; + 738837800B19378A005C7A69 /* exc_5_256_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B140907FC9900C478FC /* exc_5_256_table.c */; }; + 738837810B19378C005C7A69 /* exc_5_64_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B130907FC9900C478FC /* exc_5_64_table.c */; }; + 738837820B19378E005C7A69 /* exc_8_128_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B150907FC9900C478FC /* exc_8_128_table.c */; }; + 738837830B193791005C7A69 /* fftwrap.c in Sources */ = {isa = PBXBuildFile; fileRef = 738837470B193581005C7A69 /* fftwrap.c */; }; + 738837840B193792005C7A69 /* filterbank.c in Sources */ = {isa = PBXBuildFile; fileRef = 738837490B193581005C7A69 /* filterbank.c */; }; + 738837850B193793005C7A69 /* filters.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B1C0907FC9900C478FC /* filters.c */; }; + 738837860B193795005C7A69 /* gain_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B240907FC9900C478FC /* gain_table.c */; }; + 738837870B193796005C7A69 /* gain_table_lbr.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B230907FC9900C478FC /* gain_table_lbr.c */; }; + 738837880B193799005C7A69 /* hexc_10_32_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B250907FC9900C478FC /* hexc_10_32_table.c */; }; + 738837890B19379B005C7A69 /* hexc_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B260907FC9900C478FC /* hexc_table.c */; }; + 7388378A0B19379E005C7A69 /* high_lsp_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B270907FC9900C478FC /* high_lsp_tables.c */; }; + 7388378B0B1937A0005C7A69 /* jitter.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B280907FC9900C478FC /* jitter.c */; }; + 7388378C0B1937A4005C7A69 /* kiss_fft.c in Sources */ = {isa = PBXBuildFile; fileRef = 7388374B0B193581005C7A69 /* kiss_fft.c */; }; + 7388378D0B1937A9005C7A69 /* kiss_fftr.c in Sources */ = {isa = PBXBuildFile; fileRef = 7388374D0B193581005C7A69 /* kiss_fftr.c */; }; + 7388378E0B1937AE005C7A69 /* lbr_48k_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B290907FC9900C478FC /* lbr_48k_tables.c */; }; + 7388378F0B1937B0005C7A69 /* lpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B2B0907FC9900C478FC /* lpc.c */; }; + 738837900B1937B0005C7A69 /* lsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B2E0907FC9900C478FC /* lsp.c */; }; + 738837910B1937B5005C7A69 /* lsp_tables_nb.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B2D0907FC9900C478FC /* lsp_tables_nb.c */; }; + 738837920B1937B7005C7A69 /* ltp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B330907FC9900C478FC /* ltp.c */; }; + 738837930B1937B9005C7A69 /* math_approx.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B370907FC9900C478FC /* math_approx.c */; }; + 738837940B1937BB005C7A69 /* mdf.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B390907FC9900C478FC /* mdf.c */; }; + 738837950B1937BD005C7A69 /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B3B0907FC9900C478FC /* misc.c */; }; + 738837960B1937BE005C7A69 /* modes.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B3D0907FC9900C478FC /* modes.c */; }; + 738837970B1937C0005C7A69 /* nb_celp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B3F0907FC9900C478FC /* nb_celp.c */; }; + 738837980B1937C2005C7A69 /* preprocess.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B410907FC9900C478FC /* preprocess.c */; }; + 738837990B1937C4005C7A69 /* quant_lsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B420907FC9900C478FC /* quant_lsp.c */; }; + 7388379A0B1937C6005C7A69 /* sb_celp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B440907FC9900C478FC /* sb_celp.c */; }; + 7388379B0B1937C9005C7A69 /* smallft.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B460907FC9900C478FC /* smallft.c */; }; + 7388379C0B1937CB005C7A69 /* speex.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B4A0907FC9900C478FC /* speex.c */; }; + 7388379D0B1937CE005C7A69 /* speex_callbacks.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B480907FC9900C478FC /* speex_callbacks.c */; }; + 7388379E0B1937D0005C7A69 /* speex_header.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B490907FC9900C478FC /* speex_header.c */; }; + 7388379F0B1937D1005C7A69 /* stereo.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B4C0907FC9900C478FC /* stereo.c */; }; + 738837A00B1937DA005C7A69 /* vbr.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B520907FC9900C478FC /* vbr.c */; }; + 738837A10B1937DD005C7A69 /* vorbis_psy.c in Sources */ = {isa = PBXBuildFile; fileRef = 738837520B193581005C7A69 /* vorbis_psy.c */; }; + 738837A20B1937DF005C7A69 /* vq.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B570907FC9900C478FC /* vq.c */; }; + 738837A30B1937E1005C7A69 /* window.c in Sources */ = {isa = PBXBuildFile; fileRef = BFF73DCF0A78AA170078A4A8 /* window.c */; }; 8D07F2C00486CC7A007CD1D0 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; }; BFF73DD00A78AA170078A4A8 /* window.c in Sources */ = {isa = PBXBuildFile; fileRef = BFF73DCF0A78AA170078A4A8 /* window.c */; }; /* End PBXBuildFile section */ -/* Begin PBXBuildStyle section */ - 4F0BB7EC011F40E904CA0E50 /* Development */ = { - isa = PBXBuildStyle; - buildSettings = { - COPY_PHASE_STRIP = NO; - GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_FIX_AND_CONTINUE = YES; - GCC_GENERATE_DEBUGGING_SYMBOLS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - ZERO_LINK = YES; - }; - name = Development; - }; - 4F0BB7ED011F40E904CA0E50 /* Deployment */ = { - isa = PBXBuildStyle; - buildSettings = { - COPY_PHASE_STRIP = YES; - GCC_ENABLE_FIX_AND_CONTINUE = NO; - ZERO_LINK = NO; - }; - name = Deployment; - }; -/* End PBXBuildStyle section */ - /* Begin PBXFileReference section */ 089C1667FE841158C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; }; 32BAE0B70371A74B00C91783 /* Speex_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Speex_Prefix.pch; sourceTree = "<group>"; }; @@ -165,12 +197,34 @@ 73814B560907FC9900C478FC /* vq_sse.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = vq_sse.h; path = ../libspeex/vq_sse.h; sourceTree = SOURCE_ROOT; }; 73814B570907FC9900C478FC /* vq.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = vq.c; path = ../libspeex/vq.c; sourceTree = SOURCE_ROOT; }; 73814B580907FC9900C478FC /* vq.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = vq.h; path = ../libspeex/vq.h; sourceTree = SOURCE_ROOT; }; + 738837460B193581005C7A69 /* _kiss_fft_guts.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = _kiss_fft_guts.h; path = ../libspeex/_kiss_fft_guts.h; sourceTree = SOURCE_ROOT; }; + 738837470B193581005C7A69 /* fftwrap.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = fftwrap.c; path = ../libspeex/fftwrap.c; sourceTree = SOURCE_ROOT; }; + 738837480B193581005C7A69 /* fftwrap.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = fftwrap.h; path = ../libspeex/fftwrap.h; sourceTree = SOURCE_ROOT; }; + 738837490B193581005C7A69 /* filterbank.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = filterbank.c; path = ../libspeex/filterbank.c; sourceTree = SOURCE_ROOT; }; + 7388374A0B193581005C7A69 /* filterbank.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = filterbank.h; path = ../libspeex/filterbank.h; sourceTree = SOURCE_ROOT; }; + 7388374B0B193581005C7A69 /* kiss_fft.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = kiss_fft.c; path = ../libspeex/kiss_fft.c; sourceTree = SOURCE_ROOT; }; + 7388374C0B193581005C7A69 /* kiss_fft.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = kiss_fft.h; path = ../libspeex/kiss_fft.h; sourceTree = SOURCE_ROOT; }; + 7388374D0B193581005C7A69 /* kiss_fftr.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = kiss_fftr.c; path = ../libspeex/kiss_fftr.c; sourceTree = SOURCE_ROOT; }; + 7388374E0B193581005C7A69 /* kiss_fftr.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = kiss_fftr.h; path = ../libspeex/kiss_fftr.h; sourceTree = SOURCE_ROOT; }; + 7388374F0B193581005C7A69 /* lsp_bfin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = lsp_bfin.h; path = ../libspeex/lsp_bfin.h; sourceTree = SOURCE_ROOT; }; + 738837500B193581005C7A69 /* pseudofloat.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = pseudofloat.h; path = ../libspeex/pseudofloat.h; sourceTree = SOURCE_ROOT; }; + 738837510B193581005C7A69 /* quant_lsp_bfin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = quant_lsp_bfin.h; path = ../libspeex/quant_lsp_bfin.h; sourceTree = SOURCE_ROOT; }; + 738837520B193581005C7A69 /* vorbis_psy.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = vorbis_psy.c; path = ../libspeex/vorbis_psy.c; sourceTree = SOURCE_ROOT; }; + 738837530B193581005C7A69 /* vorbis_psy.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = vorbis_psy.h; path = ../libspeex/vorbis_psy.h; sourceTree = SOURCE_ROOT; }; + 738837770B193667005C7A69 /* libspeex.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libspeex.a; sourceTree = BUILT_PRODUCTS_DIR; }; 8D07F2C70486CC7A007CD1D0 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; }; 8D07F2C80486CC7A007CD1D0 /* Speex.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Speex.framework; sourceTree = BUILT_PRODUCTS_DIR; }; BFF73DCF0A78AA170078A4A8 /* window.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = window.c; path = ../libspeex/window.c; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 738837750B193667005C7A69 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 8D07F2C30486CC7A007CD1D0 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -185,6 +239,7 @@ isa = PBXGroup; children = ( 8D07F2C80486CC7A007CD1D0 /* Speex.framework */, + 738837770B193667005C7A69 /* libspeex.a */, ); name = Products; sourceTree = "<group>"; @@ -220,6 +275,20 @@ 08FB77ACFE841707C02AAC07 /* Source */ = { isa = PBXGroup; children = ( + 738837460B193581005C7A69 /* _kiss_fft_guts.h */, + 738837470B193581005C7A69 /* fftwrap.c */, + 738837480B193581005C7A69 /* fftwrap.h */, + 738837490B193581005C7A69 /* filterbank.c */, + 7388374A0B193581005C7A69 /* filterbank.h */, + 7388374B0B193581005C7A69 /* kiss_fft.c */, + 7388374C0B193581005C7A69 /* kiss_fft.h */, + 7388374D0B193581005C7A69 /* kiss_fftr.c */, + 7388374E0B193581005C7A69 /* kiss_fftr.h */, + 7388374F0B193581005C7A69 /* lsp_bfin.h */, + 738837500B193581005C7A69 /* pseudofloat.h */, + 738837510B193581005C7A69 /* quant_lsp_bfin.h */, + 738837520B193581005C7A69 /* vorbis_psy.c */, + 738837530B193581005C7A69 /* vorbis_psy.h */, 73814B0C0907FC9900C478FC /* arch.h */, 73814B0D0907FC9900C478FC /* bits.c */, 73814B0E0907FC9900C478FC /* cb_search_arm4.h */, @@ -329,6 +398,13 @@ /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ + 738837730B193667005C7A69 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 8D07F2BD0486CC7A007CD1D0 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -342,12 +418,38 @@ 73814B060907FBAB00C478FC /* speex_callbacks.h in Headers */, 73814B070907FBAD00C478FC /* speex_bits.h in Headers */, 73814B080907FBAE00C478FC /* speex.h in Headers */, + 738837540B193581005C7A69 /* _kiss_fft_guts.h in Headers */, + 738837560B193581005C7A69 /* fftwrap.h in Headers */, + 738837580B193581005C7A69 /* filterbank.h in Headers */, + 7388375A0B193581005C7A69 /* kiss_fft.h in Headers */, + 7388375C0B193581005C7A69 /* kiss_fftr.h in Headers */, + 7388375D0B193581005C7A69 /* lsp_bfin.h in Headers */, + 7388375E0B193581005C7A69 /* pseudofloat.h in Headers */, + 7388375F0B193581005C7A69 /* quant_lsp_bfin.h in Headers */, + 738837610B193581005C7A69 /* vorbis_psy.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + 738837760B193667005C7A69 /* libspeex (static) */ = { + isa = PBXNativeTarget; + buildConfigurationList = 738837780B193687005C7A69 /* Build configuration list for PBXNativeTarget "libspeex (static)" */; + buildPhases = ( + 738837730B193667005C7A69 /* Headers */, + 738837740B193667005C7A69 /* Sources */, + 738837750B193667005C7A69 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "libspeex (static)"; + productName = speex; + productReference = 738837770B193667005C7A69 /* libspeex.a */; + productType = "com.apple.product-type.library.static"; + }; 8D07F2BC0486CC7A007CD1D0 /* Speex */ = { isa = PBXNativeTarget; buildConfigurationList = 73814ADF0907FB1E00C478FC /* Build configuration list for PBXNativeTarget "Speex" */; @@ -360,19 +462,6 @@ ); buildRules = ( ); - buildSettings = { - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - FRAMEWORK_VERSION = A; - GCC_GENERATE_DEBUGGING_SYMBOLS = NO; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = Speex_Prefix.pch; - INFOPLIST_FILE = Info.plist; - INSTALL_PATH = "$(HOME)/Library/Frameworks"; - LIBRARY_STYLE = DYNAMIC; - PRODUCT_NAME = Speex; - WRAPPER_EXTENSION = framework; - }; dependencies = ( ); name = Speex; @@ -387,18 +476,13 @@ 0867D690FE84028FC02AAC07 /* Project object */ = { isa = PBXProject; buildConfigurationList = 73814AE30907FB1E00C478FC /* Build configuration list for PBXProject "Speex" */; - buildSettings = { - }; - buildStyles = ( - 4F0BB7EC011F40E904CA0E50 /* Development */, - 4F0BB7ED011F40E904CA0E50 /* Deployment */, - ); hasScannedForEncodings = 1; mainGroup = 0867D691FE84028FC02AAC07 /* Speex */; productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */; projectDirPath = ""; targets = ( 8D07F2BC0486CC7A007CD1D0 /* Speex */, + 738837760B193667005C7A69 /* libspeex (static) */, ); }; /* End PBXProject section */ @@ -425,6 +509,54 @@ /* End PBXRezBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 738837740B193667005C7A69 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 7388377B0B193784005C7A69 /* bits.c in Sources */, + 7388377C0B193785005C7A69 /* cb_search.c in Sources */, + 7388377D0B193788005C7A69 /* exc_10_16_table.c in Sources */, + 7388377E0B193789005C7A69 /* exc_10_32_table.c in Sources */, + 7388377F0B19378A005C7A69 /* exc_20_32_table.c in Sources */, + 738837800B19378A005C7A69 /* exc_5_256_table.c in Sources */, + 738837810B19378C005C7A69 /* exc_5_64_table.c in Sources */, + 738837820B19378E005C7A69 /* exc_8_128_table.c in Sources */, + 738837830B193791005C7A69 /* fftwrap.c in Sources */, + 738837840B193792005C7A69 /* filterbank.c in Sources */, + 738837850B193793005C7A69 /* filters.c in Sources */, + 738837860B193795005C7A69 /* gain_table.c in Sources */, + 738837870B193796005C7A69 /* gain_table_lbr.c in Sources */, + 738837880B193799005C7A69 /* hexc_10_32_table.c in Sources */, + 738837890B19379B005C7A69 /* hexc_table.c in Sources */, + 7388378A0B19379E005C7A69 /* high_lsp_tables.c in Sources */, + 7388378B0B1937A0005C7A69 /* jitter.c in Sources */, + 7388378C0B1937A4005C7A69 /* kiss_fft.c in Sources */, + 7388378D0B1937A9005C7A69 /* kiss_fftr.c in Sources */, + 7388378E0B1937AE005C7A69 /* lbr_48k_tables.c in Sources */, + 7388378F0B1937B0005C7A69 /* lpc.c in Sources */, + 738837900B1937B0005C7A69 /* lsp.c in Sources */, + 738837910B1937B5005C7A69 /* lsp_tables_nb.c in Sources */, + 738837920B1937B7005C7A69 /* ltp.c in Sources */, + 738837930B1937B9005C7A69 /* math_approx.c in Sources */, + 738837940B1937BB005C7A69 /* mdf.c in Sources */, + 738837950B1937BD005C7A69 /* misc.c in Sources */, + 738837960B1937BE005C7A69 /* modes.c in Sources */, + 738837970B1937C0005C7A69 /* nb_celp.c in Sources */, + 738837980B1937C2005C7A69 /* preprocess.c in Sources */, + 738837990B1937C4005C7A69 /* quant_lsp.c in Sources */, + 7388379A0B1937C6005C7A69 /* sb_celp.c in Sources */, + 7388379B0B1937C9005C7A69 /* smallft.c in Sources */, + 7388379C0B1937CB005C7A69 /* speex.c in Sources */, + 7388379D0B1937CE005C7A69 /* speex_callbacks.c in Sources */, + 7388379E0B1937D0005C7A69 /* speex_header.c in Sources */, + 7388379F0B1937D1005C7A69 /* stereo.c in Sources */, + 738837A00B1937DA005C7A69 /* vbr.c in Sources */, + 738837A10B1937DD005C7A69 /* vorbis_psy.c in Sources */, + 738837A20B1937DF005C7A69 /* vq.c in Sources */, + 738837A30B1937E1005C7A69 /* window.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 8D07F2C10486CC7A007CD1D0 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -464,6 +596,12 @@ 73814B9F0907FC9900C478FC /* vbr.c in Sources */, 73814BA40907FC9900C478FC /* vq.c in Sources */, BFF73DD00A78AA170078A4A8 /* window.c in Sources */, + 738837440B1934D0005C7A69 /* mdf.c in Sources */, + 738837550B193581005C7A69 /* fftwrap.c in Sources */, + 738837570B193581005C7A69 /* filterbank.c in Sources */, + 738837590B193581005C7A69 /* kiss_fft.c in Sources */, + 7388375B0B193581005C7A69 /* kiss_fftr.c in Sources */, + 738837600B193581005C7A69 /* vorbis_psy.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -481,7 +619,7 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ - 73814AE00907FB1E00C478FC /* Development */ = { + 73814AE00907FB1E00C478FC /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; @@ -502,9 +640,9 @@ WRAPPER_EXTENSION = framework; ZERO_LINK = YES; }; - name = Development; + name = Debug; }; - 73814AE10907FB1E00C478FC /* Deployment */ = { + 73814AE10907FB1E00C478FC /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = YES; @@ -523,46 +661,61 @@ WRAPPER_EXTENSION = framework; ZERO_LINK = NO; }; - name = Deployment; + name = Release; }; - 73814AE20907FB1E00C478FC /* Default */ = { + 73814AE40907FB1E00C478FC /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - FRAMEWORK_VERSION = A; - GCC_GENERATE_DEBUGGING_SYMBOLS = NO; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = Speex_Prefix.pch; - INFOPLIST_FILE = Info.plist; - INSTALL_PATH = /Library/Frameworks; - LIBRARY_STYLE = DYNAMIC; - MACH_O_TYPE = mh_dylib; - PRODUCT_NAME = Speex; - WRAPPER_EXTENSION = framework; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = __MACOSX__; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; }; - name = Default; + name = Debug; }; - 73814AE40907FB1E00C478FC /* Development */ = { + 73814AE50907FB1E00C478FC /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ARCHS = ( + ppc, + i386, + ); + GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = __MACOSX__; + OTHER_CFLAGS = ( + "$(OTHER_CFLAGS)", + "-falign-loops=16", + ); + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; }; - name = Development; + name = Release; }; - 73814AE50907FB1E00C478FC /* Deployment */ = { + 738837790B193687005C7A69 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_PREPROCESSOR_DEFINITIONS = __MACOSX__; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + INSTALL_PATH = /usr/local/lib; + PREBINDING = NO; + PRODUCT_NAME = speex; + ZERO_LINK = YES; }; - name = Deployment; + name = Debug; }; - 73814AE60907FB1E00C478FC /* Default */ = { + 7388377A0B193687005C7A69 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_PREPROCESSOR_DEFINITIONS = __MACOSX__; + COPY_PHASE_STRIP = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + INSTALL_PATH = /usr/local/lib; + PREBINDING = NO; + PRODUCT_NAME = speex; + ZERO_LINK = NO; }; - name = Default; + name = Release; }; /* End XCBuildConfiguration section */ @@ -570,22 +723,29 @@ 73814ADF0907FB1E00C478FC /* Build configuration list for PBXNativeTarget "Speex" */ = { isa = XCConfigurationList; buildConfigurations = ( - 73814AE00907FB1E00C478FC /* Development */, - 73814AE10907FB1E00C478FC /* Deployment */, - 73814AE20907FB1E00C478FC /* Default */, + 73814AE00907FB1E00C478FC /* Debug */, + 73814AE10907FB1E00C478FC /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Default; + defaultConfigurationName = Release; }; 73814AE30907FB1E00C478FC /* Build configuration list for PBXProject "Speex" */ = { isa = XCConfigurationList; buildConfigurations = ( - 73814AE40907FB1E00C478FC /* Development */, - 73814AE50907FB1E00C478FC /* Deployment */, - 73814AE60907FB1E00C478FC /* Default */, + 73814AE40907FB1E00C478FC /* Debug */, + 73814AE50907FB1E00C478FC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 738837780B193687005C7A69 /* Build configuration list for PBXNativeTarget "libspeex (static)" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 738837790B193687005C7A69 /* Debug */, + 7388377A0B193687005C7A69 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Default; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/speex.pc.in b/speex.pc.in index 01275d7..6ffe023 100644 --- a/speex.pc.in +++ b/speex.pc.in @@ -10,5 +10,5 @@ Description: Speex is an audio codec tuned for speech Version: @SPEEX_VERSION@ Requires: Conflicts: -Libs: -L${libdir} -lspeex +Libs: -L${libdir} -lspeex -lm Cflags: -I${includedir} diff --git a/speexclient/README b/speexclient/README new file mode 100644 index 0000000..69140d3 --- /dev/null +++ b/speexclient/README @@ -0,0 +1,18 @@ +This is a VERY SIMPLE Speex VoIP client. It is not a complete VoIP application, +isn't compatible with anything else (including probably future versions of +itself) and does not support any form of standard protocols. It is intended +only as a way to show how to use Speex in a VoIP application. + +To use it: + +On Alices machine: +% speexclient plughw:0,0 bob.somewhere.net alice_port bob_port + +On Bob's machine: +% speexclient plughw:0,0 alice.somewhere.net bob_port alice_port + +where bob_port is the UDP port on which bob receives and alice_port is the +UDP port on which alice receives. In most cases, the two ports can be the same. + +Note that the clients do not even know whether they are connected or not. All +they do is send/receive the audio to/from a specific port. diff --git a/speexclient/alsa_device.c b/speexclient/alsa_device.c new file mode 100644 index 0000000..a3a4abb --- /dev/null +++ b/speexclient/alsa_device.c @@ -0,0 +1,431 @@ +/* + Copyright (C) 2004-2006 Jean-Marc Valin + Copyright (C) 2006 Commonwealth Scientific and Industrial Research + Organisation (CSIRO) Australia + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ + +#include "alsa_device.h" +#include <stdlib.h> +#include <alsa/asoundlib.h> + +struct AlsaDevice_ { + char *device_name; + int channels; + int period; + snd_pcm_t *capture_handle; + snd_pcm_t *playback_handle; + int readN, writeN; + struct pollfd *read_fd, *write_fd; +}; + +AlsaDevice *alsa_device_open(char *device_name, unsigned int rate, int channels, int period) +{ + int dir; + int err; + snd_pcm_hw_params_t *hw_params; + snd_pcm_sw_params_t *sw_params; + snd_pcm_uframes_t period_size = period; + snd_pcm_uframes_t buffer_size = 2*period; + static snd_output_t *jcd_out; + AlsaDevice *dev = malloc(sizeof(*dev)); + if (!dev) + return NULL; + dev->device_name = malloc(1+strlen(device_name)); + if (!dev->device_name) + { + free(dev); + return NULL; + } + strcpy(dev->device_name, device_name); + dev->channels = channels; + dev->period = period; + err = snd_output_stdio_attach(&jcd_out, stdout, 0); + + if ((err = snd_pcm_open (&dev->capture_handle, dev->device_name, SND_PCM_STREAM_CAPTURE, 0)) < 0) { + fprintf (stderr, "cannot open audio device %s (%s)\n", + dev->device_name, + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { + fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_any (dev->capture_handle, hw_params)) < 0) { + fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_access (dev->capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { + fprintf (stderr, "cannot set access type (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_format (dev->capture_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { + fprintf (stderr, "cannot set sample format (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_rate_near (dev->capture_handle, hw_params, &rate, 0)) < 0) { + fprintf (stderr, "cannot set sample rate (%s)\n", + snd_strerror (err)); + assert(0); + } + /*fprintf (stderr, "rate = %d\n", rate);*/ + + if ((err = snd_pcm_hw_params_set_channels (dev->capture_handle, hw_params, channels)) < 0) { + fprintf (stderr, "cannot set channel count (%s)\n", + snd_strerror (err)); + assert(0); + } + + period_size = period; + dir = 0; + if ((err = snd_pcm_hw_params_set_period_size_near (dev->capture_handle, hw_params, &period_size, &dir)) < 0) { + fprintf (stderr, "cannot set period size (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_periods (dev->capture_handle, hw_params, 2, 0)) < 0) { + fprintf (stderr, "cannot set number of periods (%s)\n", + snd_strerror (err)); + assert(0); + } + + buffer_size = period_size * 2; + dir=0; + if ((err = snd_pcm_hw_params_set_buffer_size_near (dev->capture_handle, hw_params, &buffer_size)) < 0) { + fprintf (stderr, "cannot set buffer time (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params (dev->capture_handle, hw_params)) < 0) { + fprintf (stderr, "cannot set capture parameters (%s)\n", + snd_strerror (err)); + assert(0); + } + /*snd_pcm_dump_setup(dev->capture_handle, jcd_out);*/ + snd_pcm_hw_params_free (hw_params); + + if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) { + fprintf (stderr, "cannot allocate software parameters structure (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params_current (dev->capture_handle, sw_params)) < 0) { + fprintf (stderr, "cannot initialize software parameters structure (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params_set_avail_min (dev->capture_handle, sw_params, period)) < 0) { + fprintf (stderr, "cannot set minimum available count (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params (dev->capture_handle, sw_params)) < 0) { + fprintf (stderr, "cannot set software parameters (%s)\n", + snd_strerror (err)); + assert(0); + } + + + if ((err = snd_pcm_open (&dev->playback_handle, dev->device_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { + fprintf (stderr, "cannot open audio device %s (%s)\n", + dev->device_name, + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { + fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_any (dev->playback_handle, hw_params)) < 0) { + fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_access (dev->playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { + fprintf (stderr, "cannot set access type (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_format (dev->playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { + fprintf (stderr, "cannot set sample format (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_rate_near (dev->playback_handle, hw_params, &rate, 0)) < 0) { + fprintf (stderr, "cannot set sample rate (%s)\n", + snd_strerror (err)); + assert(0); + } + /*fprintf (stderr, "rate = %d\n", rate);*/ + + if ((err = snd_pcm_hw_params_set_channels (dev->playback_handle, hw_params, channels)) < 0) { + fprintf (stderr, "cannot set channel count (%s)\n", + snd_strerror (err)); + assert(0); + } + + period_size = period; + dir = 0; + if ((err = snd_pcm_hw_params_set_period_size_near (dev->playback_handle, hw_params, &period_size, &dir)) < 0) { + fprintf (stderr, "cannot set period size (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_hw_params_set_periods (dev->playback_handle, hw_params, 2, 0)) < 0) { + fprintf (stderr, "cannot set number of periods (%s)\n", + snd_strerror (err)); + assert(0); + } + buffer_size = period_size * 2; + dir=0; + if ((err = snd_pcm_hw_params_set_buffer_size_near (dev->playback_handle, hw_params, &buffer_size)) < 0) { + fprintf (stderr, "cannot set buffer time (%s)\n", + snd_strerror (err)); + assert(0); + } + + + if ((err = snd_pcm_hw_params (dev->playback_handle, hw_params)) < 0) { + fprintf (stderr, "cannot set playback parameters (%s)\n", + snd_strerror (err)); + assert(0); + } + + /*snd_pcm_dump_setup(dev->playback_handle, jcd_out);*/ + snd_pcm_hw_params_free (hw_params); + + + if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) { + fprintf (stderr, "cannot allocate software parameters structure (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params_current (dev->playback_handle, sw_params)) < 0) { + fprintf (stderr, "cannot initialize software parameters structure (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params_set_avail_min (dev->playback_handle, sw_params, period)) < 0) { + fprintf (stderr, "cannot set minimum available count (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params_set_start_threshold (dev->playback_handle, sw_params, period)) < 0) { + fprintf (stderr, "cannot set start mode (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params (dev->playback_handle, sw_params)) < 0) { + fprintf (stderr, "cannot set software parameters (%s)\n", + snd_strerror (err)); + assert(0); + } + + + snd_pcm_link(dev->capture_handle, dev->playback_handle); + if ((err = snd_pcm_prepare (dev->capture_handle)) < 0) { + fprintf (stderr, "cannot prepare audio interface for use (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_prepare (dev->playback_handle)) < 0) { + fprintf (stderr, "cannot prepare audio interface for use (%s)\n", + snd_strerror (err)); + assert(0); + } + + dev->readN = snd_pcm_poll_descriptors_count(dev->capture_handle); + dev->writeN = snd_pcm_poll_descriptors_count(dev->playback_handle); + + dev->read_fd = malloc(dev->readN*sizeof(*dev->read_fd)); + /*printf ("descriptors: %d %d\n", dev->readN, dev->writeN);*/ + if (snd_pcm_poll_descriptors(dev->capture_handle, dev->read_fd, dev->readN) != dev->readN) + { + fprintf (stderr, "cannot obtain capture file descriptors (%s)\n", + snd_strerror (err)); + assert(0); + } + + dev->write_fd = malloc(dev->writeN*sizeof(*dev->read_fd)); + if (snd_pcm_poll_descriptors(dev->playback_handle, dev->write_fd, dev->writeN) != dev->writeN) + { + fprintf (stderr, "cannot obtain playback file descriptors (%s)\n", + snd_strerror (err)); + assert(0); + } + return dev; +} + +void alsa_device_close(AlsaDevice *dev) +{ + snd_pcm_close(dev->capture_handle); + snd_pcm_close(dev->playback_handle); + free(dev->device_name); + free(dev); +} + +int alsa_device_read(AlsaDevice *dev, short *pcm, int len) +{ + int err; + /*fprintf (stderr, "-");*/ + if ((err = snd_pcm_readi (dev->capture_handle, pcm, len)) != len) + { + if (err<0) + { + //fprintf(stderr, "error %d, EPIPE = %d\n", err, EPIPE); + if (err == -EPIPE) + { + fprintf (stderr, "An overrun has occured, reseting capture\n"); + } else + { + fprintf (stderr, "read from audio interface failed (%s)\n", + snd_strerror (err)); + } + if ((err = snd_pcm_prepare (dev->capture_handle)) < 0) + { + fprintf (stderr, "cannot prepare audio interface for use (%s)\n", + snd_strerror (err)); + } + if ((err = snd_pcm_start (dev->capture_handle)) < 0) + { + fprintf (stderr, "cannot prepare audio interface for use (%s)\n", + snd_strerror (err)); + } + /*alsa_device_read(dev,pcm,len);*/ + } else { + fprintf (stderr, "Couldn't read as many samples as I wanted (%d instead of %d)\n", err, len); + } + return 1; + } + return 0; +} + +int alsa_device_write(AlsaDevice *dev, const short *pcm, int len) +{ + int err; + /*fprintf (stderr, "+");*/ + if ((err = snd_pcm_writei (dev->playback_handle, pcm, len)) != len) + { + if (err<0) + { + if (err == -EPIPE) + { + fprintf (stderr, "An underrun has occured, reseting playback, len=%d\n", len); + } else + { + fprintf (stderr, "write to audio interface failed (%s)\n", + snd_strerror (err)); + } + if ((err = snd_pcm_prepare (dev->playback_handle)) < 0) + { + fprintf (stderr, "cannot prepare audio interface for use (%s)\n", + snd_strerror (err)); + } + } else { + fprintf (stderr, "Couldn't write as many samples as I wanted (%d instead of %d)\n", err, len); + } + /*alsa_device_write(dev,pcm,len);*/ + return 1; + } + return 0; +} + +int alsa_device_capture_ready(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds) +{ + unsigned short revents=0; + int err; + if ((err = snd_pcm_poll_descriptors_revents(dev->capture_handle, pfds, dev->readN, &revents)) < 0) + { + //cerr << "error in snd_pcm_poll_descriptors_revents for capture: " << snd_strerror (err) << endl; + //FIXME: This is a kludge + fprintf (stderr, "error in alsa_device_capture_ready: %s\n", snd_strerror (err)); + return pfds[0].revents & POLLIN; + } + //cerr << (revents & POLLERR) << endl; + return revents & POLLIN; +} + +int alsa_device_playback_ready(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds) +{ + unsigned short revents=0; + int err; + if ((err = snd_pcm_poll_descriptors_revents(dev->playback_handle, pfds+dev->readN, dev->writeN, &revents)) < 0) + { + //cerr << "error in snd_pcm_poll_descriptors_revents for playback: " << snd_strerror (err) << endl; + //FIXME: This is a kludge + fprintf (stderr, "error in alsa_device_playback_ready: %s\n", snd_strerror (err)); + return pfds[1].revents & POLLOUT; + } + //cerr << (revents & POLLERR) << endl; + return revents & POLLOUT; +} + +void alsa_device_start(AlsaDevice *dev) +{ + int i; + short pcm[dev->period*dev->channels]; + for (i=0;i<dev->period*dev->channels;i++) + pcm[i] = 0; + alsa_device_write(dev, pcm, dev->period); + alsa_device_write(dev, pcm, dev->period); + snd_pcm_start(dev->capture_handle); + snd_pcm_start(dev->playback_handle); +} + +int alsa_device_nfds(AlsaDevice *dev) +{ + return dev->writeN+dev->readN; +} + +void alsa_device_getfds(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds) +{ + int i; + assert (nfds >= dev->writeN+dev->readN); + for (i=0;i<dev->readN;i++) + pfds[i] = dev->read_fd[i]; + for (i=0;i<dev->writeN;i++) + pfds[i+dev->readN] = dev->write_fd[i]; +} diff --git a/speexclient/alsa_device.h b/speexclient/alsa_device.h new file mode 100644 index 0000000..a5b3787 --- /dev/null +++ b/speexclient/alsa_device.h @@ -0,0 +1,69 @@ +/* + Copyright (C) 2004-2006 Jean-Marc Valin + Copyright (C) 2006 Commonwealth Scientific and Industrial Research + Organisation (CSIRO) Australia + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 ALSA_DEVICE_H +#define ALSA_DEVICE_H + +#include <sys/poll.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct AlsaDevice_; + +typedef struct AlsaDevice_ AlsaDevice; + +AlsaDevice *alsa_device_open(char *device_name, unsigned int rate, int channels, int period); + +void alsa_device_close(AlsaDevice *dev); + +int alsa_device_read(AlsaDevice *dev, short *pcm, int len); + +int alsa_device_write(AlsaDevice *dev, const short *pcm, int len); + +int alsa_device_capture_ready(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds); + +int alsa_device_playback_ready(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds); + +void alsa_device_start(AlsaDevice *dev); + +int alsa_device_nfds(AlsaDevice *dev); + +void alsa_device_getfds(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/speexclient/compile.sh b/speexclient/compile.sh new file mode 100755 index 0000000..54e16fc --- /dev/null +++ b/speexclient/compile.sh @@ -0,0 +1,3 @@ +#!/bin/sh +echo gcc -Wall speexclient.c alsa_device.c -o speexclient -lspeex -lasound -lm +gcc -Wall speexclient.c alsa_device.c -o speexclient -lspeex -lasound -lm diff --git a/speexclient/speexclient.c b/speexclient/speexclient.c new file mode 100644 index 0000000..60d5764 --- /dev/null +++ b/speexclient/speexclient.c @@ -0,0 +1,249 @@ +/*************************************************************************** + Copyright (C) 2004-2006 by Jean-Marc Valin + Copyright (C) 2006 Commonwealth Scientific and Industrial Research + Organisation (CSIRO) Australia + + 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 the Xiph.org Foundation 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 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. + +****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <stdio.h> +#include <unistd.h> /* close() */ +#include <string.h> /* memset() */ + +#include "alsa_device.h" +#include <speex/speex.h> +#include <speex/speex_jitter.h> +#include <speex/speex_preprocess.h> +#include <speex/speex_echo.h> + +#include <sched.h> + +#define MAX_MSG 1500 + +#define SAMPLING_RATE 16000 +#define FRAME_SIZE 320 + +int main(int argc, char *argv[]) +{ + + int sd, rc, n; + int i; + struct sockaddr_in cliAddr, remoteAddr; + char msg[MAX_MSG]; + struct hostent *h; + int local_port, remote_port; + int nfds; + struct pollfd *pfds; + SpeexPreprocessState *preprocess; + AlsaDevice *audio_dev; + int tmp; + + if (argc != 5) + { + fprintf(stderr, "wrong options\n"); + exit(1); + } + + h = gethostbyname(argv[2]); + if(h==NULL) { + fprintf(stderr, "%s: unknown host '%s' \n", argv[0], argv[1]); + exit(1); + } + + local_port = atoi(argv[3]); + remote_port = atoi(argv[4]); + + printf("%s: sending data to '%s' (IP : %s) \n", argv[0], h->h_name, + inet_ntoa(*(struct in_addr *)h->h_addr_list[0])); + + { + remoteAddr.sin_family = h->h_addrtype; + memcpy((char *) &remoteAddr.sin_addr.s_addr, + h->h_addr_list[0], h->h_length); + remoteAddr.sin_port = htons(remote_port); + } + /* socket creation */ + sd=socket(AF_INET, SOCK_DGRAM, 0); + if(sd<0) { + printf("%s: cannot open socket \n",argv[0]); + exit(1); + } + + /* bind any port */ + cliAddr.sin_family = AF_INET; + cliAddr.sin_addr.s_addr = htonl(INADDR_ANY); + cliAddr.sin_port = htons(local_port); + + rc = bind(sd, (struct sockaddr *) &cliAddr, sizeof(cliAddr)); + if(rc<0) { + printf("%s: cannot bind port\n", argv[0]); + exit(1); + } + + /* Setup audio device */ + audio_dev = alsa_device_open(argv[1], SAMPLING_RATE, 1, FRAME_SIZE); + + /* Setup the encoder and decoder in wideband */ + void *enc_state, *dec_state; + enc_state = speex_encoder_init(&speex_wb_mode); + tmp = 8; + speex_encoder_ctl(enc_state, SPEEX_SET_QUALITY, &tmp); + tmp = 2; + speex_encoder_ctl(enc_state, SPEEX_SET_COMPLEXITY, &tmp); + dec_state = speex_decoder_init(&speex_wb_mode); + tmp = 1; + speex_decoder_ctl(dec_state, SPEEX_SET_ENH, &tmp); + SpeexBits enc_bits, dec_bits; + speex_bits_init(&enc_bits); + speex_bits_init(&dec_bits); + + + struct sched_param param; + /*param.sched_priority = 40; */ + param.sched_priority = sched_get_priority_min(SCHED_FIFO); + if (sched_setscheduler(0,SCHED_FIFO,¶m)) + perror("sched_setscheduler"); + + int send_timestamp = 0; + int recv_started=0; + + /* Setup all file descriptors for poll()ing */ + nfds = alsa_device_nfds(audio_dev); + pfds = malloc(sizeof(*pfds)*(nfds+1)); + alsa_device_getfds(audio_dev, pfds, nfds); + pfds[nfds].fd = sd; + pfds[nfds].events = POLLIN; + + /* Setup jitter buffer using decoder */ + SpeexJitter jitter; + speex_jitter_init(&jitter, dec_state, SAMPLING_RATE); + + /* Echo canceller with 200 ms tail length */ + SpeexEchoState *echo_state = speex_echo_state_init(FRAME_SIZE, 10*FRAME_SIZE); + tmp = SAMPLING_RATE; + speex_echo_ctl(echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &tmp); + + /* Setup preprocessor and associate with echo canceller for residual echo suppression */ + preprocess = speex_preprocess_state_init(FRAME_SIZE, SAMPLING_RATE); + speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_ECHO_STATE, echo_state); + + alsa_device_start(audio_dev); + + /* Infinite loop on capture, playback and receiving packets */ + while (1) + { + /* Wait for either 1) capture 2) playback 3) socket data */ + poll(pfds, nfds+1, -1); + /* Received packets */ + if (pfds[nfds].revents & POLLIN) + { + /*fprintf (stderr, "x");*/ + n = recv(sd, msg, MAX_MSG, 0); + int recv_timestamp = ((int*)msg)[1]; + int payload = ((int*)msg)[0]; + + if ((payload & 0x80000000) == 0) + { + /* Put content of the packet into the jitter buffer, except for the pseudo-header */ + speex_jitter_put(&jitter, msg+8, n-8, recv_timestamp); + recv_started = 1; + } + + } + /* Ready to play a frame (playback) */ + if (alsa_device_playback_ready(audio_dev, pfds, nfds)) + { + short pcm[FRAME_SIZE]; + if (recv_started) + { + /* Get audio from the jitter buffer */ + speex_jitter_get(&jitter, pcm, NULL); + } else { + for (i=0;i<FRAME_SIZE;i++) + pcm[i] = 0; + } + /* Playback the audio and reset the echo canceller if we got an underrun */ + if (alsa_device_write(audio_dev, pcm, FRAME_SIZE)) + speex_echo_state_reset(echo_state); + /* Put frame into playback buffer */ + speex_echo_playback(echo_state, pcm); + } + /* Audio available from the soundcard (capture) */ + if (alsa_device_capture_ready(audio_dev, pfds, nfds)) + { + short pcm[FRAME_SIZE], pcm2[FRAME_SIZE]; + char outpacket[MAX_MSG]; + /* Get audio from the soundcard */ + alsa_device_read(audio_dev, pcm, FRAME_SIZE); + + /* Perform echo cancellation */ + speex_echo_capture(echo_state, pcm, pcm2); + for (i=0;i<FRAME_SIZE;i++) + pcm[i] = pcm2[i]; + + speex_bits_reset(&enc_bits); + + /* Apply noise/echo suppression */ + speex_preprocess_run(preprocess, pcm); + + /* Encode */ + speex_encode_int(enc_state, pcm, &enc_bits); + int packetSize = speex_bits_write(&enc_bits, outpacket+8, MAX_MSG); + + /* Pseudo header: four null bytes and a 32-bit timestamp */ + ((int*)outpacket)[0] = htonl(0); + ((int*)outpacket)[1] = send_timestamp; + send_timestamp += FRAME_SIZE; + rc = sendto(sd, outpacket, packetSize+8, 0, + (struct sockaddr *) &remoteAddr, + sizeof(remoteAddr)); + + if(rc<0) { + printf("cannot send audio data\n"); + close(sd); + exit(1); + } + } + + + } + + + return 0; +} diff --git a/src/speexdec.c b/src/speexdec.c index 6b24730..94a63c1 100644 --- a/src/speexdec.c +++ b/src/speexdec.c @@ -299,7 +299,7 @@ void version_short() printf ("Copyright (C) 2002-2006 Jean-Marc Valin\n"); } -static void *process_header(ogg_packet *op, int enh_enabled, int *frame_size, int *granule_frame_size, int *rate, int *nframes, int forceMode, int *channels, SpeexStereoState *stereo, int *extra_headers, int quiet) +static void *process_header(ogg_packet *op, spx_int32_t enh_enabled, spx_int32_t *frame_size, int *granule_frame_size, spx_int32_t *rate, int *nframes, int forceMode, int *channels, SpeexStereoState *stereo, int *extra_headers, int quiet) { void *st; const SpeexMode *mode; @@ -459,10 +459,10 @@ int main(int argc, char **argv) SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT; int channels=-1; int rate=0; - int extra_headers; + int extra_headers=0; int wav_format=0; int lookahead; - int skeleton_serialno = -1; + int speex_serialno = -1; enh_enabled = 1; @@ -605,8 +605,8 @@ int main(int argc, char **argv) stream_init = 1; } if (ogg_page_serialno(&og) != os.serialno) { - /* so that both skeleton & speex pages are read. */ - os.serialno = ogg_page_serialno(&og); + /* so all streams are read. */ + ogg_stream_reset_serialno(&os, ogg_page_serialno(&og)); } /*Add page to the bitstream*/ ogg_stream_pagein(&os, &og); @@ -628,13 +628,13 @@ int main(int argc, char **argv) last_granule = page_granule; /*Extract all available packets*/ packet_no=0; - while (!eos && ogg_stream_packetout(&os, &op)==1) + while (!eos && ogg_stream_packetout(&os, &op) == 1) { - if (!memcmp(op.packet, "fishead", 7) || !memcmp(op.packet, "fisbone", 7)) { - /* skipping the skeleotn packets, also saving the skeleton stream serial number. */ - skeleton_serialno = os.serialno; - break; + if (!memcmp(op.packet, "Speex", 5)) { + speex_serialno = os.serialno; } + if (speex_serialno == -1 || os.serialno != speex_serialno) + break; /*If first packet, process as Speex header*/ if (packet_count==0) { @@ -660,7 +660,7 @@ int main(int argc, char **argv) lost=1; /*End of stream condition*/ - if (op.e_o_s && os.serialno != skeleton_serialno) /* don't set eos for skeleton e_o_s */ + if (op.e_o_s && os.serialno == speex_serialno) /* don't care for anything except speex eos */ eos=1; /*Copy Ogg packet to Speex bitstream*/ @@ -693,7 +693,7 @@ int main(int argc, char **argv) speex_decode_stereo_int(output, frame_size, &stereo); if (print_bitrate) { - int tmp; + spx_int32_t tmp; char ch=13; speex_decoder_ctl(st, SPEEX_GET_BITRATE, &tmp); fputc (ch, stderr); diff --git a/src/speexenc.c b/src/speexenc.c index 58154d0..e251b9b 100644 --- a/src/speexenc.c +++ b/src/speexenc.c @@ -80,7 +80,7 @@ int oe_write_page(ogg_page *page, FILE *fp) #define MAX_FRAME_BYTES 2000 /* Convert input audio bits, endians and channels */ -static int read_samples(FILE *fin,int frame_size, int bits, int channels, int lsb, short * input, char *buff, int *size) +static int read_samples(FILE *fin,int frame_size, int bits, int channels, int lsb, short * input, char *buff, spx_int32_t *size) { unsigned char in[MAX_FRAME_BYTES*2]; int i; @@ -253,13 +253,13 @@ int main(int argc, char **argv) char *inFile, *outFile; FILE *fin, *fout; short input[MAX_FRAME_SIZE]; - int frame_size; + spx_int32_t frame_size; int quiet=0; - int vbr_enabled=0; + spx_int32_t vbr_enabled=0; spx_int32_t vbr_max=0; int abr_enabled=0; - int vad_enabled=0; - int dtx_enabled=0; + spx_int32_t vad_enabled=0; + spx_int32_t dtx_enabled=0; int nbBytes; const SpeexMode *mode=NULL; int modeID = -1; @@ -300,10 +300,11 @@ int main(int argc, char **argv) {0, 0, 0, 0} }; int print_bitrate=0; - int rate=0, size; + spx_int32_t rate=0; + spx_int32_t size; int chan=1; int fmt=16; - int quality=-1; + spx_int32_t quality=-1; float vbr_quality=-1; int lsb=1; ogg_stream_state os; @@ -314,20 +315,20 @@ int main(int argc, char **argv) int id=-1; SpeexHeader header; int nframes=1; - int complexity=3; + spx_int32_t complexity=3; char *vendor_string = "Encoded with Speex " SPEEX_VERSION; char *comments; int comments_length; int close_in=0, close_out=0; int eos=0; - int bitrate=0; + spx_int32_t bitrate=0; double cumul_bits=0, enc_frames=0; char first_bytes[12]; int wave_input=0; - int tmp; + spx_int32_t tmp; SpeexPreprocessState *preprocess = NULL; int denoise_enabled=0, agc_enabled=0; - int lookahead = 0; + spx_int32_t lookahead = 0; comment_init(&comments, &comments_length, vendor_string); diff --git a/src/wav_io.c b/src/wav_io.c index 0491efe..02931b1 100644 --- a/src/wav_io.c +++ b/src/wav_io.c @@ -37,47 +37,16 @@ #include <stdio.h> #include <string.h> #include "speex/speex_types.h" - -static spx_uint32_t le_int(spx_uint32_t i) -{ - spx_uint32_t ret=i; -#ifdef WORDS_BIGENDIAN - ret = i>>24; - ret += (i>>8)&0x0000ff00; - ret += (i<<8)&0x00ff0000; - ret += (i<<24); -#endif - return ret; -} - -unsigned short be_short(unsigned short s) -{ - unsigned short ret=s; -#ifndef WORDS_BIGENDIAN - ret = s>>8; - ret += s<<8; -#endif - return ret; -} - -unsigned short le_short(unsigned short s) -{ - unsigned short ret=s; -#ifdef WORDS_BIGENDIAN - ret = s>>8; - ret += s<<8; -#endif - return ret; -} +#include "wav_io.h" -int read_wav_header(FILE *file, int *rate, int *channels, int *format, int *size) +int read_wav_header(FILE *file, int *rate, int *channels, int *format, spx_int32_t *size) { char ch[5]; - int itmp; - short stmp; - int bpersec; - short balign; + spx_int32_t itmp; + spx_int16_t stmp; + spx_int32_t bpersec; + spx_int16_t balign; int skip_bytes; int i; @@ -221,8 +190,8 @@ int read_wav_header(FILE *file, int *rate, int *channels, int *format, int *size void write_wav_header(FILE *file, int rate, int channels, int format, int size) { char ch[5]; - int itmp; - short stmp; + spx_int32_t itmp; + spx_int16_t stmp; ch[4]=0; diff --git a/src/wav_io.h b/src/wav_io.h index 398120a..ab04e1b 100644 --- a/src/wav_io.h +++ b/src/wav_io.h @@ -35,11 +35,31 @@ #include <stdio.h> #include "speex/speex_types.h" -unsigned short be_short(unsigned short s); -unsigned short le_short(unsigned short s); -spx_uint32_t le_int(spx_uint32_t i); +#ifdef WORDS_BIGENDIAN +#define le_short(s) ((short) ((unsigned short) (s) << 8) | ((unsigned short) (s) >> 8)) +#define be_short(s) ((short) (s)) +#else +#define le_short(s) ((short) (s)) +#define be_short(s) ((short) ((unsigned short) (s) << 8) | ((unsigned short) (s) >> 8)) +#endif -int read_wav_header(FILE *file, int *rate, int *channels, int *format, int *size); +/** Convert little endian */ +static inline spx_int32_t le_int(spx_int32_t i) +{ +#ifdef WORDS_BIGENDIAN + spx_uint32_t ui, ret; + ui = i; + ret = ui>>24; + ret |= (ui>>8)&0x0000ff00; + ret |= (ui<<8)&0x00ff0000; + ret |= (ui<<24); + return ret; +#else + return i; +#endif +} + +int read_wav_header(FILE *file, int *rate, int *channels, int *format, spx_int32_t *size); void write_wav_header(FILE *file, int rate, int channels, int format, int size); diff --git a/symbian/bld.inf b/symbian/bld.inf index 71fa4d9..f03a333 100644 --- a/symbian/bld.inf +++ b/symbian/bld.inf @@ -30,6 +30,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+PRJ_EXPORTS
+
+..\include\speex\speex_bits.h \epoc32\include\speex\speex_bits.h
+..\include\speex\speex_callbacks.h \epoc32\include\speex\speex_callbacks.h
+..\include\speex\speex_config_types.h \epoc32\include\speex\speex_config_types.h
+..\include\speex\speex_echo.h \epoc32\include\speex\speex_echo.h
+..\include\speex\speex.h \epoc32\include\speex\speex.h
+..\include\speex\speex_header.h \epoc32\include\speex\speex_header.h
+..\include\speex\speex_jitter.h \epoc32\include\speex\speex_jitter.h
+..\include\speex\speex_preprocess.h \epoc32\include\speex\speex_preprocess.h
+..\include\speex\speex_stereo.h \epoc32\include\speex\speex_stereo.h
+..\include\speex\speex_types.h \epoc32\include\speex\speex_types.h
+
+
PRJ_MMPFILES
speex.mmp
diff --git a/symbian/speex.mmp b/symbian/speex.mmp index 5d071ff..67b096e 100644 --- a/symbian/speex.mmp +++ b/symbian/speex.mmp @@ -36,10 +36,10 @@ UID 0 MACRO HAVE_CONFIG_H
SOURCEPATH ..\libspeex
SOURCE bits.c cb_search.c exc_5_64_table.c exc_5_256_table.c exc_8_128_table.c
-SOURCE exc_10_16_table.c exc_10_32_table.c exc_20_32_table.c filters.c gain_table.c
+SOURCE exc_10_16_table.c exc_10_32_table.c exc_20_32_table.c fftwrap.c kiss_fft.c kiss_fftr.c filterbank.c filters.c gain_table.c
SOURCE gain_table_lbr.c hexc_10_32_table.c hexc_table.c high_lsp_tables.c jitter.c
SOURCE lbr_48k_tables.c lpc.c lsp.c lsp_tables_nb.c ltp.c math_approx.c mdf.c misc.c
SOURCE modes.c nb_celp.c preprocess.c quant_lsp.c sb_celp.c smallft.c
-SOURCE speex.c speex_callbacks.c speex_header.c stereo.c vbr.c vq.c
+SOURCE speex.c speex_callbacks.c speex_header.c stereo.c vbr.c vq.c window.c
USERINCLUDE . ..\include\speex
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\include
diff --git a/ti/testenc-TI-C5x.c b/ti/testenc-TI-C5x.c index b526fac..33100e8 100644 --- a/ti/testenc-TI-C5x.c +++ b/ti/testenc-TI-C5x.c @@ -135,9 +135,9 @@ void main() void *st;
void *dec;
SpeexBits bits;
- int tmp;
+ spx_int32_t tmp;
unsigned long bitCount=0;
- int skip_group_delay;
+ spx_int32_t skip_group_delay;
SpeexCallback callback;
/* C54xx defaults to max wait states, even for parts like C5416 with
diff --git a/ti/testenc-TI-C64x.c b/ti/testenc-TI-C64x.c index 565ba58..3bb17de 100644 --- a/ti/testenc-TI-C64x.c +++ b/ti/testenc-TI-C64x.c @@ -104,9 +104,9 @@ void main() void *st;
void *dec;
SpeexBits bits;
- int tmp;
+ spx_int32_t tmp;
unsigned long bitCount=0;
- int skip_group_delay;
+ spx_int32_t skip_group_delay;
SpeexCallback callback;
#ifdef CHECK_RESULT
diff --git a/tmv/_kiss_fft_guts_tm.h b/tmv/_kiss_fft_guts_tm.h new file mode 100644 index 0000000..9cf2864 --- /dev/null +++ b/tmv/_kiss_fft_guts_tm.h @@ -0,0 +1,188 @@ +/* Copyright (C) 2007 Hong Zhiqian */ +/** + @file _kiss_fft_guts_tm.h + @author Hong Zhiqian + @brief Various compatibility routines for Speex (TriMedia version) +*/ +/* + 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 the Xiph.org Foundation 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 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 _KISS_FFT_GUTS_TM_ +#define _KISS_FFT_GUTS_TM_ + +#ifdef TM_ASM + +#include <ops/custom_defs.h> + +#ifdef FIXED_POINT + +#undef sround +#define sround(x) sex16(((x) + (1<<(FRACBITS-1)) ) >> FRACBITS) + +#undef MIN +#undef MAX +#define MIN(a,b) imin(a,b) +#define MAX(a,b) imax(a,b) + +#define TM_MUL(res,a,b) \ + { register int a0, a1, b0, b1; \ + \ + a0 = sex16((a)); \ + a1 = asri(16,(a)); \ + b0 = sex16((b)); \ + b1 = asri(16,(b)); \ + (res)= pack16lsb( \ + sround(ifir16((a),funshift2((b),(b)))), \ + sround(a0*b0-a1*b1)); \ + } \ + +#define TM_ADD(res,a,b) \ + { (res)=dspidualadd((a),(b)); \ + } \ + +#define TM_SUB(res,a,b) \ + { (res)=dspidualsub((a),(b)); \ + } \ + +#define TM_SHR(res,a,shift) \ + { (res)=dualasr((a),(shift)); \ + } \ + +#define TM_DIV(res,c,frac) \ + { register int c1, c0; \ + \ + c1 = asri(16,(c)); \ + c0 = sex16((c)); \ + (res) = pack16lsb(sround(c1 * (32767/(frac))), sround(c0 * (32767/(frac))));\ + } \ + +#define TM_NEGMSB(res, a) \ + { (res) = pack16lsb((ineg(asri(16,(a)))), (a)); \ + } \ + +#else + +#undef MIN +#undef MAX +#define MIN(a,b) fmin(a,b) +#define MAX(a,b) fmax(a,b) + +#endif +#endif + +#undef CHECKBUF +#define CHECKBUF(buf,nbuf,n) \ + { \ + if ( nbuf < (size_t)(n) ) { \ + speex_free(buf); \ + buf = (kiss_fft_cpx*)KISS_FFT_MALLOC(sizeof(kiss_fft_cpx)*(n)); \ + nbuf = (size_t)(n); \ + } \ + } \ + +#undef C_ADD +#define C_ADD( res, a,b) \ + { \ + CHECK_OVERFLOW_OP((a).r,+,(b).r) \ + CHECK_OVERFLOW_OP((a).i,+,(b).i) \ + (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \ + } \ + + +#undef C_SUB +#define C_SUB( res, a,b) \ + { \ + CHECK_OVERFLOW_OP((a).r,-,(b).r) \ + CHECK_OVERFLOW_OP((a).i,-,(b).i) \ + (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \ + } \ + +#undef C_ADDTO +#define C_ADDTO( res , a) \ + { \ + CHECK_OVERFLOW_OP((res).r,+,(a).r) \ + CHECK_OVERFLOW_OP((res).i,+,(a).i) \ + (res).r += (a).r; (res).i += (a).i; \ + } \ + +#undef C_SUBFROM +#define C_SUBFROM( res, a) \ + { \ + CHECK_OVERFLOW_OP((res).r,-,(a).r) \ + CHECK_OVERFLOW_OP((res).i,-,(a).i) \ + (res).r -= (a).r; (res).i -= (a).i; \ + } \ + +#undef kf_cexp +#define kf_cexp(x,phase) \ + { (x)->r = KISS_FFT_COS(phase); \ + (x)->i = KISS_FFT_SIN(phase); } \ + +#undef kf_cexp2 +#define kf_cexp2(x,phase) \ + { (x)->r = spx_cos_norm((phase)); \ + (x)->i = spx_cos_norm((phase)-32768); } \ + + +#ifdef FIXED_POINT + +#undef C_MUL +#define C_MUL(m,a,b) \ + { (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \ + (m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); } \ + +#undef C_FIXDIV +#define C_FIXDIV(c,div) \ + { DIVSCALAR( (c).r , div); \ + DIVSCALAR( (c).i , div); } \ + +#undef C_MULBYSCALAR +#define C_MULBYSCALAR( c, s ) \ + { (c).r = sround( smul( (c).r , s ) ) ; \ + (c).i = sround( smul( (c).i , s ) ) ; } \ + +#else + +#undef C_MUL +#define C_MUL(m,a,b) \ + { (m).r = (a).r*(b).r - (a).i*(b).i; \ + (m).i = (a).r*(b).i + (a).i*(b).r; } \ + + +#undef C_MULBYSCALAR +#define C_MULBYSCALAR( c, s ) \ + { (c).r *= (s); \ + (c).i *= (s); } \ + + + +#endif + +#endif + diff --git a/tmv/cb_search_tm.h b/tmv/cb_search_tm.h new file mode 100644 index 0000000..15ca1d5 --- /dev/null +++ b/tmv/cb_search_tm.h @@ -0,0 +1,149 @@ +/* Copyright (C) 2007 Hong Zhiqian */
+/**
+ @file cb_search_tm.h
+ @author Hong Zhiqian
+ @brief Various compatibility routines for Speex (TriMedia version)
+*/
+/*
+ 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 the Xiph.org Foundation 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 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.
+*/
+
+#include <ops/custom_defs.h>
+#include "profile_tm.h"
+
+#ifdef FIXED_POINT
+
+#define OVERRIDE_COMPUTE_WEIGHTED_CODEBOOK
+static void compute_weighted_codebook(
+ const signed char * restrict shape_cb,
+ const Int16 * restrict r,
+ Int16 * restrict resp,
+ Int16 * restrict resp2,
+ Int32 * restrict E,
+ int shape_cb_size, int subvect_size, char *stack)
+{
+ register int i, j;
+ register int quadsize;
+
+ TMDEBUG_ALIGNMEM(r);
+ TMDEBUG_ALIGNMEM(resp);
+ TMDEBUG_ALIGNMEM(resp2);
+
+ COMPUTEWEIGHTEDCODEBOOK_START();
+
+ quadsize = subvect_size << 2;
+
+ for ( i=0 ; i<shape_cb_size ; i+=4 )
+ { register int e0, e1, e2, e3;
+
+ e0 = e1 = e2 = e3 = 0;
+ for( j=0 ; j<subvect_size ; ++j )
+ {
+ register int k, rr;
+ register int resj0, resj1, resj2, resj3;
+
+ resj0 = resj1 = resj2 = resj3 = 0;
+
+ for ( k=0 ; k<=j ; ++k )
+ { rr = r[j-k];
+
+ resj0 += shape_cb[k] * rr;
+ resj1 += shape_cb[k+subvect_size] * rr;
+ resj2 += shape_cb[k+2*subvect_size] * rr;
+ resj3 += shape_cb[k+3*subvect_size] * rr;
+ }
+
+ resj0 >>= 13;
+ resj1 >>= 13;
+ resj2 >>= 13;
+ resj3 >>= 13;
+
+ e0 += resj0 * resj0;
+ e1 += resj1 * resj1;
+ e2 += resj2 * resj2;
+ e3 += resj3 * resj3;
+
+ resp[j] = resj0;
+ resp[j+subvect_size] = resj1;
+ resp[j+2*subvect_size] = resj2;
+ resp[j+3*subvect_size] = resj3;
+ }
+
+ E[i] = e0;
+ E[i+1] = e1;
+ E[i+2] = e2;
+ E[i+3] = e3;
+
+ resp += quadsize;
+ shape_cb += quadsize;
+ }
+
+#ifndef REMARK_ON
+ (void)resp2;
+ (void)stack;
+#endif
+
+ COMPUTEWEIGHTEDCODEBOOK_STOP();
+}
+
+#define OVERRIDE_TARGET_UPDATE
+static inline void target_update(Int16 * restrict t, Int16 g, Int16 * restrict r, int len)
+{
+ register int n;
+ register int gr1, gr2, t1, t2, r1, r2;
+ register int quadsize;
+
+ TARGETUPDATE_START();
+
+ quadsize = len & 0xFFFFFFFC;
+
+ for ( n=0; n<quadsize ; n+=4 )
+ { gr1 = pack16lsb(PSHR32((g * r[n]),13) , PSHR32((g * r[n+1]),13));
+ gr2 = pack16lsb(PSHR32((g * r[n+2]),13), PSHR32((g * r[n+3]),13));
+
+ t1 = pack16lsb(t[n], t[n+1]);
+ t2 = pack16lsb(t[n+2],t[n+3]);
+
+ r1 = dspidualsub(t1, gr1);
+ r2 = dspidualsub(t2, gr2);
+
+ t[n] = asri(16,r1);
+ t[n+1] = sex16(r1);
+ t[n+2] = asri(16,r2);
+ t[n+3] = sex16(r2);
+ }
+
+ for ( n=quadsize ; n<len ; ++n )
+ { t[n] = SUB16(t[n],PSHR32(MULT16_16(g,r[n]),13));
+ }
+
+ TARGETUPDATE_STOP();
+}
+
+#endif
+
diff --git a/tmv/config.h b/tmv/config.h new file mode 100644 index 0000000..0b68fb8 --- /dev/null +++ b/tmv/config.h @@ -0,0 +1,98 @@ +#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+#define USE_COMPACT_KISS_FFT
+//#define USE_KISS_FFT
+
+#ifdef WIN32
+
+//#define FIXED_POINT
+
+#define inline __inline
+#define restrict
+
+#elif defined (__TCS__)
+
+#define FIXED_POINT
+#define PREPROCESS_MDF_FLOAT
+#define TM_ASM
+
+#define TM_DEBUGMEM_ALIGNNMENT 1
+
+#define TM_PROFILE 1
+#define TM_PROFILE_FIRMEM16 0
+#define TM_PROFILE_IIRMEM16 0
+#define TM_PROFILE_FILTERMEM16 0
+#define TM_PROFILE_VQNBEST 0
+#define TM_PROFILE_VQNBESTSIGN 0
+#define TM_PROFILE_COMPUTEQUANTWEIGHTS 0
+#define TM_PROFILE_LSPQUANT 0
+#define TM_PROFILE_LSPWEIGHTQUANT 0
+#define TM_PROFILE_LSPENFORCEMARGIN 0
+#define TM_PROFILE_LSPTOLPC 0
+#define TM_PROFILE_INNERPROD 0
+#define TM_PROFILE_PITCHXCORR 0
+#define TM_PROFILE_LSP_INTERPOLATE 0
+#define TM_PROFILE_CHEBPOLYEVA 0
+#define TM_PROFILE_COMPUTEWEIGHTEDCODEBOOK 0
+#define TM_PROFILE_TARGETUPDATE 0
+#define TM_PROFILE_SPXAUTOCORR 0
+#define TM_PROFILE_COMPUTEPITCHERROR 0
+#define TM_PROFILE_COMPUTERMS16 0
+#define TM_PROFILE_NORMALIZE16 0
+#define TM_PROFILE_BWLPC 0
+#define TM_PROFILE_HIGHPASS 0
+#define TM_PROFILE_SIGNALMUL 0
+#define TM_PROFILE_SIGNALDIV 0
+#define TM_PROFILE_COMPUTEIMPULSERESPONSE 0
+#define TM_PROFILE_PITCHGAINSEARCH3TAPVQ 0
+#define TM_PROFILE_OPENLOOPNBESTPITCH 0
+#define TM_PROFILE_PREPROCESSANALYSIS 0
+#define TM_PROFILE_UPDATENOISEPROB 0
+#define TM_PROFILE_COMPUTEGAINFLOOR 0
+#define TM_PROFILE_FILTERDCNOTCH16 0
+#define TM_PROFILE_MDFINNERPROD 0
+#define TM_PROFILE_SPECTRALMULACCUM 0
+#define TM_PROFILE_WEIGHTEDSPECTRALMULCONJ 0
+#define TM_PROFILE_MDFADJUSTPROP 0
+#define TM_PROFILE_SPEEXECHOGETRESIDUAL 0
+#define TM_PROFILE_MAXIMIZERANGE 0
+#define TM_PROFILE_RENORMRANGE 0
+#define TM_PROFILE_POWERSPECTRUM 0
+#define TM_PROFILE_QMFSYNTH 0
+#define TM_PROFILE_QMFDECOMP 0
+#define TM_PROFILE_FILTERBANKCOMPUTEBANK32 0
+#define TM_PROFILE_FILTERBANKCOMPUTEPSD16 0
+
+#define TM_UNROLL 1
+#define TM_UNROLL_FILTER 1
+#define TM_UNROLL_IIR 1
+#define TM_UNROLL_FIR 1
+#define TM_UNROLL_HIGHPASS 1
+#define TM_UNROLL_SIGNALMUL 1
+#define TM_UNROLL_SIGNALDIV 1
+#define TM_UNROLL_VQNBEST 1
+#define TM_UNROLL_VQSIGNNBEST 1
+#define TM_UNROLL__SPXAUTOCORR 1
+#define TM_UNROLL_COMPUTERMS16 1
+#define TM_UNROLL_COMPUTEIMPULSERESPONSE 1
+#define TM_UNROLL_QMFSYNTH 1
+#define TM_UNROLL_PITCHGAINSEARCH3TAPVQ 1
+#define TM_UNROLL_OPENLOOPNBESTPITCH 1
+#define TM_UNROLL_FILTERBANKCOMPUTEBANK32 1
+#define TM_UNROLL_FILTERBANKCOMPUTEPSD16 1
+#define TM_UNROLL_SPEEXPREPROCESSRUN 1
+#define TM_UNROLL_PREPROCESSANALYSIS 1
+#define TM_UNROLL_UPDATENOISEPROB 1
+#define TM_UNROLL_COMPUTEGAINFLOOR 1
+#define TM_UNROLL_SPEEXECHOGETRESIDUAL 1
+#define TM_UNROLL_SPEEXECHOCANCELLATION 1
+#define TM_UNROLL_FILTERDCNOTCH16 1
+#define TM_UNROLL_MDFINNERPRODUCT 1
+#define TM_UNROLL_SPECTRALMULACCUM 1
+#define TM_UNROLL_MDFADJUSTPROP 1
+
+#endif
+
+#endif
+
diff --git a/tmv/fftwrap_tm.h b/tmv/fftwrap_tm.h new file mode 100644 index 0000000..39d924e --- /dev/null +++ b/tmv/fftwrap_tm.h @@ -0,0 +1,233 @@ +/* Copyright (C) 2007 Hong Zhiqian */
+/**
+ @file fftwrap_tm.h
+ @author Hong Zhiqian
+ @brief Various compatibility routines for Speex (TriMedia version)
+*/
+/*
+ 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 the Xiph.org Foundation 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 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.
+*/
+#include <ops/custom_defs.h>
+#include "profile_tm.h"
+
+#ifdef FIXED_POINT
+
+#define OVERRIDE_MAXIMIZE_RANGE
+static int maximize_range(Int16 *in, Int16 *out, int bound, int len)
+{
+ register int max_val=0;
+ register int shift=0;
+ register int i, j;
+
+ TMDEBUG_ALIGNMEM(in);
+ TMDEBUG_ALIGNMEM(out);
+
+ MAXIMIZERANGE_START();
+
+ len >>= 1;
+
+ for ( i=0 ; i<len ; i+=4 )
+ {
+ register int x10, x32, x54, x76;
+
+ x10 = ld32x(in,i);
+ x32 = ld32x(in,i+1);
+ x54 = ld32x(in,i+2);
+ x76 = ld32x(in,i+3);
+
+ x10 = dspidualabs(x10);
+ x32 = dspidualabs(x32);
+ x54 = dspidualabs(x54);
+ x76 = dspidualabs(x76);
+
+ x10 = imax(sex16(x10), asri(16,x10));
+ x32 = imax(sex16(x32), asri(16,x32));
+ x54 = imax(sex16(x54), asri(16,x54));
+ x76 = imax(sex16(x76), asri(16,x76));
+
+ max_val = imax(max_val,x10);
+ max_val = imax(max_val,x32);
+ max_val = imax(max_val,x54);
+ max_val = imax(max_val,x76);
+ }
+
+ while ( max_val <= (bound>>1) && max_val != 0 )
+ { max_val <<= 1;
+ shift++;
+ }
+
+ if ( shift != 0 )
+ {
+ for ( i=0,j=0 ; i<len ; i+=4,j+=16 )
+ {
+ register int x10, x32, x54, x76;
+
+ x10 = ld32x(in,i);
+ x32 = ld32x(in,i+1);
+ x54 = ld32x(in,i+2);
+ x76 = ld32x(in,i+3);
+
+ x10 = dualasl(x10, shift);
+ x32 = dualasl(x32, shift);
+ x54 = dualasl(x54, shift);
+ x76 = dualasl(x76, shift);
+
+ st32d(j,out,x10);
+ st32d(j+4,out,x32);
+ st32d(j+8,out,x54);
+ st32d(j+12,out,x76);
+ }
+ }
+
+ MAXIMIZERANGE_STOP();
+
+ return shift;
+}
+
+#define OVERRIDE_RENORM_RANGE
+static void renorm_range(Int16 *in, Int16 *out, int shift, int len)
+{
+ register int i, j, s, l;
+
+ TMDEBUG_ALIGNMEM(in);
+ TMDEBUG_ALIGNMEM(out);
+
+ RENORMRANGE_START();
+
+ s = (1<<((shift))>>1);
+ s = pack16lsb(s,s);
+
+ len >>= 1;
+ l = len & (int)0xFFFFFFFE;
+
+ for ( i=0,j=0 ; i<l; i+=2,j+=8 )
+ {
+ register int x10, x32;
+
+ x10 = ld32x(in,i);
+ x32 = ld32x(in,i+1);
+
+ x10 = dspidualadd(x10, s);
+ x32 = dspidualadd(x32, s);
+
+ x10 = dualasr(x10, shift);
+ x32 = dualasr(x32, shift);
+
+ st32d(j,out,x10);
+ st32d(j+4,out,x32);
+ }
+
+ if ( len & (int)0x01 )
+ {
+ register int x10;
+
+ x10 = ld32x(in,i);
+ x10 = dspidualadd(x10, s);
+ x10 = dualasr(x10, shift);
+ st32d(j,out,x10);
+ }
+
+ RENORMRANGE_STOP();
+}
+
+#endif
+
+#ifdef USE_COMPACT_KISS_FFT
+#ifdef FIXED_POINT
+
+#define OVERRIDE_POWER_SPECTRUM
+void power_spectrum(const spx_word16_t *X, spx_word32_t *ps, int N)
+{
+ register int x10, x32, x54, x76, *x;
+ register int i;
+
+ x = (int*)(X-1);
+
+ TMDEBUG_ALIGNMEM(x);
+
+ POWERSPECTRUM_START();
+
+ x76 = 0;
+ ps[0] = MULT16_16(X[0],X[0]);
+ N >>= 1;
+
+ for( i=1 ; i<N ; i+=4 )
+ {
+ x10 = ld32x(x, i);
+ x32 = ld32x(x, i+1);
+ x54 = ld32x(x, i+2);
+ x76 = ld32x(x, i+3);
+
+ ps[i] = ifir16(x10,x10);
+ ps[i+1] = ifir16(x32,x32);
+ ps[i+2] = ifir16(x54,x54);
+ ps[i+3] = ifir16(x76,x76);
+ }
+
+ x76 = sex16(x76);
+ ps[N] = x76 * x76;
+
+ POWERSPECTRUM_STOP();
+}
+
+#else
+
+#define OVERRIDE_POWER_SPECTRUM
+void power_spectrum(const float * restrict X, float * restrict ps, int N)
+{
+ register int i, j;
+ register float xx;
+
+ POWERSPECTRUM_START();
+
+ xx = X[0];
+
+ ps[0]=MULT16_16(xx,xx);
+
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+ for (i=1,j=1;i<N-1;i+=2,j++)
+ { register float xi, xii;
+
+ xi = X[i];
+ xii = X[i+1];
+
+ ps[j] = MULT16_16(xi,xi) + MULT16_16(xii,xii);
+ }
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+
+ xx = X[i];
+ ps[j]=MULT16_16(xx,xx);
+
+ POWERSPECTRUM_STOP();
+}
+
+#endif
+#endif
+
diff --git a/tmv/filterbank_tm.h b/tmv/filterbank_tm.h new file mode 100644 index 0000000..39d2332 --- /dev/null +++ b/tmv/filterbank_tm.h @@ -0,0 +1,289 @@ +/* Copyright (C) 2007 Hong Zhiqian */
+/**
+ @file filterbank_tm.h
+ @author Hong Zhiqian
+ @brief Various compatibility routines for Speex (TriMedia version)
+*/
+/*
+ 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 the Xiph.org Foundation 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 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.
+*/
+#include <ops/custom_defs.h>
+#include "profile_tm.h"
+
+#ifdef FIXED_POINT
+
+#define OVERRIDE_FILTERBANK_COMPUTE_BANK32
+void filterbank_compute_bank32(FilterBank * restrict bank, spx_word32_t * restrict ps, spx_word32_t * restrict mel)
+{
+ register int i, j, k, banks, len, zero, s;
+ register int * restrict left;
+ register int * restrict right;
+ register int * restrict bleft;
+ register int * restrict bright;
+
+ left = (int*)bank->filter_left;
+ right = (int*)bank->filter_right;
+ bleft = (int*)bank->bank_left;
+ bright = (int*)bank->bank_right;
+
+ TMDEBUG_ALIGNMEM(ps);
+ TMDEBUG_ALIGNMEM(mel);
+ TMDEBUG_ALIGNMEM(left);
+ TMDEBUG_ALIGNMEM(right);
+ TMDEBUG_ALIGNMEM(bleft);
+ TMDEBUG_ALIGNMEM(bright);
+
+ FILTERBANKCOMPUTEBANK32_START();
+
+ banks = bank->nb_banks << 2;
+ zero = 0;
+ len = bank->len;
+ s = (1<<((15))>>1);
+
+#if (TM_UNROLL && TM_UNROLL_FILTERBANKCOMPUTEBANK32)
+#pragma TCS_unroll=2
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<banks ; i+=4 )
+ { st32d(i, mel, zero);
+ }
+#if (TM_UNROLL && TM_UNROLL_FILTERBANKCOMPUTEBANK32)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+#if (TM_UNROLL && TM_UNROLL_FILTERBANKCOMPUTEBANK32)
+#pragma TCS_unroll=2
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0,j=1,k=0 ; i<len ; i+=2,j+=2,++k )
+ { register int ps1, ps0, _mel, ps0_msb, ps0_lsb, ps1_msb, ps1_lsb;
+ register int left10, right10, left1, left0, right1, right0;
+ register int il1, ir1, il0, ir0;
+
+ ps0 = ld32x(ps,i);
+ il0 = ld32x(bleft,i);
+ _mel = ld32x(mel,il0);
+ left10 = ld32x(left,k);
+ ir0 = ld32x(bright,i);
+ right10 = ld32x(right,k);
+
+ ps0_msb = ps0 >> 15;
+ ps0_lsb = ps0 & 0x00007fff;
+ left0 = sex16(left10);
+ right0 = sex16(right10);
+
+ _mel += left0 * ps0_msb + ((left0 * ps0_lsb + s ) >> 15);
+ mel[il0]= _mel;
+ _mel = ld32x(mel,ir0);
+ _mel += right0 * ps0_msb + ((right0 * ps0_lsb + s ) >> 15);
+ mel[ir0]= _mel;
+
+ ps1 = ld32x(ps,j);
+ il1 = ld32x(bleft,j);
+ _mel = ld32x(mel,il1);
+ ir1 = ld32x(bright,j);
+
+ left1 = asri(16,left10);
+ right1 = asri(16,right10);
+ ps1_msb = ps1 >> 15;
+ ps1_lsb = ps1 & 0x00007fff;
+
+ _mel += left1 * ps1_msb + ((left1 * ps1_lsb + s ) >> 15);
+ mel[il1]= _mel;
+ _mel = ld32x(mel,ir1);
+ _mel += right1 * ps1_msb + ((right1 * ps1_lsb + s ) >> 15);
+ mel[ir1]= _mel;
+ }
+#if (TM_UNROLL && TM_UNROLL_FILTERBANKCOMPUTEBANK32)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ FILTERBANKCOMPUTEBANK32_STOP();
+}
+
+#define OVERRIDE_FILTERBANK_COMPUTE_PSD16
+void filterbank_compute_psd16(FilterBank * restrict bank, spx_word16_t * restrict mel, spx_word16_t * restrict ps)
+{
+ register int i, j, k, len, s;
+ register int * restrict left;
+ register int * restrict right;
+ register int * restrict bleft;
+ register int * restrict bright;
+
+ left = (int*)bank->filter_left;
+ right = (int*)bank->filter_right;
+ bleft = (int*)bank->bank_left;
+ bright = (int*)bank->bank_right;
+
+ TMDEBUG_ALIGNMEM(ps);
+ TMDEBUG_ALIGNMEM(mel);
+ TMDEBUG_ALIGNMEM(left);
+ TMDEBUG_ALIGNMEM(right);
+ TMDEBUG_ALIGNMEM(bleft);
+ TMDEBUG_ALIGNMEM(bright);
+
+ FILTERBANKCOMPUTEPSD16_START();
+
+ len = bank->len;
+ s = (1<<((15))>>1);
+
+#if (TM_UNROLL && TM_UNROLL_FILTERBANKCOMPUTEPSD16)
+#pragma TCS_unroll=2
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0,j=0,k=0 ; i<len ; i+=2,j+=4,++k )
+ {
+ register int mell0, melr0, mel1, mel0, mell1, melr1;
+ register int il1, ir1, il0, ir0;
+ register int left10, right10, lr1, lr0;
+ register int acc0, acc1, ps10;
+
+ acc0 = acc1 = s;
+
+ il0 = ld32x(bleft, i);
+ ir0 = ld32x(bright,i);
+ mell0 = mel[il0];
+ melr0 = mel[ir0];
+ left10 = ld32x(left, k);
+ right10 = ld32x(right, k);
+ mel0 = pack16lsb(mell0, melr0);
+ lr0 = pack16lsb(left10, right10);
+
+ acc0 += ifir16(mel0, lr0);
+ acc0 >>= 15;
+
+ il1 = ld32x(bleft, i+1);
+ ir1 = ld32x(bright,i+1);
+ mell1 = mel[il1];
+ melr1 = mel[ir1];
+ mel1 = pack16lsb(mell1, melr1);
+ lr1 = pack16msb(left10, right10);
+
+ acc1 += ifir16(mel1, lr1);
+ acc1 >>= 15;
+
+ ps10 = pack16lsb(acc1, acc0);
+
+ st32d(j, ps, ps10);
+ }
+#if (TM_UNROLL && TM_UNROLL_FILTERBANKCOMPUTEPSD16)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ FILTERBANKCOMPUTEPSD16_STOP();
+}
+
+#else
+
+#define OVERRIDE_FILTERBANK_COMPUTE_BANK32
+void filterbank_compute_bank32(FilterBank * restrict bank, float * restrict ps, float * restrict mel)
+{
+ register int i, banks, len;
+ register int * restrict bleft, * restrict bright;
+ register float * restrict left, * restrict right;
+
+ banks = bank->nb_banks;
+ len = bank->len;
+ bleft = bank->bank_left;
+ bright= bank->bank_right;
+ left = bank->filter_left;
+ right = bank->filter_right;
+
+ FILTERBANKCOMPUTEBANK32_START();
+
+ memset(mel, 0, banks * sizeof(float));
+
+#if (TM_UNROLL && TM_UNROLL_FILTERBANKCOMPUTEBANK32)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<len ; ++i)
+ {
+ register int id1, id2;
+ register float psi;
+
+ id1 = bleft[i];
+ id2 = bright[i];
+ psi = ps[i];
+
+ mel[id1] += left[i] * psi;
+ mel[id2] += right[i] * psi;
+ }
+#if (TM_UNROLL && TM_UNROLL_FILTERBANKCOMPUTEBANK32)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ FILTERBANKCOMPUTEBANK32_STOP();
+}
+
+#define OVERRIDE_FILTERBANK_COMPUTE_PSD16
+void filterbank_compute_psd16(FilterBank * restrict bank, float * restrict mel, float * restrict ps)
+{
+ register int i, len;
+ register int * restrict bleft, * restrict bright;
+ register float * restrict left, * restrict right;
+
+ len = bank->len;
+ bleft = bank->bank_left;
+ bright= bank->bank_right;
+ left = bank->filter_left;
+ right = bank->filter_right;
+
+ FILTERBANKCOMPUTEPSD16_START();
+
+#if (TM_UNROLL && TM_UNROLL_FILTERBANKCOMPUTEPSD16)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<len ; ++i )
+ {
+ register float acc;
+ register int id1, id2;
+
+ id1 = bleft[i];
+ id2 = bright[i];
+
+ acc = mel[id1] * left[i];
+ acc += mel[id2] * right[i];
+
+ ps[i] = acc;
+ }
+#if (TM_UNROLL && TM_UNROLL_FILTERBANKCOMPUTEPSD16)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ FILTERBANKCOMPUTEPSD16_STOP();
+}
+
+
+#endif
diff --git a/tmv/filters_tm.h b/tmv/filters_tm.h new file mode 100644 index 0000000..8f28102 --- /dev/null +++ b/tmv/filters_tm.h @@ -0,0 +1,1521 @@ +#include <ops/custom_defs.h>
+#include "profile_tm.h"
+
+#ifdef FIXED_POINT
+
+#define iadd(a,b) ((a) + (b))
+
+#define OVERRIDE_BW_LPC
+void bw_lpc(Int16 gamma, const Int16 *lpc_in, Int16 *lpc_out, int order)
+{
+ register int tmp, g, i;
+
+ TMDEBUG_ALIGNMEM(lpc_in);
+ TMDEBUG_ALIGNMEM(lpc_out);
+
+ BWLPC_START();
+
+ tmp = g = gamma;
+ for ( i=0 ; i<4 ; i+=2,lpc_out+=4 )
+ { register int in10, y1, y0, y10;
+ register int in32, y3, y2, y32;
+
+ in10 = ld32x(lpc_in,i);
+ y0 = ((tmp * sex16(in10)) + 16384) >> 15;
+ tmp = ((tmp * g) + 16384) >> 15;
+ y1 = ((tmp * asri(16,in10)) + 16384) >> 15;
+ tmp = ((tmp * g) + 16384) >> 15;
+ y10 = pack16lsb(y1,y0);
+ st32(lpc_out,y10);
+
+ in32 = ld32x(lpc_in,i+1);
+ y2 = ((tmp * sex16(in32)) + 16384) >> 15;
+ tmp = ((tmp * g) + 16384) >> 15;
+ y3 = ((tmp * asri(16,in32)) + 16384) >> 15;
+ tmp = ((tmp * g) + 16384) >> 15;
+ y32 = pack16lsb(y3,y2);
+ st32d(4,lpc_out,y32);
+ }
+
+ if ( order == 10 )
+ { register int in10, y1, y0, y10;
+
+ in10 = ld32x(lpc_in,i);
+ y0 = ((tmp * sex16(in10)) + 16384) >> 15;
+ tmp = ((tmp * g) + 16384) >> 15;
+ y1 = ((tmp * asri(16,in10)) + 16384) >> 15;
+ tmp = ((tmp * g) + 16384) >> 15;
+ y10 = pack16lsb(y1,y0);
+ st32(lpc_out,y10);
+ }
+
+ BWLPC_STOP();
+}
+
+
+#define OVERRIDE_HIGHPASS
+void highpass(const Int16 *x, Int16 *y, int len, int filtID, Int32 *mem)
+{
+ const Int16 Pcoef[5][3] = {{16384, -31313, 14991}, {16384, -31569, 15249}, {16384, -31677, 15328}, {16384, -32313, 15947}, {16384, -22446, 6537}};
+ const Int16 Zcoef[5][3] = {{15672, -31344, 15672}, {15802, -31601, 15802}, {15847, -31694, 15847}, {16162, -32322, 16162}, {14418, -28836, 14418}};
+ register int i;
+ register int den1, den2, num0, num1, num2, den11, den22, mem0, mem1;
+
+ TMDEBUG_ALIGNMEM(mem);
+
+ HIGHPASS_START();
+
+ filtID = imin(4, filtID);
+
+ den1 = -Pcoef[filtID][1];
+ den2 = -Pcoef[filtID][2];
+ num0 = Zcoef[filtID][0];
+ num1 = Zcoef[filtID][1];
+ num2 = Zcoef[filtID][2];
+ den11 = den1 << 1;
+ den22 = den2 << 1;
+ mem0 = mem[0];
+ mem1 = mem[1];
+
+#if (TM_UNROLL && TM_UNROLL_HIGHPASS)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<len ; ++i )
+ {
+ register int yi;
+ register int vout, xi, vout_i, vout_d;
+
+ xi = x[i];
+
+ vout = num0 * xi + mem0;
+ vout_i = vout >> 15;
+ vout_d = vout & 0x7FFF;
+ yi = iclipi(PSHR32(vout,14),32767);
+ mem0 = (mem1 + num1 * xi) + (den11 * vout_i) + (((den1 * vout_d) >> 15) << 1);
+ mem1 = (num2 * xi) + (den22 * vout_i) + (((den2 * vout_d) >> 15) << 1);
+
+ y[i] = yi;
+ }
+#if (TM_UNROLL && TM_UNROLL_HIGHPASS)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ mem[0] = mem0;
+ mem[1] = mem1;
+
+ HIGHPASS_STOP();
+}
+
+
+#define OVERRIDE_SIGNALMUL
+void signal_mul(const Int32 *x, Int32 *y, Int32 scale, int len)
+{
+ register int i, scale_i, scale_d;
+
+ SIGNALMUL_START();
+
+ scale_i = scale >> 14;
+ scale_d = scale & 0x3FFF;
+
+#if (TM_UNROLL && TM_UNROLL_SIGNALMUL)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<len ; ++i)
+ {
+ register int xi;
+
+ xi = x[i] >> 7;
+
+ y[i] = ((xi * scale_i + ((xi * scale_d) >> 14)) << 7);
+
+ }
+#if (TM_UNROLL && TM_UNROLL_SIGNALMUL)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ SIGNALMUL_STOP();
+}
+
+#define OVERRIDE_SIGNALDIV
+void signal_div(const Int16 *x, Int16 *y, Int32 scale, int len)
+{
+ register int i;
+
+ SIGNALDIV_START();
+
+ if (scale > SHL32(EXTEND32(SIG_SCALING), 8))
+ {
+ register int scale_1;
+ scale = PSHR32(scale, SIG_SHIFT);
+ scale_1 = DIV32_16(SHL32(EXTEND32(SIG_SCALING),7),scale);
+#if (TM_UNROLL && TM_UNROLL_SIGNALDIV)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<len ; ++i)
+ {
+ y[i] = MULT16_16_P15(scale_1, x[i]);
+ }
+#if (TM_UNROLL && TM_UNROLL_SIGNALDIV)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ } else if (scale > SHR32(EXTEND32(SIG_SCALING), 2)) {
+
+ register int scale_1;
+ scale = PSHR32(scale, SIG_SHIFT-5);
+ scale_1 = DIV32_16(SHL32(EXTEND32(SIG_SCALING),3),scale);
+#if (TM_UNROLL && TM_UNROLL_SIGNALDIV)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for (i=0;i<len;i++)
+ {
+ y[i] = PSHR32(MULT16_16(scale_1, SHL16(x[i],2)),8);
+ }
+#if (TM_UNROLL && TM_UNROLL_SIGNALDIV)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ } else {
+
+ register int scale_1;
+ scale = PSHR32(scale, SIG_SHIFT-7);
+ scale = imax(5,scale);
+ scale_1 = DIV32_16(SHL32(EXTEND32(SIG_SCALING),3),scale);
+
+#if (TM_UNROLL && TM_UNROLL_SIGNALDIV)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for (i=0;i<len;i++)
+ {
+ y[i] = PSHR32(MULT16_16(scale_1, SHL16(x[i],2)),6);
+ }
+#if (TM_UNROLL && TM_UNROLL_SIGNALDIV)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ }
+
+ SIGNALMUL_STOP();
+}
+
+
+#define OVERRIDE_COMPUTE_RMS
+Int16 compute_rms(const Int32 *x, int len)
+{
+ register int i;
+ register int sum=0;
+ register int max_val=1;
+ register int sig_shift;
+
+ TMDEBUG_ALIGNMEM(x);
+
+ for ( i=0 ; i<len ; i+=4 )
+ {
+ register int tmp0, tmp1, tmp2, tmp3;
+
+ tmp0 = ld32x(x,i);
+ tmp1 = ld32x(x,i+1);
+
+ tmp0 = iabs(tmp0);
+ tmp1 = iabs(tmp1);
+
+ tmp2 = ld32x(x,i+2);
+ tmp3 = ld32x(x,i+3);
+
+ tmp2 = iabs(tmp2);
+ tmp3 = iabs(tmp3);
+
+ tmp0 = imax(tmp0, tmp1);
+ max_val = imax(max_val, tmp0);
+ tmp2 = imax(tmp2, tmp3);
+ max_val = imax(max_val, tmp2);
+ }
+
+ sig_shift = 0;
+ while ( max_val>16383 )
+ { sig_shift++;
+ max_val >>= 1;
+ }
+
+
+ for ( i=0 ; i<len ; i+=4 )
+ {
+ register int acc0, acc1, acc2;
+
+ acc0 = pack16lsb(ld32x(x,i) >> sig_shift, ld32x(x,i+1) >> sig_shift);
+ acc1 = pack16lsb(ld32x(x,i+2) >> sig_shift, ld32x(x,i+3) >> sig_shift);
+ acc2 = ifir16(acc0,acc0) + ifir16(acc1, acc1);
+ sum += acc2 >> 6;
+ }
+
+ return EXTRACT16(PSHR32(SHL32(EXTEND32(spx_sqrt(DIV32(sum,len))),(sig_shift+3)),SIG_SHIFT));
+}
+
+#define OVERRIDE_COMPUTE_RMS16
+Int16 compute_rms16(const Int16 *x, int len)
+{
+ register int max_val, i;
+
+ COMPUTERMS16_START();
+
+ max_val = 10;
+
+#if 0
+
+ {
+ register int len2 = len >> 1;
+#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16)
+#pragma TCS_unroll=2
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<len2 ; i+=2 )
+ {
+ register int x10, x32;
+
+ x10 = ld32x(x,i);
+ x32 = ld32x(x,i+1);
+
+ x10 = dspidualabs(x10);
+ x32 = dspidualabs(x32);
+
+ x10 = imax(sex16(x10), asri(16,x10));
+ x32 = imax(sex16(x32), asri(16,x32));
+
+ max_val = imax(max_val,x10);
+ max_val = imax(max_val,x32);
+ }
+#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ if (max_val>16383)
+ {
+ register int sum = 0;
+#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16)
+#pragma TCS_unroll=2
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<len_2; i+=2 )
+ {
+ register int x10, x32;
+ register int acc0, acc1;
+
+ x10 = ld32x(x,i);
+ x32 = ld32x(x,i+1);
+
+ x10 = dualasr(x10,1);
+ x32 = dualasr(x32,1);
+
+ acc0 = ifir16(x10,x10);
+ acc1 = ifir16(x32,x32);
+ sum += (acc0 + acc1) >> 6;
+ }
+#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ COMPUTERMS16_STOP();
+ return spx_sqrt(sum/len) << 4;
+ } else
+ {
+ register int sig_shift;
+ register int sum=0;
+
+ sig_shift = mux(max_val < 8192, 1, 0);
+ sig_shift = mux(max_val < 4096, 2, sig_shift);
+ sig_shift = mux(max_val < 2048, 3, sig_shift);
+
+#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16)
+#pragma TCS_unroll=2
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<len_2 ; i+=2 )
+ {
+ register int x10, x32;
+ register int acc0, acc1;
+
+ x10 = ld32x(x,i);
+ x32 = ld32x(x,i+1);
+
+ x10 = dualasl(x10,sig_shift);
+ x32 = dualasl(x32,sig_shift);
+
+ acc0 = ifir16(x10,x10);
+ acc1 = ifir16(x32,x32);
+ sum += (acc0 + acc1) >> 6;
+ }
+#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ COMPUTERMS16_STOP();
+ return spx_sqrt(sum/len) << (3 - sig_shift);
+ }
+ }
+
+#else
+ {
+#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<len ; ++i )
+ {
+ register int xi;
+
+ xi = x[i];
+ xi = iabs(xi);
+ max_val = imax(xi,max_val);
+ }
+#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ if (max_val>16383)
+ {
+ register int sum = 0;
+#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16)
+#pragma TCS_unroll=2
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<len ; i+=4 )
+ {
+ register int x10, x32;
+ register int acc0, acc1;
+
+ x10 = pack16lsb(x[i+1],x[i]);
+ x32 = pack16lsb(x[i+3],x[i+2]);
+
+ x10 = dualasr(x10,1);
+ x32 = dualasr(x32,1);
+
+ acc0 = ifir16(x10,x10);
+ acc1 = ifir16(x32,x32);
+ sum += (acc0 + acc1) >> 6;
+ }
+#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ COMPUTERMS16_STOP();
+ return spx_sqrt(sum/len) << 4;
+ } else {
+ register int sig_shift;
+ register int sum=0;
+
+ sig_shift = mux(max_val < 8192, 1, 0);
+ sig_shift = mux(max_val < 4096, 2, sig_shift);
+ sig_shift = mux(max_val < 2048, 3, sig_shift);
+
+#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16)
+#pragma TCS_unroll=2
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<len ; i+=4 )
+ {
+ register int x10, x32;
+ register int acc0, acc1;
+
+ x10 = pack16lsb(x[i+1],x[i]);
+ x32 = pack16lsb(x[i+3],x[i+2]);
+
+ x10 = dualasl(x10,sig_shift);
+ x32 = dualasl(x32,sig_shift);
+
+ acc0 = ifir16(x10,x10);
+ acc1 = ifir16(x32,x32);
+ sum += (acc0 + acc1) >> 6;
+ }
+#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ COMPUTERMS16_STOP();
+ return spx_sqrt(sum/len) << (3 - sig_shift);
+ }
+ }
+#endif
+}
+
+int normalize16_9(const Int32* restrict x, Int16 * restrict y, Int32 max_scale)
+{
+ register int x0, x1, x2, x3, x4, x5, x6, x7, x8;
+ register int max_val, m0, m1, m2, m3, m4;
+ register int sig_shift;
+ register int y10, y32, y54, y76;
+
+ TMDEBUG_ALIGNMEM(x);
+
+ x0 = ld32(x);
+ x1 = ld32x(x,1); x2 = ld32x(x,2); x3 = ld32x(x,3); x4 = ld32x(x,4);
+ x5 = ld32x(x,5); x6 = ld32x(x,6); x7 = ld32x(x,7); x8 = ld32x(x,8);
+
+ m0 = imax(iabs(x0), iabs(x1));
+ m1 = imax(iabs(x2), iabs(x3));
+ m2 = imax(iabs(x4), iabs(x5));
+ m3 = imax(iabs(x6), iabs(x7));
+ m4 = imax(m0, iabs(x8));
+ m1 = imax(m1, m2);
+ m3 = imax(m3, m4);
+ max_val = imax(1,imax(m1,m3));
+
+ sig_shift=0;
+ while (max_val>max_scale)
+ { sig_shift++;
+ max_val >>= 1;
+ }
+
+ if ( sig_shift != 0 )
+ {
+ y10 = pack16lsb(x1 >> sig_shift, x0 >> sig_shift);
+ y32 = pack16lsb(x3 >> sig_shift, x2 >> sig_shift);
+ y54 = pack16lsb(x5 >> sig_shift, x4 >> sig_shift);
+ y76 = pack16lsb(x7 >> sig_shift, x6 >> sig_shift);
+
+ y[8] = x8 >> sig_shift;
+ st32(y,y10);
+ st32d(4,y,y32);
+ st32d(8,y,y54);
+ st32d(12,y,y76);
+ }
+ return sig_shift;
+}
+
+int normalize16_mod8(const Int32 * restrict x, Int16 * restrict y, Int32 max_scale,int len)
+{
+ register int i, max_val, sig_shift;
+
+ TMDEBUG_ALIGNMEM(x);
+
+ max_val = 1;
+
+ for ( i=0 ; i<len ; i+=4 )
+ {
+ register int tmp0, tmp1, tmp2, tmp3;
+
+ tmp0 = ld32x(x,i);
+ tmp1 = ld32x(x,i+1);
+
+ tmp0 = iabs(tmp0);
+ tmp1 = iabs(tmp1);
+
+ tmp2 = ld32x(x,i+2);
+ tmp3 = ld32x(x,i+3);
+
+ tmp2 = iabs(tmp2);
+ tmp3 = iabs(tmp3);
+
+ tmp0 = imax(tmp0, tmp1);
+ max_val = imax(max_val, tmp0);
+ tmp2 = imax(tmp2, tmp3);
+ max_val = imax(max_val, tmp2);
+ }
+
+ sig_shift=0;
+ while (max_val>max_scale)
+ { sig_shift++;
+ max_val >>= 1;
+ }
+
+ if ( sig_shift != 0 )
+ {
+ for ( i=0 ; i<len ; i+=8, y+=8 )
+ {
+ register int x0, x1, x2, x3, x4, x5, x6, x7;
+ register int y10, y32, y54, y76;
+
+ x0 = ld32x(x,i); x1 = ld32x(x,i+1); x2 = ld32x(x,i+2); x3 = ld32x(x,i+3);
+ x4 = ld32x(x,i+4); x5 = ld32x(x,i+5); x6 = ld32x(x,i+6); x7 = ld32x(x,i+7);
+
+ y10 = pack16lsb(x1 >> sig_shift, x0 >> sig_shift);
+ y32 = pack16lsb(x3 >> sig_shift, x2 >> sig_shift);
+ y54 = pack16lsb(x5 >> sig_shift, x4 >> sig_shift);
+ y76 = pack16lsb(x7 >> sig_shift, x6 >> sig_shift);
+
+ st32(y,y10);
+ st32d(4,y,y32);
+ st32d(8,y,y54);
+ st32d(12,y,y76);
+ }
+ }
+ return sig_shift;
+}
+
+
+#define OVERRIDE_NORMALIZE16
+int normalize16(const Int32 *x, Int16 *y, Int32 max_scale, int len)
+{
+ TMDEBUG_ALIGNMEM(x);
+ TMDEBUG_ALIGNMEM(y);
+
+ NORMALIZE16_START();
+
+ if ( len == 9 )
+ { NORMALIZE16_STOP();
+ return normalize16_9(x,y,max_scale);
+ } else
+ { NORMALIZE16_STOP();
+ return normalize16_mod8(x,y,max_scale,len);
+ }
+}
+
+
+void filter_mem16_10(const Int16 *x, const Int16 *num, const Int16 *den, Int16 *y, int N, Int32 *mem)
+{
+ register int i;
+ register int c9, c8, c7, c6, c5;
+ register int c4, c3, c2, c1, c0;
+ register int input;
+ register int output_0, output_1, output_2, output_3, output_4;
+ register int output_5, output_6, output_7, output_8, output_9;
+ register Int16 xi, yi;
+
+ c9 = pack16lsb(-den[9],num[9]);
+ c8 = pack16lsb(-den[8],num[8]);
+ c7 = pack16lsb(-den[7],num[7]);
+ c6 = pack16lsb(-den[6],num[6]);
+ c5 = pack16lsb(-den[5],num[5]);
+ c4 = pack16lsb(-den[4],num[4]);
+ c3 = pack16lsb(-den[3],num[3]);
+ c2 = pack16lsb(-den[2],num[2]);
+ c1 = pack16lsb(-den[1],num[1]);
+ c0 = pack16lsb(-den[0],num[0]);
+
+ output_0 = mem[0];
+ output_1 = mem[1];
+ output_2 = mem[2];
+ output_3 = mem[3];
+ output_4 = mem[4];
+ output_5 = mem[5];
+ output_6 = mem[6];
+ output_7 = mem[7];
+ output_8 = mem[8];
+ output_9 = mem[9];
+
+#if (TM_UNROLL && TM_UNROLL_FILTER)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+
+ for ( i=0 ; i<N ; i++ )
+ {
+ xi = (int)(x[i]);
+ yi = iclipi(iadd(xi,PSHR32(output_0,LPC_SHIFT)),32767);
+
+ input = pack16lsb(yi,xi);
+ output_0= iadd(ifir16(c0,input),output_1);
+ output_1= iadd(ifir16(c1,input),output_2);
+ output_2= iadd(ifir16(c2,input),output_3);
+ output_3= iadd(ifir16(c3,input),output_4);
+ output_4= iadd(ifir16(c4,input),output_5);
+ output_5= iadd(ifir16(c5,input),output_6);
+ output_6= iadd(ifir16(c6,input),output_7);
+ output_7= iadd(ifir16(c7,input),output_8);
+ output_8= iadd(ifir16(c8,input),output_9);
+ output_9= ifir16(c9,input);
+
+ y[i] = yi;
+ }
+
+#if (TM_UNROLL && TM_UNROLL_FILTER)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ mem[0] = output_0;
+ mem[1] = output_1;
+ mem[2] = output_2;
+ mem[3] = output_3;
+ mem[4] = output_4;
+ mem[5] = output_5;
+ mem[6] = output_6;
+ mem[7] = output_7;
+ mem[8] = output_8;
+ mem[9] = output_9;
+}
+
+void filter_mem16_8(const Int16 *x, const Int16 *num, const Int16 *den, Int16 *y, int N, Int32 *mem)
+{
+ register int i;
+ register int c7, c6, c5, c4, c3, c2, c1, c0;
+ register int output_0, output_1, output_2, output_3, output_4, output_5, output_6, output_7;
+ register int input;
+ register Int16 xi, yi;
+
+ c7 = pack16lsb(-den[7],num[7]);
+ c6 = pack16lsb(-den[6],num[6]);
+ c5 = pack16lsb(-den[5],num[5]);
+ c4 = pack16lsb(-den[4],num[4]);
+ c3 = pack16lsb(-den[3],num[3]);
+ c2 = pack16lsb(-den[2],num[2]);
+ c1 = pack16lsb(-den[1],num[1]);
+ c0 = pack16lsb(-den[0],num[0]);
+
+ output_0 = mem[0];
+ output_1 = mem[1];
+ output_2 = mem[2];
+ output_3 = mem[3];
+ output_4 = mem[4];
+ output_5 = mem[5];
+ output_6 = mem[6];
+ output_7 = mem[7];
+
+#if (TM_UNROLL && TM_UNROLL_FILTER)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+
+ for ( i=0 ; i<N ; i++ )
+ {
+ xi = x[i];
+ yi = iclipi(iadd((int)(xi),PSHR32(output_0,LPC_SHIFT)),32767);
+
+ input = pack16lsb(yi,xi);
+ output_0= iadd(ifir16(c0,input),output_1);
+ output_1= iadd(ifir16(c1,input),output_2);
+ output_2= iadd(ifir16(c2,input),output_3);
+ output_3= iadd(ifir16(c3,input),output_4);
+ output_4= iadd(ifir16(c4,input),output_5);
+ output_5= iadd(ifir16(c5,input),output_6);
+ output_6= iadd(ifir16(c6,input),output_7);
+ output_7= ifir16(c7,input);
+
+ y[i] = yi;
+ }
+
+#if (TM_UNROLL && TM_UNROLL_FILTER)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+
+ mem[0] = output_0;
+ mem[1] = output_1;
+ mem[2] = output_2;
+ mem[3] = output_3;
+ mem[4] = output_4;
+ mem[5] = output_5;
+ mem[6] = output_6;
+ mem[7] = output_7;
+}
+
+#define OVERRIDE_FILTER_MEM16
+void filter_mem16(const Int16 *x, const Int16 *num, const Int16 *den, Int16 *y, int N, int ord, Int32 *mem, char *stack)
+{
+ TMDEBUG_ALIGNMEM(x);
+ TMDEBUG_ALIGNMEM(y);
+ TMDEBUG_ALIGNMEM(num);
+ TMDEBUG_ALIGNMEM(den);
+
+ FILTERMEM16_START();
+
+ if(ord==10)
+ filter_mem16_10(x, num, den, y, N, mem);
+ else if (ord==8)
+ filter_mem16_8(x, num, den, y, N, mem);
+
+#ifndef REMARK_ON
+ (void)stack;
+#endif
+
+ FILTERMEM16_STOP();
+}
+
+void iir_mem16_8(const Int16 *x, const Int16 *den, Int16 *y, int N, Int32 *mem)
+{
+ register int i;
+ register int c67, c45, c23, c01;
+ register int r1, r2, r3;
+ register int y10, y32, y54, y76, yi;
+
+ c67 = pack16lsb(-den[6],-den[7]);
+ c45 = pack16lsb(-den[4],-den[5]);
+ c23 = pack16lsb(-den[2],-den[3]);
+ c01 = pack16lsb(-den[0],-den[1]);
+
+ y10 = mem[0];
+ y32 = mem[1];
+ y54 = mem[2];
+ y76 = mem[3];
+
+#if (TM_UNROLL && TM_UNROLL_IIR)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+
+ for ( i=0 ; i < N ; ++i )
+ {
+ r2 = iadd(ifir16(y10,c67),ifir16(y32,c45));
+ r3 = iadd(ifir16(y54,c23),ifir16(y76,c01));
+ r1 = iadd(r2,r3);
+
+ y10 = funshift2(y32, y10);
+ y32 = funshift2(y54, y32);
+ y54 = funshift2(y76, y54);
+
+ yi = iclipi(iadd((int)(x[i]),PSHR32(r1,LPC_SHIFT)),32767);
+ y[i]= yi;
+ y76 = funshift2(yi, y76);
+ }
+
+#if (TM_UNROLL && TM_UNROLL_IIR)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ mem[0] = y10;
+ mem[1] = y32;
+ mem[2] = y54;
+ mem[3] = y76;
+
+}
+
+void iir_mem16_10(const Int16 *x, const Int16 *den, Int16 *y, int N, Int32 *mem)
+{
+ register int i;
+ register int c89, c67, c45, c23, c01;
+ register int r1, r2, r3, r4, r5;
+ register int y10, y32, y54, y76, y98, yi;
+
+ c89 = pack16lsb(-den[8],-den[9]);
+ c67 = pack16lsb(-den[6],-den[7]);
+ c45 = pack16lsb(-den[4],-den[5]);
+ c23 = pack16lsb(-den[2],-den[3]);
+ c01 = pack16lsb(-den[0],-den[1]);
+
+ y10 = mem[0];
+ y32 = mem[1];
+ y54 = mem[2];
+ y76 = mem[3];
+ y98 = mem[4];
+
+#if (TM_UNROLL && TM_UNROLL_IIR)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+
+ for ( i=0 ; i < N ; ++i )
+ {
+ r2 = iadd(ifir16(y10,c89),ifir16(y32,c67));
+ r3 = iadd(ifir16(y54,c45),ifir16(y76,c23));
+ r4 = ifir16(y98,c01);
+ r5 = iadd(r2,r3);
+ r1 = iadd(r4,r5);
+
+ y10 = funshift2(y32, y10);
+ y32 = funshift2(y54, y32);
+ y54 = funshift2(y76, y54);
+ y76 = funshift2(y98, y76);
+
+ yi = iclipi(iadd((int)(x[i]),PSHR32(r1,LPC_SHIFT)),32767);
+ y[i]= yi;
+ y98 = funshift2(yi, y98);
+ }
+
+#if (TM_UNROLL && TM_UNROLL_IIR)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ mem[0] = y10;
+ mem[1] = y32;
+ mem[2] = y54;
+ mem[3] = y76;
+ mem[4] = y98;
+}
+
+#define OVERRIDE_IIR_MEM16
+void iir_mem16(const Int16 *x, const Int16 *den, Int16 *y, int N, int ord, Int32 *mem, char *stack)
+{
+ TMDEBUG_ALIGNMEM(den);
+
+ IIRMEM16_START();
+
+ if(ord==10)
+ iir_mem16_10(x, den, y, N, mem);
+ else if (ord==8)
+ iir_mem16_8(x, den, y, N, mem);
+
+#ifndef REMARK_ON
+ (void)stack;
+#endif
+
+ IIRMEM16_STOP();
+}
+
+void fir_mem16_8(const Int16 *x, const Int16 *num, Int16 *y, int N, Int32 *mem)
+{
+ register int i, N_2;
+ register int c67, c45, c23, c01;
+ register int b0, b1, b2, b3;
+ register int r1, r2, r3;
+ register int x10, x32, x54, x76, xi;
+ register Int16 *a;
+
+ N_2 = N >> 1;
+
+ c67 = ld32x(num,3);
+ c45 = ld32x(num,2);
+ c23 = ld32x(num,1);
+ c01 = ld32x(num,0);
+
+ c67 = funshift2(c67,c67);
+ c45 = funshift2(c45,c45);
+ c23 = funshift2(c23,c23);
+ c01 = funshift2(c01,c01);
+
+ b3 = x76 = ld32x(x,N_2-1);
+ b2 = x54 = ld32x(x,N_2-2);
+ b1 = x32 = ld32x(x,N_2-3);
+ b0 = x10 = ld32x(x,N_2-4);
+
+#if (TM_UNROLL && TM_UNROLL_FILTER > 0)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+
+ for ( i=N-1 ; i >= 8 ; --i )
+ {
+ xi = asri(16,x76);
+ x76 = funshift2(x76, x54);
+ x54 = funshift2(x54, x32);
+ x32 = funshift2(x32, x10);
+ x10 = pack16lsb(x10, (int)x[i-8]);
+
+ r2 = iadd(ifir16(x10,c67),ifir16(x32,c45));
+ r3 = iadd(ifir16(x54,c23),ifir16(x76,c01));
+ r1 = iadd(r2,r3);
+
+ y[i] = iclipi(iadd(xi,PSHR32(r1,LPC_SHIFT)),32767);
+ }
+ for ( i=7, a=(Int16*)mem ; i>=0 ; --i )
+ {
+ xi = asri(16,x76);
+ x76 = funshift2(x76, x54);
+ x54 = funshift2(x54, x32);
+ x32 = funshift2(x32, x10);
+ x10 = pack16lsb(x10, (int)a[i]);
+
+ r2 = iadd(ifir16(x10,c67),ifir16(x32,c45));
+ r3 = iadd(ifir16(x54,c23),ifir16(x76,c01));
+ r1 = iadd(r2,r3);
+
+ y[i] = iclipi(iadd(xi,PSHR32(r1,LPC_SHIFT)),32767);
+ }
+
+#if (TM_UNROLL && TM_UNROLL_FILTER > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ mem[0] = b0;
+ mem[1] = b1;
+ mem[2] = b2;
+ mem[3] = b3;
+}
+
+void fir_mem16_10(const Int16 *x, const Int16 *num, Int16 *y, int N, Int32 *mem)
+{
+ register int N_2, i;
+ register int c89, c67, c45, c23, c01;
+ register int b0, b1, b2, b3, b4;
+ register int r1, r2, r3, r4, r5;
+ register int x10, x32, x54, x76, x98, xi;
+ register Int16 *a;
+
+ N_2 = N >> 1;
+
+ c89 = ld32x(num,4);
+ c67 = ld32x(num,3);
+ c45 = ld32x(num,2);
+ c23 = ld32x(num,1);
+ c01 = ld32x(num,0);
+
+ c89 = funshift2(c89,c89);
+ c67 = funshift2(c67,c67);
+ c45 = funshift2(c45,c45);
+ c23 = funshift2(c23,c23);
+ c01 = funshift2(c01,c01);
+
+ b4 = x98 = ld32x(x,N_2-1);
+ b3 = x76 = ld32x(x,N_2-2);
+ b2 = x54 = ld32x(x,N_2-3);
+ b1 = x32 = ld32x(x,N_2-4);
+ b0 = x10 = ld32x(x,N_2-5);
+
+#if (TM_UNROLL && TM_UNROLL_FIR > 0)
+#pragma TCS_unroll=5
+#pragma TCS_unrollexact=1
+#endif
+
+ for ( i=N-1 ; i >= 10 ; --i )
+ {
+ xi = asri(16,x98);
+ x98 = funshift2(x98, x76);
+ x76 = funshift2(x76, x54);
+ x54 = funshift2(x54, x32);
+ x32 = funshift2(x32, x10);
+ x10 = pack16lsb(x10, (int)(x[i-10]));
+
+ r2 = iadd(ifir16(x10,c89),ifir16(x32,c67));
+ r3 = iadd(ifir16(x54,c45),ifir16(x76,c23));
+ r4 = ifir16(x98,c01);
+ r5 = iadd(r2,r3);
+ r1 = iadd(r4,r5);
+
+ y[i] = iclipi(iadd(xi,PSHR32(r1,LPC_SHIFT)),32767);
+ }
+
+ for ( i=9,a =(Int16*)mem ; i>=0 ; --i )
+ {
+ xi = asri(16,x98);
+ x98 = funshift2(x98, x76);
+ x76 = funshift2(x76, x54);
+ x54 = funshift2(x54, x32);
+ x32 = funshift2(x32, x10);
+ x10 = pack16lsb(x10, (int)(a[i]));
+
+ r2 = iadd(ifir16(x10,c89),ifir16(x32,c67));
+ r3 = iadd(ifir16(x54,c45),ifir16(x76,c23));
+ r4 = ifir16(x98,c01);
+ r5 = iadd(r2,r3);
+ r1 = iadd(r4,r5);
+
+ y[i] = iclipi(iadd(xi,PSHR32(r1,LPC_SHIFT)),32767);
+ }
+
+#if (TM_UNROLL && TM_UNROLL_FIR > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ mem[0] = b0;
+ mem[1] = b1;
+ mem[2] = b2;
+ mem[3] = b3;
+ mem[4] = b4;
+
+
+}
+
+#define OVERRIDE_FIR_MEM16
+void fir_mem16(const spx_word16_t *x, const Int16 *num, spx_word16_t *y, int N, int ord, Int32 *mem, char *stack)
+{
+ TMDEBUG_ALIGNMEM(x);
+ TMDEBUG_ALIGNMEM(y);
+ TMDEBUG_ALIGNMEM(num);
+
+ FIRMEM16_START();
+
+ if(ord==10)
+ fir_mem16_10(x, num, y, N, mem);
+ else if (ord==8)
+ fir_mem16_8(x, num, y, N, mem);
+
+#ifndef REMARK_ON
+ (void)stack;
+#endif
+
+ FIRMEM16_STOP();
+}
+
+
+
+#define OVERRIDE_SYN_PERCEP_ZERO16
+void syn_percep_zero16(const Int16 *xx, const Int16 *ak, const Int16 *awk1, const Int16 *awk2, Int16 *y, int N, int ord, char *stack)
+{
+ register int i,j;
+ VARDECL(Int32 *mem);
+ ALLOC(mem, ord, Int32);
+
+ TMDEBUG_ALIGNMEM(mem);
+
+ for ( i=0,j=0 ; i<ord ; ++i,j+=4 )
+ st32d(j,mem,0);
+ iir_mem16(xx, ak, y, N, ord, mem, stack);
+ for ( i=0,j=0 ; i<ord ; ++i,j+=4 )
+ st32d(j,mem,0);
+ filter_mem16(y, awk1, awk2, y, N, ord, mem, stack);
+}
+
+
+#define OVERRIDE_RESIDUE_PERCEP_ZER016
+void residue_percep_zero16(const Int16 *xx, const Int16 *ak, const Int16 *awk1, const Int16 *awk2, Int16 *y, int N, int ord, char *stack)
+{
+ register int i,j;
+ VARDECL(Int32 *mem);
+ ALLOC(mem, ord, Int32);
+
+ TMDEBUG_ALIGNMEM(mem);
+
+ for ( i=0,j=0 ; i<ord ; ++i,j+=4 )
+ st32d(j,mem,0);
+ filter_mem16(xx, ak, awk1, y, N, ord, mem, stack);
+ for ( i=0,j=0 ; i<ord ; ++i,j+=4 )
+ st32d(j,mem,0);
+ fir_mem16(y, awk2, y, N, ord, mem, stack);
+}
+
+
+
+void compute_impulse_response_10(const Int16 *ak, const Int16 *awk1, const Int16 *awk2, Int16 *y, int N)
+{
+ register int awk_01, awk_23, awk_45, awk_67, awk_89;
+ register int y10, y32, y54, y76, y98, yi;
+ register int i, acc0, acc1, N_2;
+
+ N_2 = N << 1;
+
+ awk_01 = ld32(awk1);
+ awk_23 = ld32x(awk1,1);
+ awk_45 = ld32x(awk1,2);
+ awk_67 = ld32x(awk1,3);
+ awk_89 = ld32x(awk1,4);
+
+ y10 = funshift2(awk_01, LPC_SCALING << 16);
+ st32d(0, y, y10);
+ y32 = funshift2(awk_23, awk_01);
+ st32d(4, y, y32);
+ y54 = funshift2(awk_45, awk_23);
+ st32d(8, y, y54);
+ y76 = funshift2(awk_67, awk_45);
+ st32d(12, y, y76);
+ y98 = funshift2(awk_89, awk_67);
+ st32d(16, y, y98);
+ y10 = funshift2(0, awk_89);
+ st32d(20, y, y10);
+#if (TM_UNROLL && TM_UNROLL_COMPUTEIMPULSERESPONSE > 0)
+#pragma TCS_unroll=2
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=24 ; i<N_2 ; i+=4 )
+ { st32d(i, y, 0);
+ }
+#if (TM_UNROLL && TM_UNROLL_COMPUTEIMPULSERESPONSE > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ y10 = y32 = y54 = y76 = y98 = 0;
+ awk_01 = ld32(awk2);
+ awk_23 = ld32x(awk2,1);
+ awk_45 = ld32x(awk2,2);
+ awk_67 = ld32x(awk2,3);
+ awk_89 = ld32x(awk2,4);
+
+ awk_01 = funshift2(awk_01, awk_01);
+ awk_23 = funshift2(awk_23, awk_23);
+ awk_45 = funshift2(awk_45, awk_45);
+ awk_67 = funshift2(awk_67, awk_67);
+ awk_89 = funshift2(awk_89, awk_89);
+
+#if (TM_UNROLL && TM_UNROLL_COMPUTEIMPULSERESPONSE > 0)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<N ; ++i )
+ {
+ yi = y[i];
+
+ acc0 = ifir16(y10, awk_89) + ifir16(y32, awk_67);
+ acc1 = ifir16(y54, awk_45) + ifir16(y76, awk_23);
+ yi += PSHR32(acc0 + acc1 + ifir16(y98, awk_01),LPC_SHIFT);
+ y[i] = yi;
+
+ y10 = funshift2(y32, y10);
+ y32 = funshift2(y54, y32);
+ y54 = funshift2(y76, y54);
+ y76 = funshift2(y98, y76);
+ y98 = funshift2(ineg(yi), y98);
+ }
+#if (TM_UNROLL && TM_UNROLL_COMPUTEIMPULSERESPONSE > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ y10 = y32 = y54 = y76 = y98 = 0;
+ awk_01 = ld32(ak);
+ awk_23 = ld32x(ak,1);
+ awk_45 = ld32x(ak,2);
+ awk_67 = ld32x(ak,3);
+ awk_89 = ld32x(ak,4);
+ awk_01 = funshift2(awk_01, awk_01);
+ awk_23 = funshift2(awk_23, awk_23);
+ awk_45 = funshift2(awk_45, awk_45);
+ awk_67 = funshift2(awk_67, awk_67);
+ awk_89 = funshift2(awk_89, awk_89);
+
+#if (TM_UNROLL && TM_UNROLL_COMPUTEIMPULSERESPONSE > 0)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<N ; ++i )
+ {
+ yi = y[i];
+
+ acc0 = ifir16(y10, awk_89) + ifir16(y32, awk_67);
+ acc1 = ifir16(y54, awk_45) + ifir16(y76, awk_23);
+ yi = PSHR32(SHL32(yi,LPC_SHIFT+1) + acc0 + acc1 + ifir16(y98, awk_01),LPC_SHIFT);
+ y[i] = yi;
+
+ y10 = funshift2(y32, y10);
+ y32 = funshift2(y54, y32);
+ y54 = funshift2(y76, y54);
+ y76 = funshift2(y98, y76);
+ y98 = funshift2(ineg(yi), y98);
+ }
+#if (TM_UNROLL && TM_UNROLL_COMPUTEIMPULSERESPONSE > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+}
+
+void compute_impulse_response_8(const Int16 *ak, const Int16 *awk1, const Int16 *awk2, Int16 *y, int N)
+{
+ register int awk_01, awk_23, awk_45, awk_67;
+ register int y10, y32, y54, y76, yi;
+ register int i, acc0, acc1, N_2;
+
+ N_2 = N << 1;
+
+ awk_01 = ld32(awk1);
+ awk_23 = ld32x(awk1,1);
+ awk_45 = ld32x(awk1,2);
+ awk_67 = ld32x(awk1,3);
+
+ y10 = funshift2(awk_01, LPC_SCALING << 16);
+ st32d(0, y, y10);
+ y32 = funshift2(awk_23, awk_01);
+ st32d(4, y, y32);
+ y54 = funshift2(awk_45, awk_23);
+ st32d(8, y, y54);
+ y76 = funshift2(awk_67, awk_45);
+ st32d(12, y, y76);
+ y10 = funshift2(0, awk_67);
+ st32d(16, y, y10);
+ st32d(20, y, 0);
+
+#if (TM_UNROLL && TM_UNROLL_COMPUTEIMPULSERESPONSE > 0)
+#pragma TCS_unroll=2
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=24 ; i<N_2 ; i+=4 )
+ { st32d(i, y, 0);
+ }
+#if (TM_UNROLL && TM_UNROLL_COMPUTEIMPULSERESPONSE > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ y10 = y32 = y54 = y76 = 0;
+ awk_01 = ld32(awk2);
+ awk_23 = ld32x(awk2,1);
+ awk_45 = ld32x(awk2,2);
+ awk_67 = ld32x(awk2,3);
+
+ awk_01 = funshift2(awk_01, awk_01);
+ awk_23 = funshift2(awk_23, awk_23);
+ awk_45 = funshift2(awk_45, awk_45);
+ awk_67 = funshift2(awk_67, awk_67);
+#if (TM_UNROLL && TM_UNROLL_COMPUTEIMPULSERESPONSE > 0)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<N ; ++i )
+ {
+ yi = y[i];
+
+ acc0 = ifir16(y10, awk_67) + ifir16(y32, awk_45);
+ acc1 = ifir16(y54, awk_23) + ifir16(y76, awk_01);
+ yi += PSHR32(acc0 + acc1,LPC_SHIFT);
+ y[i] = yi;
+
+ y10 = funshift2(y32, y10);
+ y32 = funshift2(y54, y32);
+ y54 = funshift2(y76, y54);
+ y76 = funshift2(ineg(yi), y76);
+ }
+#if (TM_UNROLL && TM_UNROLL_COMPUTEIMPULSERESPONSE > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ y10 = y32 = y54 = y76 = 0;
+ awk_01 = ld32(ak);
+ awk_23 = ld32x(ak,1);
+ awk_45 = ld32x(ak,2);
+ awk_67 = ld32x(ak,3);
+ awk_01 = funshift2(awk_01, awk_01);
+ awk_23 = funshift2(awk_23, awk_23);
+ awk_45 = funshift2(awk_45, awk_45);
+ awk_67 = funshift2(awk_67, awk_67);
+#if (TM_UNROLL && TM_UNROLL_COMPUTEIMPULSERESPONSE > 0)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<N ; ++i )
+ {
+ yi = y[i];
+
+ acc0 = ifir16(y10, awk_67) + ifir16(y32, awk_45);
+ acc1 = ifir16(y54, awk_23) + ifir16(y76, awk_01);
+ yi = PSHR32(SHL32(yi,LPC_SHIFT+1) + acc0 + acc1,LPC_SHIFT);
+ y[i] = yi;
+
+ y10 = funshift2(y32, y10);
+ y32 = funshift2(y54, y32);
+ y54 = funshift2(y76, y54);
+ y76 = funshift2(ineg(yi), y76);
+ }
+#if (TM_UNROLL && TM_UNROLL_COMPUTEIMPULSERESPONSE > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+}
+
+
+#define OVERRIDE_COMPUTE_IMPULSE_RESPONSE
+void compute_impulse_response(const Int16 *ak, const Int16 *awk1, const Int16 *awk2, Int16 *y, int N, int ord, char *stack)
+{
+ TMDEBUG_ALIGNMEM(ak);
+ TMDEBUG_ALIGNMEM(awk1);
+ TMDEBUG_ALIGNMEM(awk2);
+ TMDEBUG_ALIGNMEM(y);
+
+ COMPUTEIMPULSERESPONSE_START();
+ if ( ord == 10 )
+ compute_impulse_response_10(ak,awk1,awk2,y,N);
+ else
+ compute_impulse_response_8(ak,awk1,awk2,y,N);
+
+ (void)stack;
+
+ COMPUTEIMPULSERESPONSE_STOP();
+}
+
+
+#define OVERRIDE_QMFSYNTH
+void qmf_synth(const Int16 *x1, const Int16 *x2, const Int16 *a, Int16 *y, int N, int M, Int32 *mem1, Int32 *mem2, char *stack)
+ /* assumptions:
+ all odd x[i] are zero -- well, actually they are left out of the array now
+ N and M are multiples of 4 */
+{
+ register int i, j;
+ register int M2, N2;
+ VARDECL(int *x12);
+ M2 = M>>1;
+ N2 = N>>1;
+ ALLOC(x12, M2+N2, int);
+
+
+ TMDEBUG_ALIGNMEM(a);
+ TMDEBUG_ALIGNMEM(x12);
+ TMDEBUG_ALIGNMEM(mem1);
+ TMDEBUG_ALIGNMEM(mem2);
+
+ QMFSYNTH_START();
+
+#if (TM_UNROLL && TM_UNROLL_QMFSYNTH > 0)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<N2 ; ++i )
+ { register int index = N2-1-i;
+ x12[i] = pack16lsb(x1[index],x2[index]);
+ }
+
+ for ( j= 0; j<M2 ; ++j)
+ { register int index = (j << 1) + 1;
+ x12[N2+j] = pack16lsb(mem1[index],mem2[index]);
+ }
+#if (TM_UNROLL && TM_UNROLL_QMFSYNTH > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ for (i = 0; i < N2; i += 2)
+ {
+ register int y0, y1, y2, y3;
+ register int x12_0;
+
+ y0 = y1 = y2 = y3 = 0;
+ x12_0 = x12[N2-2-i];
+
+ for (j = 0; j < M2; j += 2)
+ {
+ register int x12_1;
+ register int a10, a11, a0_0;
+ register int _a10, _a11, _a0_0;
+
+ a10 = ld32x(a,j);
+ a11 = pack16msb(a10,a10);
+ a0_0= pack16lsb(a10,ineg(sex16(a10)));
+ x12_1 = x12[N2-1+j-i];
+
+ y0 += ifir16(a0_0,x12_1);
+ y1 += ifir16(a11, x12_1);
+ y2 += ifir16(a0_0,x12_0);
+ y3 += ifir16(a11 ,x12_0);
+
+
+ _a10 = ld32x(a,j+1);
+ _a11 = pack16msb(_a10,_a10);
+ _a0_0 = pack16lsb(_a10,ineg(sex16(_a10)));
+ x12_0 = x12[N2+j-i];
+
+ y0 += ifir16(_a0_0,x12_0);
+ y1 += ifir16(_a11, x12_0);
+ y2 += ifir16(_a0_0,x12_1);
+ y3 += ifir16(_a11 ,x12_1);
+
+ }
+ y[2*i] = EXTRACT16(SATURATE32(PSHR32(y0,15),32767));
+ y[2*i+1] = EXTRACT16(SATURATE32(PSHR32(y1,15),32767));
+ y[2*i+2] = EXTRACT16(SATURATE32(PSHR32(y2,15),32767));
+ y[2*i+3] = EXTRACT16(SATURATE32(PSHR32(y3,15),32767));
+ }
+
+#if (TM_UNROLL && TM_UNROLL_QMFSYNTH > 0)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for (i = 0; i < M2; ++i)
+ { mem1[2*i+1] = asri(16,x12[i]);
+ mem2[2*i+1] = sex16(x12[i]);
+ }
+#if (TM_UNROLL && TM_UNROLL_QMFSYNTH > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ QMFSYNTH_STOP();
+}
+
+
+#define OVERRIDE_QMFDECOMP
+void qmf_decomp(const Int16 *xx, const Int16 *aa, Int16 *y1, Int16 *y2, int N, int M, Int16 *mem, char *stack)
+{
+ VARDECL(int *_a);
+ VARDECL(int *_x);
+ register int i, j, k, MM, M2, N2;
+ register int _xx10, _mm10;
+ register int *_x2;
+
+ M2=M>>1;
+ N2=N>>1;
+ MM=(M-2)<<1;
+
+ ALLOC(_a, M2, int);
+ ALLOC(_x, N2+M2, int);
+ _x2 = _x + M2 - 1;
+
+ TMDEBUG_ALIGNMEM(xx);
+ TMDEBUG_ALIGNMEM(aa);
+ TMDEBUG_ALIGNMEM(y1);
+ TMDEBUG_ALIGNMEM(y2);
+ TMDEBUG_ALIGNMEM(mem);
+ TMDEBUG_ALIGNMEM(_a);
+ TMDEBUG_ALIGNMEM(_x);
+
+ QMFDECOMP_START();
+
+ _xx10 = ld32(xx);
+ _xx10 = dualasr(_xx10,1);
+ _mm10 = ld32(mem);
+ _x2[0] = pack16lsb(_xx10,_mm10);
+
+#if (TM_UNROLL && TM_UNROLL_QMFSYNTH > 0)
+#pragma TCS_unroll=2
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<M2 ; ++i )
+ { register int a10;
+
+ a10 = ld32x(aa,i);
+ a10 = funshift2(a10, a10);
+ _a[M2-i-1] = a10;
+ }
+
+ for ( j=1 ; j<N2 ; ++j )
+ { register int _xx32;
+
+ _xx32 = ld32x(xx,j);
+ _xx32 = dualasr(_xx32,1);
+ _x2[j] = funshift2(_xx32, _xx10);
+ _xx10 = _xx32;
+ }
+
+ for ( k=1 ; k<M2; ++k )
+ { register int _mm32;
+
+ _mm32 = ld32x(mem,k);
+ _mm10 = funshift2(_mm10,_mm10);
+ _x2[-k] = pack16lsb(_mm10,_mm32);
+ _mm10 = _mm32;
+ }
+
+
+ for ( i=N2-1,j=0 ; j<MM ; --i,j+=4 )
+ { register int _xx;
+
+ _xx = ld32x(xx,i);
+ _xx = dualasr(_xx,1);
+ _xx = funshift2(_xx,_xx);
+ st32d(j, mem, _xx);
+ }
+#if (TM_UNROLL && TM_UNROLL_QMFSYNTH > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ mem[M-2] = xx[N-M+1] >> 1;
+
+
+ M2 >>= 1;
+ for ( i=0 ; i<N2 ; ++i )
+ { register int y1k, y2k;
+
+ y1k = y2k = 0;
+
+ for ( j=0 ; j<M2 ; j+=2 )
+ { register int _aa, _acc0, _acc1;
+ register int __xx10, __mm10, __acc0, __acc1, __aa;
+ register int _tmp0, _tmp1, _tmp2, _tmp3;
+
+ _xx10 = ld32x(_x, i+j);
+ _mm10 = ld32x(_x2,i-j);
+ _aa = ld32x(_a, j);
+ _mm10 = funshift2(_mm10,_mm10);
+ _acc0 = dspidualadd(_xx10, _mm10);
+ _acc1 = dspidualsub(_xx10, _mm10);
+
+ __xx10 = ld32x(_x, i+j+1);
+ __mm10 = ld32x(_x2,i-j-1);
+ __aa = ld32x(_a, j+1);
+ __mm10 = funshift2(__mm10,__mm10);
+ __acc0 = dspidualadd(__xx10, __mm10);
+ __acc1 = dspidualsub(__xx10, __mm10);
+
+ y1k += ifir16(_aa, _acc0);
+ y1k += ifir16(__aa, __acc0);
+
+ _tmp0 = pack16lsb(_aa,__aa);
+ _tmp1 = pack16msb(_aa,__aa);
+ _tmp2 = pack16lsb(_acc1, __acc1);
+ _tmp3 = pack16msb(_acc1, __acc1);
+
+ y2k -= ifir16(_tmp0, _tmp2);
+ y2k += ifir16(_tmp1, _tmp3);
+
+ }
+
+ y1[i] = iclipi(PSHR32(y1k,15),32767);
+ y2[i] = iclipi(PSHR32(y2k,15),32767);
+ }
+
+ QMFDECOMP_STOP();
+}
+
+#endif
+
diff --git a/tmv/fixed_tm.h b/tmv/fixed_tm.h new file mode 100644 index 0000000..c8fa968 --- /dev/null +++ b/tmv/fixed_tm.h @@ -0,0 +1,100 @@ +/* Copyright (C) 2007 Hong Zhiqian */
+/**
+ @file fixed_tm.h
+ @author Hong Zhiqian
+ @brief Various compatibility routines for Speex (TriMedia version)
+*/
+/*
+ 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 the Xiph.org Foundation 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 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 FIXED_TM_H
+#define FIXED_TM_H
+
+#include <ops/custom_defs.h>
+
+
+#undef SATURATE
+#undef SATURATE16
+#undef SATURATE32
+#define SATURATE(x,a) iclipi(x,a)
+#define SATURATE16(x,a) iclipi(x,a)
+#define SATURATE32(x,a) iclipi(x,a)
+
+#undef EXTEND32
+#define EXTEND32(x) sex16(x)
+
+#undef NEG16
+#undef NEG32
+#define NEG16(x) ineg((int)(x))
+#define NEG32(x) ineg(x)
+
+#undef ABS
+#undef ABS16
+#undef ABS32
+#define ABS(x) iabs(x)
+#define ABS32(x) iabs(x)
+#define ABS16(x) iabs((int)(x))
+
+#undef MIN16
+#undef MIN32
+#define MIN16(a,b) imin((int)(a),(int)(b))
+#define MIN32(a,b) imin(a,b)
+
+#undef MAX16
+#undef MAX32
+#define MAX16(a,b) imax((int)(a),(int)(b))
+#define MAX32(a,b) imax(a,b)
+
+#undef ADD16
+#undef SUB16
+#undef ADD32
+#undef SUB32
+#undef MULT16_16
+#undef MULT16_16_16
+
+#define ADD16(a,b) ((int)(a) + (int)(b))
+#define SUB16(a,b) ((int)(a) - (int)(b))
+#define ADD32(a,b) ((int)(a) + (int)(b))
+#define SUB32(a,b) ((int)(a) - (int)(b))
+#define MULT16_16_16(a,b) ((int)(a) * (int)(b))
+#define MULT16_16(a,b) ((int)(a) * (int)(b))
+
+#if TM_DEBUGMEM_ALIGNNMENT
+#include <stdio.h>
+#define TMDEBUG_ALIGNMEM(x) \
+ { if( ((int)(x) & (int)(0x00000003)) != 0 ) \
+ { printf("memory not align. file: %s, line: %d\n", __FILE__, __LINE__); \
+ } \
+ }
+
+#else
+#define TMDEBUG_ALIGNMEM(x)
+#endif
+
+#endif
+
diff --git a/tmv/kiss_fft_tm.h b/tmv/kiss_fft_tm.h new file mode 100644 index 0000000..dce2072 --- /dev/null +++ b/tmv/kiss_fft_tm.h @@ -0,0 +1,599 @@ +/* Copyright (C) 2007 Hong Zhiqian */
+/**
+ @file kiss_fft_tm.h
+ @author Hong Zhiqian
+ @brief Various compatibility routines for Speex (TriMedia version)
+*/
+/*
+ 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 the Xiph.org Foundation 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 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.
+*/
+
+#include "_kiss_fft_guts_tm.h"
+
+#ifdef TM_ASM
+
+#include "profile_tm.h"
+
+#ifdef FIXED_POINT
+
+#define OVERRIDE_KFBFLY2
+static void kf_bfly2(
+ kiss_fft_cpx *Fout,
+ const int fstride,
+ const kiss_fft_cfg st,
+ int m
+ )
+{
+ register int * restrict Fout2;
+ register int * restrict tw1 = (int*)st->twiddles;
+ register int i, j;
+ register int _inv = !st->inverse;
+
+ Fout2 = (int*)Fout + m;
+
+ for ( i=0,j=0 ; i<m ; ++i,j+=4,tw1+=fstride )
+ { register int tw_10, ff_10, f2_10;
+
+ ff_10 = ld32x(Fout, i);
+ f2_10 = ld32x(Fout2, i);
+ tw_10 = ld32(tw1);
+
+ if ( _inv )
+ { TM_SHR(f2_10, f2_10, 1);
+ TM_SHR(ff_10, ff_10, 1);
+ }
+
+ TM_MUL(tw_10, tw_10, f2_10);
+ TM_SUB(f2_10, ff_10, tw_10);
+ TM_ADD(ff_10, ff_10, tw_10);
+
+ st32d(j, Fout2, f2_10);
+ st32d(j, Fout, ff_10);
+ }
+}
+
+#define OVERRIDE_KFBFLY4
+static void kf_bfly4(
+ kiss_fft_cpx *Fout,
+ const int fstride,
+ const kiss_fft_cfg st,
+ const int m
+ )
+{
+ register int * restrict tw1;
+ register int * restrict tw2;
+ register int * restrict tw3;
+ register int * restrict Fout1;
+ register int * restrict Fout2;
+ register int * restrict Fout3;
+ register int i, j;
+ register int fstride2, fstride3;
+ register int _inv = !st->inverse;
+
+ tw3 = tw2 = tw1 = (int*)st->twiddles;
+ fstride2 = fstride << 1;
+ fstride3 = fstride * 3;
+
+ Fout1 = (int*)Fout + m;
+ Fout2 = (int*)Fout + (m << 1);
+ Fout3 = (int*)Fout + (m * 3);
+
+
+ for ( i=0,j=0 ; i<m ; ++i,j+=4,tw1+=fstride,tw2+=fstride2,tw3+=fstride3 )
+ { register int sc0, sc1, sc2, sc3, sc4, sc5;
+ register int ff0;
+
+ sc0 = ld32x(Fout1,i);
+ sc3 = ld32(tw1);
+ sc1 = ld32x(Fout2, i);
+ sc4 = ld32(tw2);
+ sc2 = ld32x(Fout3, i);
+ sc5 = ld32(tw3);
+ ff0 = ld32x(Fout,i);
+
+ if ( _inv )
+ {
+ TM_ADD(sc0, sc0, 0x00020002);
+ TM_ADD(sc1, sc1, 0x00020002);
+ TM_ADD(sc2, sc2, 0x00020002);
+ TM_ADD(ff0, ff0, 0x00020002);
+ TM_SHR(sc0, sc0, 2);
+ TM_SHR(sc1, sc1, 2);
+ TM_SHR(sc2, sc2, 2);
+ TM_SHR(ff0, ff0, 2);
+ }
+
+ TM_MUL(sc0, sc0, sc3);
+ TM_MUL(sc1, sc1, sc4);
+ TM_MUL(sc2, sc2, sc5);
+ TM_SUB(sc5, ff0, sc1);
+ TM_ADD(ff0, ff0, sc1);
+ TM_ADD(sc3, sc0, sc2);
+ TM_SUB(sc4, sc0, sc2);
+ TM_SUB(sc1, ff0, sc3);
+ TM_ADD(ff0, ff0, sc3);
+
+ st32d(j, Fout2, sc1);
+ st32d(j, Fout, ff0);
+
+ sc5 = funshift2(sc5, sc5);
+
+ if ( _inv )
+ { TM_ADD(ff0, sc5, sc4);
+ TM_SUB(sc1, sc5, sc4);
+ } else
+ { TM_ADD(sc1, sc5, sc4);
+ TM_SUB(ff0, sc5, sc4);
+ }
+
+ sc0 = funshift2(sc1, ff0);
+ sc2 = funshift2(ff0, sc1);
+
+ st32d(j, Fout1, sc0);
+ st32d(j, Fout3, sc2);
+ }
+}
+
+
+#define OVERRIDE_KFBFLY3
+static void kf_bfly3(
+ kiss_fft_cpx *Fout,
+ const int fstride,
+ const kiss_fft_cfg st,
+ int m
+ )
+{
+ register int * restrict tw1;
+ register int * restrict tw2;
+ register int * restrict Fout1;
+ register int * restrict Fout2;
+ register int epi;
+ register int i, j;
+ register int fstride2;
+ register int _inv = !st->inverse;
+
+ tw1 = tw2 = (int*)st->twiddles;
+ Fout1 = (int*)Fout + m;
+ Fout2 = (int*)Fout + (m << 1);
+ epi = tw1[fstride*m];
+ epi = pack16lsb(epi,epi);
+ fstride2 = fstride << 1;
+
+ for ( i=0,j=0 ; i<m ; ++i,j+=4,tw1+=fstride,tw2+=fstride2 )
+ { register int sc0, sc1, sc2, sc3, sc4, sc5;
+ register int ff0;
+
+ sc1 = ld32x(Fout1,i);
+ sc2 = ld32x(Fout2,i);
+ sc3 = ld32(tw1);
+ sc4 = ld32(tw2);
+ ff0 = ld32x(Fout,i);
+
+ if ( _inv )
+ {
+ TM_DIV(sc1, sc1, 3);
+ TM_DIV(sc2, sc2, 3);
+ TM_DIV(ff0, ff0, 3);
+ }
+
+ TM_MUL(sc1, sc1, sc3);
+ TM_MUL(sc2, sc2, sc4);
+ TM_ADD(sc3, sc1, sc2);
+ TM_SUB(sc0, sc1, sc2);
+ TM_SHR(sc4, sc3, 1);
+ TM_SUB(sc1, ff0, sc4);
+
+ sc0 = dspidualmul(sc0, epi);
+ sc0 = funshift2(sc0, sc0);
+
+ TM_ADD(ff0, ff0, sc3);
+ TM_ADD(sc4, sc1, sc0);
+ TM_SUB(sc5, sc1, sc0);
+
+ sc1 = funshift2(sc4, sc5);
+ sc2 = funshift2(sc5, sc4);
+ sc2 = funshift2(sc2, sc2);
+
+ st32d(j, Fout1, sc1);
+ st32d(j, Fout, ff0);
+ st32d(j, Fout2, sc2);
+ }
+}
+
+
+#define OVERRIDE_KFBFLY5
+static void kf_bfly5(
+ kiss_fft_cpx *Fout,
+ const int fstride,
+ const kiss_fft_cfg st,
+ int m
+ )
+{
+ register int * restrict tw1;
+ register int * restrict tw2;
+ register int * restrict tw3;
+ register int * restrict tw4;
+ register int * restrict Fout1;
+ register int * restrict Fout2;
+ register int * restrict Fout3;
+ register int * restrict Fout4;
+ register int fstride2, fstride3, fstride4;
+ register int i, j;
+ register int yab_msb, yab_lsb, yba_msb, yba_lsb;
+ register int _inv = !st->inverse;
+
+
+ Fout1=(int*)Fout+m;
+ Fout2=(int*)Fout+(m<<1);
+ Fout3=(int*)Fout+(3 *m);
+ Fout4=(int*)Fout+(m<<2);
+
+ tw1 = tw2 = tw3 = tw4 = (int*)st->twiddles;
+
+ i = tw1[fstride*m];
+ yab_lsb = tw1[fstride*(m<<1)];
+ yab_msb = pack16msb(i, yab_lsb);
+ yab_lsb = pack16lsb(i, yab_lsb);
+ yba_msb = funshift2(-sex16(yab_msb), yab_msb);
+ yba_lsb = funshift2(yab_lsb, yab_lsb);
+
+ fstride2 = fstride << 1;
+ fstride3 = fstride * 3;
+ fstride4 = fstride << 2;
+
+ for ( i=0,j=0 ; i<m ; ++i,j+=4,tw1+=fstride,tw2+=fstride2,tw3+=fstride3,tw4+=fstride4 )
+ { register int sc0, sc1, sc2, sc3, sc4, sc5, sc6;
+ register int sc7, sc8, sc9, sc10, sc11, sc12;
+ register int ff0, sc78_msb, sc78_lsb, sc90_msb, sc90_lsb;
+
+ sc0 = ld32x(Fout,i);
+ sc1 = ld32x(Fout1,i);
+ sc2 = ld32x(Fout2,i);
+ sc3 = ld32x(Fout3,i);
+ sc4 = ld32x(Fout4,i);
+ sc5 = ld32(tw1);
+ sc6 = ld32(tw2);
+ sc7 = ld32(tw3);
+ sc8 = ld32(tw4);
+
+ if ( _inv )
+ {
+ TM_DIV(sc0, sc0, 5);
+ TM_DIV(sc1, sc1, 5);
+ TM_DIV(sc2, sc2, 5);
+ TM_DIV(sc3, sc3, 5);
+ TM_DIV(sc4, sc4, 5);
+ }
+
+ ff0 = sc0;
+
+ TM_MUL(sc1, sc1, sc5);
+ TM_MUL(sc2, sc2, sc6);
+ TM_MUL(sc3, sc3, sc7);
+ TM_MUL(sc4, sc4, sc8);
+ TM_ADD(sc7, sc1, sc4);
+ TM_SUB(sc10,sc1, sc4);
+ TM_ADD(sc8, sc2, sc3);
+ TM_SUB(sc9, sc2, sc3);
+
+ TM_ADD(ff0, ff0, sc7);
+ TM_ADD(ff0, ff0, sc8);
+ st32d(j, Fout, ff0);
+
+ sc78_msb = pack16msb(sc7,sc8);
+ sc78_lsb = pack16lsb(sc7,sc8);
+ sc90_msb = pack16msb(sc10,sc9);
+ sc90_lsb = pack16lsb(sc10,sc9);
+
+ sc5 = pack16lsb( sround(ifir16(sc78_msb,yab_lsb)), sround(ifir16(sc78_lsb,yab_lsb)));
+ sc6 = pack16lsb(-sround(ifir16(sc90_lsb,yab_msb)), sround(ifir16(sc90_msb,yab_msb)));
+
+ TM_ADD(sc5, sc5, sc0);
+ TM_SUB(sc1, sc5, sc6);
+ TM_ADD(sc4, sc5, sc6);
+ st32d(j, Fout1, sc1);
+ st32d(j, Fout4, sc4);
+
+ sc11 = pack16lsb( sround(ifir16(sc78_msb,yba_lsb)), sround(ifir16(sc78_lsb,yba_lsb)));
+ sc12 = pack16lsb(-sround(ifir16(sc90_lsb,yba_msb)), sround(ifir16(sc90_msb,yba_msb)));
+
+ TM_ADD(sc11, sc11, sc0);
+ TM_ADD(sc2, sc11, sc12);
+ TM_SUB(sc3, sc11, sc12);
+ st32d(j, Fout2, sc2);
+ st32d(j, Fout3, sc3);
+
+ }
+}
+
+
+#define OVERRIDE_KF_BFLY_GENERIC
+static void kf_bfly_generic(
+ kiss_fft_cpx * restrict Fout,
+ const size_t fstride,
+ const kiss_fft_cfg st,
+ int m,
+ int p
+ )
+{
+ register int _inv = !st->inverse;
+ register int i, j, k, l;
+ register int * restrict twiddles = (int*)st->twiddles;
+ register int Norig = st->nfft;
+
+ CHECKBUF(scratchbuf,nscratchbuf,p);
+
+ for ( i=0; i<m; ++i )
+ { register int sc10;
+
+ for ( j=0,k=i ; j<p ; ++j,k+=m )
+ { register int f10;
+
+ f10 = ld32x(Fout,k);
+
+ if ( _inv )
+ { TM_DIV(f10, f10, p);
+ }
+
+ st32d(j<<2, scratchbuf, f10);
+ }
+
+ for ( j=0,k=i,sc10=ld32(scratchbuf) ; j<p ; ++j,k+=m )
+ {
+ register int twidx = 0;
+ register int f10;
+
+ for ( l=1,f10 = sc10 ; l<p ; ++l )
+ { register int tw, sc;
+
+ twidx += fstride * k;
+ if ( twidx>=Norig )
+ { twidx -= Norig;
+ }
+
+ sc = ld32x(scratchbuf,l);
+ tw = ld32x(twiddles,twidx);
+
+ TM_MUL(sc, sc, tw);
+ TM_ADD(f10, f10, sc);
+ }
+ st32d(k<<2, Fout, f10);
+ }
+ }
+}
+
+#else
+
+#define OVERRIDE_KFBFLY2
+static void kf_bfly2(
+ kiss_fft_cpx * Fout,
+ const size_t fstride,
+ const kiss_fft_cfg st,
+ int m
+ )
+{
+ register kiss_fft_cpx * restrict Fout2;
+ register kiss_fft_cpx * restrict tw1 = st->twiddles;
+
+ Fout2 = Fout + m;
+
+ do
+ {
+ register kiss_fft_cpx _fout2, _fout, t;
+
+ _fout2 = *Fout2;
+ _fout = *Fout;
+
+ C_MUL ( t, _fout2, *tw1);
+ C_SUB (_fout2, _fout, t);
+ C_ADD (_fout, _fout, t);
+
+ *Fout2 = _fout2;
+ *Fout = _fout;
+
+ tw1 += fstride;
+ ++Fout2;
+ ++Fout;
+
+ } while ( --m );
+}
+
+#define OVERRIDE_KFBFLY4
+static void kf_bfly4(
+ kiss_fft_cpx * Fout,
+ const int fstride,
+ const kiss_fft_cfg st,
+ int m
+ )
+{
+ register kiss_fft_cpx * restrict tw1,* restrict tw2,* restrict tw3;
+ register kiss_fft_cpx * restrict Fout1, * restrict Fout2, * restrict Fout3;
+ register int _inv = !st->inverse;
+
+ tw3 = tw2 = tw1 = st->twiddles;
+
+ Fout1 = Fout + m;
+ Fout2 = Fout + (m << 1);
+ Fout3 = Fout + (m * 3);
+
+ do {
+
+ register kiss_fft_cpx _fout;
+ register kiss_fft_cpx sc0, sc1, sc2, sc3, sc4, sc5;
+
+ _fout = *Fout;
+
+ C_MUL( sc0,*Fout1, *tw1);
+ C_MUL( sc1,*Fout2, *tw2);
+ C_MUL( sc2,*Fout3, *tw3);
+ C_SUB( sc5, _fout, sc1);
+ C_ADD( _fout, _fout, sc1);
+ C_ADD( sc3, sc0, sc2);
+ C_SUB( sc4, sc0, sc2);
+ C_SUB(*Fout2, _fout, sc3);
+ C_ADD( *Fout, _fout, sc3);
+
+ tw1 += fstride;
+ tw2 += (fstride << 1);
+ tw3 += (fstride * 3);
+
+ if ( _inv )
+ {
+ Fout1->r = sc5.r + sc4.i;
+ Fout1->i = sc5.i - sc4.r;
+ Fout3->r = sc5.r - sc4.i;
+ Fout3->i = sc5.i + sc4.r;
+ }
+ else
+ { Fout1->r = sc5.r - sc4.i;
+ Fout1->i = sc5.i + sc4.r;
+ Fout3->r = sc5.r + sc4.i;
+ Fout3->i = sc5.i - sc4.r;
+ }
+
+
+ ++Fout; ++Fout1; ++Fout2; ++Fout3;
+
+ } while(--m);
+}
+
+#define OVERRIDE_KFBFLY3
+static void kf_bfly3(
+ kiss_fft_cpx * Fout,
+ const int fstride,
+ const kiss_fft_cfg st,
+ int m
+ )
+{
+ register kiss_fft_cpx * restrict Fout1, * restrict Fout2;
+ register kiss_fft_cpx * restrict tw1,* restrict tw2;
+ register float epi;
+
+ tw1 = tw2 = st->twiddles;
+ epi = st->twiddles[fstride*m].i;
+ Fout1 = Fout + m;
+ Fout2 = Fout + (m << 1);
+
+ do {
+
+ register kiss_fft_cpx _fout;
+ register kiss_fft_cpx sc0, sc1, sc2, sc3;
+
+ _fout = *Fout;
+
+ C_MUL( sc1, *Fout1, *tw1);
+ C_MUL( sc2, *Fout2, *tw2);
+ C_ADD( sc3, sc1, sc2);
+ C_SUB( sc0, sc1, sc2);
+ tw1 += fstride;
+ tw2 += (fstride << 1);
+
+ sc1.r = _fout.r - HALF_OF(sc3.r);
+ sc1.i = _fout.i - HALF_OF(sc3.i);
+
+ C_MULBYSCALAR(sc0, epi);
+ C_ADD(*Fout, _fout, sc3);
+
+ Fout2->r = sc1.r + sc0.i;
+ Fout2->i = sc1.i - sc0.r;
+
+ Fout1->r = sc1.i - sc0.i;
+ Fout1->i = sc1.r + sc0.r;
+
+ ++Fout; ++Fout1; ++Fout2;
+
+ } while(--m);
+}
+
+#define OVERRIDE_KFBFLY5
+static void kf_bfly5(
+ kiss_fft_cpx * Fout,
+ const size_t fstride,
+ const kiss_fft_cfg st,
+ int m
+ )
+{
+ register kiss_fft_cpx * restrict Fout1,* restrict Fout2,* restrict Fout3,* restrict Fout4;
+ register int u;
+ register kiss_fft_cpx *tw;
+ register float yar, yai, ybr, ybi;
+
+ Fout1=Fout+m;
+ Fout2=Fout+(m<<1);
+ Fout3=Fout+(m*3);
+ Fout4=Fout+(m<<2);
+
+ tw = st->twiddles;
+ yar = tw[fstride*m].r;
+ yai = tw[fstride*m].i;
+ ybr = tw[fstride*2*m].r;
+ ybi = tw[fstride*2*m].i;
+
+ for ( u=0; u<m; ++u )
+ {
+ register kiss_fft_cpx sc0, sc1, sc2, sc3, sc4, sc5, sc6, sc7, sc8, sc9, sc10, sc11, sc12;
+
+ sc0 = *Fout;
+
+ C_MUL( sc1,*Fout1, tw[u*fstride]);
+ C_MUL( sc2,*Fout2, tw[2*u*fstride]);
+ C_MUL( sc3,*Fout3, tw[3*u*fstride]);
+ C_MUL( sc4,*Fout4, tw[4*u*fstride]);
+
+ C_ADD( sc7, sc1, sc4);
+ C_SUB( sc10, sc1, sc4);
+ C_ADD( sc8, sc2, sc3);
+ C_SUB( sc9, sc2, sc3);
+
+ Fout->r = sc0.r + sc7.r + sc8.r;
+ Fout->i = sc0.i + sc7.i + sc8.i;
+
+ sc5.r = sc0.r + S_MUL(sc7.r,yar) + S_MUL(sc8.r,ybr);
+ sc5.i = sc0.i + S_MUL(sc7.i,yar) + S_MUL(sc8.i,ybr);
+
+ sc6.r = S_MUL(sc10.i,yai) + S_MUL(sc9.i,ybi);
+ sc6.i = -S_MUL(sc10.r,yai) - S_MUL(sc9.r,ybi);
+
+ C_SUB(*Fout1,sc5,sc6);
+ C_ADD(*Fout4,sc5,sc6);
+
+ sc11.r = sc0.r + S_MUL(sc7.r,ybr) + S_MUL(sc8.r,yar);
+ sc11.i = sc0.i + S_MUL(sc7.i,ybr) + S_MUL(sc8.i,yar);
+ sc12.r = - S_MUL(sc10.i,ybi) + S_MUL(sc9.i,yai);
+ sc12.i = S_MUL(sc10.r,ybi) - S_MUL(sc9.r,yai);
+ C_ADD(*Fout2,sc11,sc12);
+ C_SUB(*Fout3,sc11,sc12);
+
+ ++Fout1; ++Fout2; ++Fout3; ++Fout4;
+ }
+}
+
+
+#endif
+
+#endif
diff --git a/tmv/kiss_fftr_tm.h b/tmv/kiss_fftr_tm.h new file mode 100644 index 0000000..5b2b2cf --- /dev/null +++ b/tmv/kiss_fftr_tm.h @@ -0,0 +1,235 @@ +/* Copyright (C) 2007 Hong Zhiqian */
+/**
+ @file kiss_fftr_tm.h
+ @author Hong Zhiqian
+ @brief Various compatibility routines for Speex (TriMedia version)
+*/
+/*
+ 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 the Xiph.org Foundation 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 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.
+*/
+#include "_kiss_fft_guts_tm.h"
+
+#ifdef TM_ASM
+
+#include "profile_tm.h"
+
+#ifdef FIXED_POINT
+
+#define TM_NDIV(res,c,frac) \
+ { register int c1, c0; \
+ \
+ c1 = -asri(16,(c)); \
+ c0 = sex16((c)); \
+ (res) = pack16lsb(sround(c1 * (32767/(frac))), sround(c0 * (32767/(frac))));\
+ }
+
+
+#define OVERRIDE_KISS_FFTR
+void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar * restrict timedata, kiss_fft_cpx * restrict freqdata)
+{
+ register int ncfft, ncfft2, k;
+ register int * restrict tmpbuf;
+ register int * restrict twiddles;
+
+ ncfft = st->substate->nfft;
+ ncfft2 = ncfft >> 1;
+ tmpbuf = (int*)st->tmpbuf;
+ twiddles = (int*)st->super_twiddles;
+
+ TMDEBUG_ALIGNMEM(timedata);
+ TMDEBUG_ALIGNMEM(freqdata);
+ TMDEBUG_ALIGNMEM(tmpbuf);
+ TMDEBUG_ALIGNMEM(twiddles);
+
+ kiss_fft(st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf);
+
+ {
+ register int tdcr, tdci;
+ tdcr = sround(st->tmpbuf[0].r * (32767/2));
+ tdci = sround(st->tmpbuf[0].i * (32767/2));
+
+ freqdata[0].r = tdcr + tdci;
+ freqdata[ncfft].r = tdcr - tdci;
+ freqdata[ncfft].i = freqdata[0].i = 0;
+ }
+
+ for ( k=1 ; k <= ncfft2 ; ++k )
+ {
+ register int fpk, fpnk, i, tw, f1k, f2k;
+ register int fq1, fq2;
+
+ i = ncfft-k;
+
+ fpk = ld32x(tmpbuf,k);
+ tw = ld32x(twiddles,k);
+ fpnk = ld32x(tmpbuf,i);
+
+ TM_DIV(fpk, fpk, 2);
+ TM_NDIV(fpnk,fpnk,2);
+
+ TM_ADD( f1k, fpk , fpnk );
+ TM_SUB( f2k, fpk , fpnk );
+ TM_MUL( tw , f2k, tw );
+ TM_ADD( fq1, f1k, tw );
+ TM_SHR( fq1, fq1, 1 );
+ TM_SUB( fq2, f1k, tw );
+ TM_NEGMSB( fq2, fq2 );
+ TM_SHR( fq2, fq2, 1 );
+
+
+ st32d( k<<2, freqdata, fq1 );
+ st32d( i<<2, freqdata, fq2 );
+ }
+}
+
+#define OVERRIDE_KISS_FFTRI
+void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx * restrict freqdata,kiss_fft_scalar * restrict timedata)
+{
+ register int k, ncfft, ncfft2;
+ register int * restrict tmpbuf;
+ register int * restrict twiddles;
+
+ ncfft = st->substate->nfft;
+ ncfft2 = ncfft >> 1;
+ tmpbuf = (int*)st->tmpbuf;
+ twiddles = (int*)st->super_twiddles;
+
+ TMDEBUG_ALIGNMEM(freqdata);
+ TMDEBUG_ALIGNMEM(timedata);
+ TMDEBUG_ALIGNMEM(tmpbuf);
+ TMDEBUG_ALIGNMEM(twiddles);
+
+ {
+ register int fqr, fqnr;
+
+ fqr = freqdata[0].r;
+ fqnr = freqdata[ncfft].r;
+
+ st->tmpbuf[0].r = fqr + fqnr;
+ st->tmpbuf[0].i = fqr - fqnr;
+ }
+
+ for ( k=1 ; k <= ncfft2 ; ++k )
+ {
+ register int fk, fnkc, i, tw, fek, fok, tmp;
+ register int tbk, tbn;
+
+ i = ncfft-k;
+
+ fk = ld32x(freqdata,k);
+ tw = ld32x(twiddles,k);
+ fnkc = pack16lsb(-freqdata[i].i, freqdata[i].r);
+
+ TM_ADD (fek, fk, fnkc);
+ TM_SUB (tmp, fk, fnkc);
+ TM_MUL (fok, tmp, tw );
+ TM_ADD (tbk, fek, fok);
+ TM_SUB (tbn, fek, fok);
+ TM_NEGMSB(tbn, tbn);
+
+ st32d(k<<2, tmpbuf, tbk);
+ st32d(i<<2, tmpbuf, tbn);
+ }
+ kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata);
+}
+
+#else
+
+#define OVERRIDE_KISS_FFTR
+void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar * restrict timedata,kiss_fft_cpx * restrict freqdata)
+{
+ register kiss_fft_cpx fpnk, fpk, f1k, f2k, twk;
+ register int k, ncfft;
+ register kiss_fft_cpx * restrict tmpbuf, * restrict tw;
+ register float tdcr, tdci;
+
+ ncfft = st->substate->nfft;
+ tmpbuf= st->tmpbuf;
+ tw = st->super_twiddles;
+
+ kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, tmpbuf );
+
+ tdcr = tmpbuf[0].r;
+ tdci = tmpbuf[0].i;
+
+ freqdata[0].r = tdcr + tdci;
+ freqdata[ncfft].r = tdcr - tdci;
+ freqdata[ncfft].i = freqdata[0].i = 0;
+
+ for ( k=1;k <= ncfft/2 ; ++k )
+ {
+ fpk = tmpbuf[k];
+ fpnk.r = tmpbuf[ncfft-k].r;
+ fpnk.i = -tmpbuf[ncfft-k].i;
+
+ C_ADD( f1k, fpk , fpnk );
+ C_SUB( f2k, fpk , fpnk );
+ C_MUL( twk, f2k , tw[k]);
+
+ freqdata[k].r = HALF_OF(f1k.r + twk.r);
+ freqdata[k].i = HALF_OF(f1k.i + twk.i);
+ freqdata[ncfft-k].r = HALF_OF(f1k.r - twk.r);
+ freqdata[ncfft-k].i = HALF_OF(twk.i - f1k.i);
+ }
+}
+
+#define OVERRIDE_KISS_FFTRI
+void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx * restrict freqdata,kiss_fft_scalar * restrict timedata)
+{
+ register int k, ncfft;
+ register kiss_fft_cpx * restrict tmpbuf, * restrict tw;
+
+
+ ncfft = st->substate->nfft;
+ tmpbuf= st->tmpbuf;
+ tw = st->super_twiddles;
+
+ tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r;
+ tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r;
+
+ for (k = 1; k <= ncfft / 2; ++k)
+ {
+ register kiss_fft_cpx fk, fnkc, fek, fok, tmp;
+ fk = freqdata[k];
+ fnkc.r = freqdata[ncfft - k].r;
+ fnkc.i = -freqdata[ncfft - k].i;
+
+ C_ADD (fek, fk, fnkc);
+ C_SUB (tmp, fk, fnkc);
+ C_MUL (fok,tmp,tw[k]);
+ C_ADD (tmpbuf[k],fek, fok);
+ C_SUB (tmp, fek, fok);
+ tmpbuf[ncfft - k].r = tmp.r;
+ tmpbuf[ncfft - k].i = -tmp.i;
+ }
+ kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata);
+}
+
+#endif
+#endif
+
diff --git a/tmv/lpc_tm.h b/tmv/lpc_tm.h new file mode 100644 index 0000000..f5e9bcd --- /dev/null +++ b/tmv/lpc_tm.h @@ -0,0 +1,150 @@ +/* Copyright (C) 2007 Hong Zhiqian */
+/**
+ @file lpc_tm.h
+ @author Hong Zhiqian
+ @brief Various compatibility routines for Speex (TriMedia version)
+*/
+/*
+ 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 the Xiph.org Foundation 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 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.
+*/
+
+#include <ops/custom_defs.h>
+#include "profile_tm.h"
+
+#ifdef FIXED_POINT
+
+#define OVERRIDE_SPEEX_AUTOCORR
+void _spx_autocorr(const Int16 *x, Int16 *ac, int lag, int n)
+{
+ register int i, j;
+ register int shift, ac_shift;
+ register int n_2;
+ register int ac0;
+
+ TMDEBUG_ALIGNMEM(x);
+ TMDEBUG_ALIGNMEM(ac);
+
+ _SPX_AUTOCORR_START();
+
+ n_2 = n >> 1;
+ ac0 = n + 1;
+
+#if (TM_UNROLL && TM_UNROLL__SPXAUTOCORR)
+#pragma TCS_unroll=5
+#pragma TCS_unrollexact=1
+#endif
+ for ( j=0 ; j<n_2 ; j+=4 )
+ { register int x10, x32, x54, x76;
+
+ x10 = ld32x(x,j);
+ x32 = ld32x(x,j+1);
+ x54 = ld32x(x,j+2);
+ x76 = ld32x(x,j+3);
+
+ ac0 += ifir16(x10, x10) >> 8;
+ ac0 += ifir16(x32, x32) >> 8;
+ ac0 += ifir16(x54, x54) >> 8;
+ ac0 += ifir16(x76, x76) >> 8;
+ }
+#if (TM_UNROLL && TM_UNROLL__SPXAUTOCORR)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ shift = 8;
+ while (shift && ac0<0x40000000)
+ { shift--;
+ ac0 <<= 1;
+ }
+
+ ac_shift = 18;
+ while (ac_shift && ac0<0x40000000)
+ { ac_shift--;
+ ac0 <<= 1;
+ }
+
+ if ( shift == 0 )
+ {
+ for ( i=0 ; i<lag ; ++i )
+ {
+ register int acc0, acc1, acc2;
+ register int k, l, m;
+ register int x10, x32, y10, y32;
+
+ acc2 = acc1 = acc0 = 0;
+
+ for ( j=i ; j<16 ; ++j )
+ { acc0 += (x[j] * x[j-i]);
+ }
+
+ for ( k=16,l=8,m=16-i ; k<n ; k+=4,l+=2,m+=4 )
+ {
+ x10 = ld32x(x,l);
+ y10 = pack16lsb(x[m+1],x[m]);
+ x32 = ld32x(x,l+1);
+ y32 = pack16lsb(x[m+3],x[m+2]);
+
+ acc1 += ifir16(x10,y10);
+ acc2 += ifir16(x32,y32);
+ }
+
+ ac[i] = (acc0 + acc1 + acc2) >> ac_shift;
+ }
+ } else
+ {
+ for ( i=0 ; i<lag ; ++i )
+ {
+ register int acc0, acc1, acc2;
+ register int k, l, m;
+ register int x10, x32, y10, y32;
+
+ acc2 = acc1 = acc0 = 0;
+
+ for ( j=i ; j<16 ; ++j )
+ { acc0 += (x[j] * x[j-i]) >> shift;
+ }
+
+ for ( k=16,l=8,m=16-i ; k<n ; k+=4,l+=2,m+=4 )
+ {
+ x10 = ld32x(x,l);
+ y10 = pack16lsb(x[m+1],x[m]);
+ x32 = ld32x(x,l+1);
+ y32 = pack16lsb(x[m+3],x[m+2]);
+
+ acc1 += ifir16(x10,y10) >> shift;
+ acc2 += ifir16(x32,y32) >> shift;
+ }
+
+ ac[i] = (acc0 + acc1 + acc2) >> ac_shift;
+ }
+ }
+
+ _SPX_AUTOCORR_STOP();
+}
+
+#endif
diff --git a/tmv/lsp_tm.h b/tmv/lsp_tm.h new file mode 100644 index 0000000..acb0d91 --- /dev/null +++ b/tmv/lsp_tm.h @@ -0,0 +1,310 @@ +/* Copyright (C) 2007 Hong Zhiqian */
+/**
+ @file lsp_tm.h
+ @author Hong Zhiqian
+ @brief Various compatibility routines for Speex (TriMedia version)
+*/
+/*
+ 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 the Xiph.org Foundation 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 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.
+*/
+
+#include <ops/custom_defs.h>
+#include "profile_tm.h"
+
+
+#ifdef FIXED_POINT
+
+#define OVERRIDE_LSP_INTERPOLATE
+void lsp_interpolate(Int16 *old_lsp, Int16 *new_lsp, Int16 *interp_lsp, int len, int subframe, int nb_subframes)
+{
+ register int tmp = DIV32_16(SHL32(EXTEND32(1 + subframe),14),nb_subframes);
+ register int tmp2 = 16384-tmp;
+ register int in_0, in_1, factor, out_1, out_2, olsp, nlsp, ilsp;
+ register int i;
+
+ TMDEBUG_ALIGNMEM(old_lsp);
+ TMDEBUG_ALIGNMEM(new_lsp);
+ TMDEBUG_ALIGNMEM(interp_lsp);
+
+ LSPINTERPOLATE_START();
+
+ factor = pack16lsb(tmp,tmp2);
+
+ len >>= 1;
+ for ( i=0 ; i<len ; ++i )
+ {
+ olsp = ld32x(old_lsp,i); // olsp[i+1],olsp[i]
+ nlsp = ld32x(new_lsp,i); // nlsp[i+1],nlsp[i]
+
+ in_0 = pack16lsb(nlsp,olsp);
+ in_1 = pack16msb(nlsp,olsp);
+
+ out_1 = 8192 + ifir16(in_0,factor);
+ out_2 = 8192 + ifir16(in_1,factor);
+
+ ilsp = pack16lsb(out_2 >> 14, out_1 >> 14);
+ st32d(i << 2, interp_lsp, ilsp);
+
+ }
+
+ LSPINTERPOLATE_STOP();
+}
+
+
+#define OVERRIDE_CHEB_POLY_EVA
+static inline Int32 cheb_poly_eva(Int16 *coef, Int16 x, int m, char *stack)
+{
+ register int c10, c32, c54;
+ register int sum, b0, f0, f1, f2, f3;
+ register int xx, f32, f10;
+
+ CHEBPOLYEVA_START();
+
+ xx = sex16(x);
+ b0 = iclipi(xx,16383);
+
+#if 0
+ c10 = ld32(coef);
+ c32 = ld32x(coef,1);
+ c54 = ld32x(coef,2);
+#else
+ c10 = pack16lsb(coef[1],coef[0]);
+ c32 = pack16lsb(coef[3],coef[2]);
+ c54 = pack16lsb(coef[5],coef[4]);
+#endif
+
+ f0 = ((xx * b0) >> 13) - 16384;
+ f1 = ((xx * f0) >> 13) - b0;
+ f2 = ((xx * f1) >> 13) - f0;
+
+ if ( m == 4 )
+ { sum = sex16(c54);
+ f32 = pack16lsb(xx,f0);
+ f10 = pack16lsb(f1,f2);
+
+ } else
+ { sum = asri(16,c54);
+ sum += ((sex16(c54) * xx) + 8192) >> 14;
+
+ f3 = ((xx * f2) >> 13) - f1;
+ f32 = pack16lsb(f0,f1);
+ f10 = pack16lsb(f2,f3);
+ }
+
+ sum += (ifir16(c32,f32) + 8192) >> 14;
+ sum += (ifir16(c10,f10) + 8192) >> 14;
+
+#ifndef REMARK_ON
+ (void)stack;
+#endif
+
+ CHEBPOLYEVA_STOP();
+ return sum;
+}
+
+
+#define OVERRIDE_LSP_ENFORCE_MARGIN
+void lsp_enforce_margin(Int16 *lsp, int len, Int16 margin)
+{
+ register int i;
+ register int m = margin;
+ register int m2 = 25736-margin;
+ register int lsp0, lsp1, lsp2;
+
+ TMDEBUG_ALIGNMEM(lsp);
+
+ LSPENFORCEMARGIN_START();
+
+ lsp0 = ld32(lsp);
+ lsp1 = asri(16,lsp0);
+ lsp0 = sex16(lsp0);
+ lsp2 = lsp[len-1];
+
+ if ( lsp0 < m )
+ { lsp0 = m;
+ lsp[0] = m;
+ }
+
+ if ( lsp2 > m2 )
+ { lsp2 = m2;
+ lsp[len-1] = m2;
+ }
+
+ for ( i=1 ; i<len-1 ; ++i )
+ {
+ lsp0 += m;
+ lsp2 = lsp[i+1];
+ m2 = lsp2 - m;
+
+ if ( lsp1 < lsp0 )
+ { lsp1 = lsp0;
+ lsp[i] = lsp0;
+ }
+
+ if ( lsp1 > m2 )
+ { lsp1 = (lsp1 >> 1) + (m2 >> 1);
+ lsp[i] = lsp1;
+ }
+
+ lsp0 = lsp1;
+ lsp1 = lsp2;
+ }
+
+ LSPENFORCEMARGIN_STOP();
+}
+
+
+#define OVERRIDE_LSP_TO_LPC
+void lsp_to_lpc(Int16 *freq, Int16 *ak,int lpcrdr, char *stack)
+{
+ VARDECL(Int16 *freqn);
+ VARDECL(int **xp);
+ VARDECL(int *xpmem);
+ VARDECL(int **xq);
+ VARDECL(int *xqmem);
+
+ register int i, j, k;
+ register int xout1,xout2,xin;
+ register int m;
+
+ LSPTOLPC_START();
+
+ m = lpcrdr>>1;
+
+ /*
+
+ Reconstruct P(z) and Q(z) by cascading second order polynomials
+ in form 1 - 2cos(w)z(-1) + z(-2), where w is the LSP frequency.
+ In the time domain this is:
+
+ y(n) = x(n) - 2cos(w)x(n-1) + x(n-2)
+
+ This is what the ALLOCS below are trying to do:
+
+ int xp[m+1][lpcrdr+1+2]; // P matrix in QIMP
+ int xq[m+1][lpcrdr+1+2]; // Q matrix in QIMP
+
+ These matrices store the output of each stage on each row. The
+ final (m-th) row has the output of the final (m-th) cascaded
+ 2nd order filter. The first row is the impulse input to the
+ system (not written as it is known).
+
+ The version below takes advantage of the fact that a lot of the
+ outputs are zero or known, for example if we put an inpulse
+ into the first section the "clock" it 10 times only the first 3
+ outputs samples are non-zero (it's an FIR filter).
+ */
+
+ ALLOC(xp, (m+1), int*);
+ ALLOC(xpmem, (m+1)*(lpcrdr+1+2), int);
+
+ ALLOC(xq, (m+1), int*);
+ ALLOC(xqmem, (m+1)*(lpcrdr+1+2), int);
+
+ for ( i=0; i<=m; i++ )
+ { xp[i] = xpmem + i*(lpcrdr+1+2);
+ xq[i] = xqmem + i*(lpcrdr+1+2);
+ }
+
+ /* work out 2cos terms in Q14 */
+
+ ALLOC(freqn, lpcrdr, Int16);
+ for ( j=0,k=0 ; j<m ; ++j,k+=2 )
+ { register int f;
+
+ f = ld32x(freq,j);
+
+ freqn[k] = ANGLE2X(sex16(f));
+ freqn[k+1] = ANGLE2X(asri(16,f));
+ }
+
+ #define QIMP 21 /* scaling for impulse */
+ xin = SHL32(EXTEND32(1), (QIMP-1)); /* 0.5 in QIMP format */
+
+ /* first col and last non-zero values of each row are trivial */
+
+ for(i=0;i<=m;i++)
+ { xp[i][1] = 0;
+ xp[i][2] = xin;
+ xp[i][2+2*i] = xin;
+ xq[i][1] = 0;
+ xq[i][2] = xin;
+ xq[i][2+2*i] = xin;
+ }
+
+ /* 2nd row (first output row) is trivial */
+
+ xp[1][3] = -MULT16_32_Q14(freqn[0],xp[0][2]);
+ xq[1][3] = -MULT16_32_Q14(freqn[1],xq[0][2]);
+
+ xout1 = xout2 = 0;
+
+ for( i=1 ; i<m ; ++i)
+ { register int f, f0, f1, m0, m1;
+
+ k = 2*(i+1)-1;
+ f = ld32x(freqn,i);
+ f0 = sex16(f);
+ f1 = asri(16,f);
+
+ for( j=1 ; j<k ; ++j)
+ { register int _m0, _m1;
+
+ _m0 = MULT16_32_Q14(f0,xp[i][j+1]);
+ xp[i+1][j+2] = ADD32(SUB32(xp[i][j+2], _m0), xp[i][j]);
+
+ _m1 = MULT16_32_Q14(f1,xq[i][j+1]);
+ xq[i+1][j+2] = ADD32(SUB32(xq[i][j+2], _m1), xq[i][j]);
+ }
+
+
+ m0 = MULT16_32_Q14(f0,xp[i][j+1]);
+ xp[i+1][j+2] = SUB32(xp[i][j], m0);
+ m1 = MULT16_32_Q14(f1,xq[i][j+1]);
+ xq[i+1][j+2] = SUB32(xq[i][j], m1);
+ }
+
+
+ for( i=0,j=3 ; i<lpcrdr ; ++j,++i )
+ { register int _a0, _xp0, _xq0;
+
+ _xp0 = xp[m][j];
+ _xq0 = xq[m][j];
+
+ _a0 = PSHR32(_xp0 + xout1 + _xq0 - xout2, QIMP-13);
+ xout1 = _xp0;
+ xout2 = _xq0;
+
+ ak[i] = iclipi(_a0,32767);
+ }
+
+ LSPTOLPC_STOP();
+}
+
+
+#endif
diff --git a/tmv/ltp_tm.h b/tmv/ltp_tm.h new file mode 100644 index 0000000..eccd701 --- /dev/null +++ b/tmv/ltp_tm.h @@ -0,0 +1,479 @@ +/* Copyright (C) 2007 Hong Zhiqian */
+/**
+ @file ltp_tm.h
+ @author Hong Zhiqian
+ @brief Various compatibility routines for Speex (TriMedia version)
+*/
+/*
+ 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 the Xiph.org Foundation 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 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.
+*/
+#include <ops/custom_defs.h>
+#include "profile_tm.h"
+
+#ifdef FIXED_POINT
+
+#define OVERRIDE_INNER_PROD
+Int32 inner_prod(const Int16 * restrict x, const Int16 * restrict y, int len)
+{
+ register int sum = 0;
+
+ INNERPROD_START();
+
+ if ( (int)x & 0x03 == 0 && (int)y & 0x03 == 0 )
+ {
+ register int i;
+
+ len >>= 1;
+ for ( i=0 ; i<len ; i+=4 )
+ {
+ register int x0, x1, y0, y1, x2, x3, y2, y3;
+
+ x0 = ld32x(x,i);
+ y0 = ld32x(x,i);
+ x1 = ld32x(x,i+1);
+ y1 = ld32x(y,i+1);
+ sum += (ifir16(x0,y0) + ifir16(x1,y1)) >> 6;
+
+ x2 = ld32x(x,i+2);
+ y2 = ld32x(x,i+2);
+ x3 = ld32x(x,i+3);
+ y3 = ld32x(x,i+3);
+ sum += (ifir16(x2,y2) + ifir16(x3,y3)) >> 6;
+
+ }
+ } else
+ {
+ len >>= 3;
+ while( len-- )
+ {
+ register int x0, x1, x2, x3, y0, y1, y2, y3;
+
+ x0 = pack16lsb(x[0],x[1]);
+ y0 = pack16lsb(y[0],y[1]);
+ x1 = pack16lsb(x[2],x[3]);
+ y1 = pack16lsb(y[2],y[3]);
+ sum += (ifir16(x0,y0) + ifir16(x1,y1)) >> 6;
+
+ x2 = pack16lsb(x[4],x[5]);
+ y2 = pack16lsb(y[4],y[5]);
+ x3 = pack16lsb(x[6],x[7]);
+ y3 = pack16lsb(y[6],y[7]);
+ sum += (ifir16(x2,y2) + ifir16(x3,y3)) >> 6;
+
+ x += 8;
+ y += 8;
+ }
+ }
+
+ INNERPROD_STOP();
+ return sum;
+}
+
+#define OVERRIDE_PITCH_XCORR
+void pitch_xcorr(const Int16 *_x, const Int16 *_y, Int32 *corr, int len, int nb_pitch, char *stack)
+{
+ register int sum_1, sum_2, sum_3, sum_4;
+ register int y10, y32, y54, y76, y21, y43, y65;
+ register int x10, x32;
+ register int i, j, k, limit;
+
+ TMDEBUG_ALIGNMEM(_x);
+ TMDEBUG_ALIGNMEM(_y);
+
+ PITCHXCORR_START();
+
+ limit = nb_pitch >> 1;
+ len >>= 1;
+
+ for (i=0 ; i<limit ; i+=2 )
+ {
+ sum_1 = sum_2 = sum_3 = sum_4 = 0;
+
+ y10 = ld32x(_y,i);
+ y32 = ld32x(_y,i+1);
+
+ for ( j=0 ; j<len ; j+=2 )
+ {
+ x10 = ld32x(_x,j);
+ x32 = ld32x(_x,j+1);
+ y54 = ld32x(_y,i+j+2);
+ y76 = ld32x(_y,i+j+3);
+
+ sum_1 += (ifir16(x10,y10) + ifir16(x32,y32)) >> 6;
+ sum_3 += (ifir16(x10,y32) + ifir16(x32,y54)) >> 6;
+
+ y21 = funshift2(y32,y10);
+ y43 = funshift2(y54,y32);
+ y65 = funshift2(y76,y54);
+
+ sum_2 += (ifir16(x10,y21) + ifir16(x32,y43)) >> 6;
+ sum_4 += (ifir16(x10,y43) + ifir16(x32,y65)) >> 6;
+
+ y10 = y54;
+ y32 = y76;
+
+ }
+
+ k = i << 1;
+ corr[nb_pitch-1-k]=sum_1;
+ corr[nb_pitch-2-k]=sum_2;
+ corr[nb_pitch-3-k]=sum_3;
+ corr[nb_pitch-4-k]=sum_4;
+ }
+
+#ifndef REMARK_ON
+ (void)stack;
+#endif
+
+ PITCHXCORR_STOP();
+}
+
+#ifndef ttisim
+#define OVERRIDE_PITCH_GAIN_SEARCH_3TAP_VQ
+static int pitch_gain_search_3tap_vq
+(
+ const signed char *gain_cdbk,
+ int gain_cdbk_size,
+ Int16 *C16,
+ Int16 max_gain
+)
+{
+ register int pp = 0x00400040, p=64;
+ register int g10, g2, g20, g21, g02, g22, g01;
+ register int cb0, cb1, cb2, cb5432;
+ register int C10, C32, C54, C76, C98, C83, C2;
+ register int acc0, acc1, acc2, acc3, sum, gsum, bsum=-VERY_LARGE32;
+ register int i, best_cdbk=0;
+ register Int16 tmp;
+
+ TMDEBUG_ALIGNMEM(C16);
+ TMDEBUG_ALIGNMEM(gain_cdbk+2);
+
+ PITCHGAINSEARCH3TAPVQ_START();
+
+ tmp = ild16(gain_cdbk);
+ C98 = ld32x(C16,4);
+ C32 = ld32x(C16,1);
+ C10 = ld32(C16);
+ C54 = ld32x(C16,2);
+ C76 = ld32x(C16,3);
+
+ cb0 = sex8(tmp);
+ cb1 = sex8(tmp>>8);
+ C83 = funshift2(C98,C32);
+ C2 = sex16(C32);
+ gain_cdbk += 2;
+
+
+#if (TM_UNROLL && TM_UNROLL_PITCHGAINSEARCH3TAPVQ > 0)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<gain_cdbk_size ; ++i )
+ {
+ cb5432 = ld32x(gain_cdbk,i);
+ cb2 = sex8(cb5432);
+ gsum = sex8(cb5432>>8);
+ sum = 0;
+
+ g10 = pack16lsb(cb1 + 32, cb0 + 32);
+ g2 = cb2 + 32;
+ g02 = pack16lsb(g10, g2);
+ acc0 = dspidualmul(g10,pp);
+ sum += ifir16(acc0,C10);
+ sum += p * g2 * C2;
+
+ g22 = pack16lsb(g02, g02);
+ g01 = funshift2(g10, g10);
+
+ acc1 = dspidualmul(g22, g01);
+ sum -= ifir16(acc1, C54);
+ acc2 = dspidualmul(g10, g10);
+ sum -= ifir16(acc2, C76);
+
+ g20 = pack16lsb(g2, g10);
+ g21 = funshift2(g2, g10);
+ acc3 = dspidualmul(g20, g21);
+ sum -= ifir16(acc3, C83);
+
+
+ if ( sum>bsum && gsum<=max_gain )
+ { bsum = sum;
+ best_cdbk=i;
+ }
+
+ cb0 = sex8(cb5432 >> 16);
+ cb1 = asri(24,cb5432);
+ }
+#if (TM_UNROLL && TM_UNROLL_PITCHGAINSEARCH3TAPVQ > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ PITCHGAINSEARCH3TAPVQ_STOP();
+ return best_cdbk;
+}
+#endif
+
+#define OVERRIDE_COMPUTE_PITCH_ERROR
+#ifndef OVERRIDE_PITCH_GAIN_SEARCH_3TAP_VQ
+inline Int32 compute_pitch_error(Int16 *C, Int16 *g, Int16 pitch_control)
+{
+ register int c10, c32, c54, c76, c98, c83;
+ register int g10, g32, g02, g22, g01, g21, g20;
+ register int pp, tmp0, tmp1, tmp2, tmp3;
+ register int sum = 0;
+
+
+ COMPUTEPITCHERROR_START();
+
+ g10 = ld32(g);
+ g32 = ld32x(g,1);
+ pp = pack16lsb(pitch_control,pitch_control);
+ c10 = ld32(C);
+ c32 = ld32x(C,1);
+ g02 = pack16lsb(g10,g32);
+ g22 = pack16lsb(g32,g32);
+ g01 = funshift2(g10,g10);
+ tmp0 = dspidualmul(g10,pp);
+ sum += ifir16(tmp0, c10);
+ sum += pitch_control * sex16(g32) * sex16(c32);
+ c54 = ld32x(C,2);
+ c76 = ld32x(C,3);
+ c98 = ld32x(C,4);
+ tmp1 = dspidualmul(g22,g01);
+ sum -= ifir16(tmp1, c54);
+ tmp2 = dspidualmul(g10,g10);
+ sum -= ifir16(tmp2,c76);
+ c83 = funshift2(c98,c32);
+ g20 = funshift2(g02,g02);
+ g21 = funshift2(g02,g10);
+ tmp3 = dspidualmul(g20,g21);
+ sum -= ifir16(tmp3,c83);
+
+ COMPUTEPITCHERROR_STOP();
+ return sum;
+}
+#endif
+
+#define OVERRIDE_OPEN_LOOP_NBEST_PITCH
+void open_loop_nbest_pitch(Int16 *sw, int start, int end, int len, int *pitch, Int16 *gain, int N, char *stack)
+{
+ VARDECL(int *best_score);
+ VARDECL(int *best_ener);
+ VARDECL(Int32 *corr);
+ VARDECL(Int16 *corr16);
+ VARDECL(Int16 *ener16);
+ register int i, j, k, l, N4, N2;
+ register int _sw10, _sw32, _s0, _s2, limit;
+ register int *energy;
+ register int cshift=0, eshift=0;
+ register int scaledown = 0;
+ register int e0, _energy0;
+
+ ALLOC(corr16, end-start+1, Int16);
+ ALLOC(ener16, end-start+1, Int16);
+ ALLOC(corr, end-start+1, Int32);
+ ALLOC(best_score, N, int);
+ ALLOC(best_ener, N, int);
+ energy = corr;
+ N4 = N << 2;
+ N2 = N >> 1;
+
+ TMDEBUG_ALIGNMEM(sw);
+ TMDEBUG_ALIGNMEM(pitch);
+ TMDEBUG_ALIGNMEM(gain);
+ TMDEBUG_ALIGNMEM(best_score);
+ TMDEBUG_ALIGNMEM(best_ener);
+ TMDEBUG_ALIGNMEM(corr16);
+ TMDEBUG_ALIGNMEM(ener16);
+
+ OPENLOOPNBESTPITCH_START();
+
+ for ( i=0 ; i<N4 ; i+=4 )
+ { st32d(i,best_score,-1);
+ st32d(i,best_ener,0);
+ st32d(i,pitch,start);
+ }
+
+ for ( j=asri(1,-end) ; j<N2 ; ++j )
+ { register int _sw10;
+
+ _sw10 = ld32x(sw,j);
+ _sw10 = dspidualabs(_sw10);
+
+ if ( _sw10 & 0xC000C000 )
+ { scaledown = 1;
+ break;
+ }
+ }
+
+ if ( scaledown )
+ {
+ for ( j=asri(1,-end),k=asli(1,-end) ; j<N2 ; ++j,k+=4 )
+ { register int _sw10;
+
+ _sw10 = ld32x(sw,j);
+ _sw10 = dualasr(_sw10,1);
+ st32d(k, sw, _sw10);
+ }
+ }
+
+ energy[0] = _energy0 = inner_prod(sw-start, sw-start, len);
+ e0 = inner_prod(sw, sw, len);
+
+ j=asri(1,-start-1); k=j+20;
+ _sw10 = ld32x(sw,j);
+ _sw32 = ld32x(sw,k);
+ limit = end-1-start;
+
+ for ( i=1,--j,--k ; i<limit ; i+=2,--j,--k )
+ { register int _energy1, __sw10, __sw32, __s0, __s2;
+
+ _s0 = sex16(_sw10);
+ _s2 = sex16(_sw32);
+ _energy1 = (_energy0 + ((_s0 * _s0) >> 6)) - ((_s2 * _s2) >> 6);
+ _energy0 = imax(0,_energy1);
+ energy[i] = _energy0;
+ __sw10 = ld32x(sw,j);
+ __sw32 = ld32x(sw,k);
+ __s0 = asri(16,__sw10);
+ __s2 = asri(16,__sw32);
+ _energy1 = (_energy0 + ((__s0 * __s0) >> 6)) - ((__s2 * __s2) >> 6);
+ _energy0 = imax(0,_energy1);
+ energy[i+1] = _energy0;
+ _sw10 = __sw10;
+ _sw32 = __sw32;
+ }
+
+ _s0 = sex16(_sw10);
+ _s2 = sex16(_sw32);
+ _energy0 = imax(0,(_energy0 + ((_s0 * _s0) >> 6)) - ((_s2 * _s2) >> 6));
+ energy[i] = _energy0;
+
+
+ eshift = normalize16(energy, ener16, 32766, end-start+1);
+ /* In fixed-point, this actually overrites the energy array (aliased to corr) */
+ pitch_xcorr(sw, sw-end, corr, len, end-start+1, stack);
+ /* Normalize to 180 so we can square it and it still fits in 16 bits */
+ cshift = normalize16(corr, corr16, 180, end-start+1);
+ /* If we scaled weighted input down, we need to scale it up again (OK, so we've just lost the LSB, who cares?) */
+
+ if ( scaledown )
+ {
+ for ( j=asri(1,-end),k=asli(1,-end) ; j<N2 ; ++j,k+=4 )
+ { register int _sw10;
+
+ _sw10 = ld32x(sw,j);
+ _sw10 = dualasl(_sw10,1);
+ st32d(k, sw, _sw10);
+ }
+ }
+
+ /* Search for the best pitch prediction gain */
+ for ( i=start,l=0 ; i<end ; i+=2,++l )
+ { register int _corr16, _c0, _c1;
+ register int _ener16, _e0, _e1;
+
+ _corr16 = ld32x(corr16,l);
+ _corr16 = dspidualmul(_corr16,_corr16);
+ _c0 = sex16(_corr16);
+ _c1 = asri(16,_corr16);
+
+ _ener16 = ld32x(ener16,l);
+ _ener16 = dspidualadd(_ener16,0x00010001);
+ _e0 = sex16(_ener16);
+ _e1 = asri(16,_ener16);
+
+ /* Instead of dividing the tmp by the energy, we multiply on the other side */
+
+ if ( (_c0 * best_ener[N-1]) > (best_score[N-1] * _e0) )
+ {
+ best_score[N-1] = _c0;
+ best_ener[N-1] = _e0;
+ pitch[N-1] = i;
+
+ for( j=0 ; j<N-1 ; ++j )
+ { if ( (_c0 * best_ener[j]) > best_score[j] * _e0 )
+ { for( k=N-1 ; k>j ; --k )
+ {
+ best_score[k]=best_score[k-1];
+ best_ener[k]=best_ener[k-1];
+ pitch[k]=pitch[k-1];
+ }
+
+ best_score[j]=_c0;
+ best_ener[j]=_e0;
+ pitch[j]=i;
+ break;
+ }
+ }
+ }
+
+ if ( (_c1 * best_ener[N-1]) > (best_score[N-1] * _e1) )
+ {
+ best_score[N-1] = _c1;
+ best_ener[N-1] = _e1;
+ pitch[N-1] = i+1;
+
+ for( j=0 ; j<N-1 ; ++j )
+ { if ( (_c1 * best_ener[j]) > best_score[j] * _e1 )
+ { for( k=N-1 ; k>j ; --k )
+ {
+ best_score[k]=best_score[k-1];
+ best_ener[k]=best_ener[k-1];
+ pitch[k]=pitch[k-1];
+ }
+
+ best_score[j]=_c1;
+ best_ener[j]=_e1;
+ pitch[j]=i+1;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Compute open-loop gain if necessary */
+ if (gain)
+ {
+ for (j=0;j<N;j++)
+ {
+ spx_word16_t g;
+ i=pitch[j];
+ g = DIV32(SHL32(EXTEND32(corr16[i-start]),cshift), 10+SHR32(MULT16_16(spx_sqrt(e0),spx_sqrt(SHL32(EXTEND32(ener16[i-start]),eshift))),6));
+ gain[j] = imax(0,g);
+ }
+ }
+
+ OPENLOOPNBESTPITCH_STOP();
+}
+
+
+#endif
+
diff --git a/tmv/mdf_tm.h b/tmv/mdf_tm.h new file mode 100644 index 0000000..cc82bf8 --- /dev/null +++ b/tmv/mdf_tm.h @@ -0,0 +1,1192 @@ +/* Copyright (C) 2007 Hong Zhiqian */
+/**
+ @file mdf_tm.h
+ @author Hong Zhiqian
+ @brief Various compatibility routines for Speex (TriMedia version)
+*/
+/*
+ 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 the Xiph.org Foundation 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 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.
+*/
+#include <ops/custom_defs.h>
+#include "profile_tm.h"
+
+// shifted power spectrum to fftwrap.c so that optimisation can be shared between mdf.c and preprocess.c
+#define OVERRIDE_POWER_SPECTRUM
+
+#ifdef FIXED_POINT
+
+#else
+
+#define OVERRIDE_FILTER_DC_NOTCH16
+void filter_dc_notch16(
+ const spx_int16_t * restrict in,
+ float radius,
+ float * restrict out,
+ int len,
+ float * restrict mem
+)
+{
+ register int i;
+ register float den2, r1;
+ register float mem0, mem1;
+
+ FILTERDCNOTCH16_START();
+
+ r1 = 1 - radius;
+ den2 = (radius * radius) + (0.7 * r1 * r1);
+ mem0 = mem[0];
+ mem1 = mem[1];
+
+#if (TM_UNROLL && TM_UNROLL_FILTERDCNOTCH16)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<len ; ++i )
+ {
+ register float vin = in[i];
+ register float vout = mem0 + vin;
+ register float rvout = radius * vout;
+
+ mem0 = mem1 + 2 * (-vin + rvout);
+ mem1 = vin - (den2 * vout);
+
+ out[i] = rvout;
+ }
+#if (TM_UNROLL && TM_UNROLL_FILTERDCNOTCH16)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ mem[0] = mem0;
+ mem[1] = mem1;
+
+ FILTERDCNOTCH16_STOP();
+}
+
+#define OVERRIDE_MDF_INNER_PROD
+float mdf_inner_prod(
+ const float * restrict x,
+ const float * restrict y,
+ int len
+)
+{
+ register float sum = 0;
+
+ MDFINNERPROD_START();
+
+ len >>= 1;
+
+#if (TM_UNROLL && TM_UNROLL_MDFINNERPRODUCT)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ while(len--)
+ {
+ register float acc0, acc1;
+
+ acc0 = (*x++) * (*y++);
+ acc1 = (*x++) * (*y++);
+
+ sum += acc0 + acc1;
+ }
+#if (TM_UNROLL && TM_UNROLL_MDFINNERPRODUCT)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ MDFINNERPROD_STOP();
+
+ return sum;
+}
+
+#define OVERRIDE_SPECTRAL_MUL_ACCUM
+void spectral_mul_accum(
+ const float * restrict X,
+ const float * restrict Y,
+ float * restrict acc,
+ int N, int M
+)
+{
+ register int i, j;
+ register float Xi, Yi, Xii, Yii;
+ register int _N;
+
+ SPECTRALMULACCUM_START();
+
+ acc[0] = X[0] * Y[0];
+ _N = N-1;
+
+ for ( i=1 ; i<_N ; i+=2 )
+ {
+ Xi = X[i];
+ Yi = Y[i];
+ Xii = X[i+1];
+ Yii = Y[i+1];
+
+ acc[i] = (Xi * Yi - Xii * Yii);
+ acc[i+1]= (Xii * Yi + Xi * Yii);
+ }
+
+ acc[_N] = X[_N] * Y[_N];
+
+ for ( j=1,X+=N,Y+=N ; j<M ; j++ )
+ {
+ acc[0] += X[0] * Y[0];
+
+ for ( i=1 ; i<N-1 ; i+=2 )
+ {
+ Xi = X[i];
+ Yi = Y[i];
+ Xii = X[i+1];
+ Yii = Y[i+1];
+
+ acc[i] += (Xi * Yi - Xii * Yii);
+ acc[i+1]+= (Xii * Yi + Xi * Yii);
+ }
+
+ acc[_N] += X[_N] * Y[_N];
+ X += N;
+ Y += N;
+ }
+
+ SPECTRALMULACCUM_STOP();
+}
+
+#define OVERRIDE_WEIGHTED_SPECTRAL_MUL_CONJ
+void weighted_spectral_mul_conj(
+ const float * restrict w,
+ const float p,
+ const float * restrict X,
+ const float * restrict Y,
+ float * restrict prod,
+ int N
+)
+{
+ register int i, j;
+ register int _N;
+
+ WEIGHTEDSPECTRALMULCONJ_START();
+
+ prod[0] = p * w[0] * X[0] * Y[0];
+ _N = N-1;
+
+ for (i=1,j=1;i<_N;i+=2,j++)
+ {
+ register float W;
+ register float Xi, Yi, Xii, Yii;
+
+ Xi = X[i];
+ Yi = Y[i];
+ Xii = X[i+1];
+ Yii = Y[i+1];
+ W = p * w[j];
+
+
+ prod[i] = W * (Xi * Yi + Xii * Yii);
+ prod[i+1]= W * (Xi * Yii - Xii * Yi);
+ }
+
+ prod[_N] = p * w[j] * X[_N] * Y[_N];
+
+ WEIGHTEDSPECTRALMULCONJ_STOP();
+}
+
+#define OVERRIDE_MDF_ADJUST_PROP
+void mdf_adjust_prop(
+ const float * restrict W,
+ int N,
+ int M,
+ float * restrict prop
+)
+{
+ register int i, j;
+ register float max_sum = 1;
+ register float prop_sum = 1;
+
+ MDFADJUSTPROP_START();
+
+ for ( i=0 ; i<M ; ++i )
+ {
+ register float tmp = 1;
+ register int k = i * N;
+ register int l = k + N;
+ register float propi;
+
+#if (TM_UNROLL && TM_UNROLL_MDFADJUSTPROP)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( j=k ; j<l ; ++j )
+ {
+ register float wi = W[j];
+
+ tmp += wi * wi;
+ }
+#if (TM_UNROLL && TM_UNROLL_MDFADJUSTPROP)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ propi = spx_sqrt(tmp);
+ prop[i]= propi;
+ max_sum= fmux(propi > max_sum, propi, max_sum);
+ }
+
+ for ( i=0 ; i<M ; ++i )
+ {
+ register float propi = prop[i];
+
+ propi += .1f * max_sum;
+ prop_sum += propi;
+ prop[i] = propi;
+ }
+
+ prop_sum = 0.99f / prop_sum;
+ for ( i=0 ; i<M ; ++i )
+ { prop[i] = prop_sum * prop[i];
+ }
+
+ MDFADJUSTPROP_STOP();
+}
+
+
+#define OVERRIDE_SPEEX_ECHO_GET_RESIDUAL
+void speex_echo_get_residual(
+ SpeexEchoState * restrict st,
+ float * restrict residual_echo,
+ int len
+)
+{
+ register int i;
+ register float leak2, leake;
+ register int N;
+ register float * restrict window;
+ register float * restrict last_y;
+ register float * restrict y;
+
+ SPEEXECHOGETRESIDUAL_START();
+
+ window = st->window;
+ last_y = st->last_y;
+ y = st->y;
+ N = st->window_size;
+
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOGETRESIDUAL)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for (i=0;i<N;i++)
+ { y[i] = window[i] * last_y[i];
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOGETRESIDUAL)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ spx_fft(st->fft_table, st->y, st->Y);
+ power_spectrum(st->Y, residual_echo, N);
+
+ leake = st->leak_estimate;
+ leak2 = fmux(leake > .5, 1, 2 * leake);
+ N = st->frame_size;
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOGETRESIDUAL)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<N ; ++i )
+ { residual_echo[i] *= leak2;
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOGETRESIDUAL)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ residual_echo[N] *= leak2;
+
+#ifndef NO_REMARK
+ (void)len;
+#endif
+
+ SPEEXECHOGETRESIDUAL_STOP();
+}
+#endif
+
+
+void mdf_preemph(
+ SpeexEchoState * restrict st,
+ spx_word16_t * restrict x,
+ const spx_int16_t * restrict far_end,
+ int framesize
+)
+{
+ register spx_word16_t preemph = st->preemph;
+ register spx_word16_t memX = st->memX;
+ register spx_word16_t memD = st->memD;
+ register spx_word16_t * restrict input = st->input;
+ register int i;
+#ifdef FIXED_POINT
+ register int saturated = st->saturated;
+#endif
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<framesize ; ++i )
+ {
+ register spx_int16_t far_endi = far_end[i];
+ register spx_word32_t tmp32;
+ register spx_word16_t inputi = input[i];
+
+ tmp32 = SUB32(EXTEND32(far_endi), EXTEND32(MULT16_16_P15(preemph,memX)));
+
+#ifdef FIXED_POINT
+ saturated = mux(iabs(tmp32) > 32767, M+1, saturated);
+ tmp32 = iclipi(tmp32,32767);
+#endif
+
+ x[i] = EXTRACT16(tmp32);
+ memX = far_endi;
+ tmp32 = SUB32(EXTEND32(inputi), EXTEND32(MULT16_16_P15(preemph, memD)));
+
+#ifdef FIXED_POINT
+ saturated = mux( ((tmp32 > 32767) && (saturated == 0)), 1,
+ mux( ((tmp32 <-32767) && (saturated == 0)), 1, saturated ));
+ tmp32 = iclipi(tmp32,32767);
+#endif
+ memD = inputi;
+ input[i] = tmp32;
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ st->memD = memD;
+ st->memX = memX;
+
+#ifdef FIXED_POINT
+ st->saturated = saturated;
+#endif
+}
+
+void mdf_sub(
+ spx_word16_t * restrict dest,
+ const spx_word16_t * restrict src1,
+ const spx_word16_t * restrict src2,
+ int framesize
+)
+{
+ register int i;
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+
+#ifdef FIXED_POINT
+ for ( i=0,framesize<<=1 ; i<framesize ; i+=4 )
+ { register int src1i, src2i, desti;
+
+ src1i = ld32d(src1,i);
+ src2i = ld32d(src2,i);
+ desti = dspidualsub(src1i,src2i);
+ st32d(i, dest, desti);
+ }
+#else
+ for ( i=0 ; i<framesize ; ++i )
+ { dest[i] = src1[i] - src2[i];
+ }
+#endif
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+}
+
+void mdf_sub_int(
+ spx_word16_t * restrict dest,
+ const spx_int16_t * restrict src1,
+ const spx_int16_t * restrict src2,
+ int framesize
+)
+{
+ register int i, j;
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+
+#ifdef FIXED_POINT
+ for ( i=0,framesize<<=1 ; i<framesize ; i+=4 )
+ { register int src1i, src2i, desti;
+
+ src1i = ld32d(src1,i);
+ src2i = ld32d(src2,i);
+ desti = dspidualsub(src1i,src2i);
+ st32d(i, dest, desti);
+ }
+#else
+ for ( i=0,j=0 ; i<framesize ; i+=2,++j )
+ { register int src1i, src2i, desti;
+
+
+ src1i = ld32d(src1,j);
+ src2i = ld32d(src2,j);
+ desti = dspidualsub(src1i,src2i);
+
+ dest[i] = sex16(desti);
+ dest[i+1] = asri(16,desti);
+ }
+#endif
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+}
+
+void mdf_compute_weight_gradient(
+ SpeexEchoState * restrict st,
+ spx_word16_t * restrict X,
+ int N,
+ int M
+)
+{
+ register int i, j;
+ register spx_word32_t * restrict PHI = st->PHI;
+
+ for (j=M-1;j>=0;j--)
+ {
+ register spx_word32_t * restrict W = &(st->W[j*N]);
+
+ weighted_spectral_mul_conj(
+ st->power_1,
+ FLOAT_SHL(PSEUDOFLOAT(st->prop[j]),-15),
+ &X[(j+1)*N],
+ st->E,
+ st->PHI,
+ N);
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for (i=0;i<N;i++)
+ { W[i] = ADD32(W[i],PHI[i]);
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ }
+}
+
+void mdf_update_weight(
+ SpeexEchoState * restrict st,
+ int N,
+ int M,
+ int framesize
+)
+{
+ register int j;
+ register int cancel_count = st->cancel_count;
+ register spx_word16_t * restrict wtmp = st->wtmp;
+#ifdef FIXED_POINT
+ register spx_word16_t * restrict wtmp2 = st->wtmp2;
+ register int i;
+#endif
+
+ for ( j=0 ; j<M ; j++ )
+ {
+ register spx_word32_t * restrict W = &(st->W[j*N]);
+
+ if (j==0 || cancel_count%(M-1) == j-1)
+ {
+#ifdef FIXED_POINT
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<N ; i++ )
+ wtmp2[i] = EXTRACT16(PSHR32(W[i],NORMALIZE_SCALEDOWN+16));
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ spx_ifft(st->fft_table, wtmp2, wtmp);
+ memset(wtmp, 0, framesize * sizeof(spx_word16_t));
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for (j=framesize; j<N ; ++j)
+ { wtmp[j]=SHL16(wtmp[j],NORMALIZE_SCALEUP);
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ spx_fft(st->fft_table, wtmp, wtmp2);
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for (i=0;i<N;i++)
+ { W[i] -= SHL32(EXTEND32(wtmp2[i]),16+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1);
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+#else
+ spx_ifft(st->fft_table, W, wtmp);
+ memset(&wtmp[framesize], 0, (N-framesize) * sizeof(spx_word16_t));
+ spx_fft(st->fft_table, wtmp, W);
+#endif
+ }
+ }
+}
+
+#ifdef TWO_PATH
+// first four parameters is passed by registers
+// generate faster performance with 4 parameters functions
+spx_word32_t mdf_update_foreground(
+ SpeexEchoState * restrict st,
+ spx_word32_t Dbf,
+ spx_word32_t Sff,
+ spx_word32_t See
+)
+{
+ register spx_word32_t Davg1 = st->Davg1;
+ register spx_word32_t Davg2 = st->Davg2;
+ register spx_word32_t Dvar1 = st->Dvar1;
+ register spx_word32_t Dvar2 = st->Dvar2;
+ register spx_word16_t * restrict input = st->input;
+ register int framesize = st->frame_size;
+ register spx_word16_t * restrict xx = st->x + framesize;
+ register spx_word16_t * restrict y = st->y + framesize;
+ register spx_word16_t * restrict ee = st->e + framesize;
+ register int update_foreground;
+ register int i;
+ register int N = st->window_size;
+ register int M = st->M;
+
+#ifdef FIXED_POINT
+ register spx_word32_t sc0 = SUB32(Sff,See);
+ register spx_float_t sc1 = FLOAT_MUL32U(Sff,Dbf);
+
+ Davg1 = ADD32(MULT16_32_Q15(QCONST16(.6f,15),Davg1), MULT16_32_Q15(QCONST16(.4f,15),sc0));
+ Davg2 = ADD32(MULT16_32_Q15(QCONST16(.85f,15),Davg2), MULT16_32_Q15(QCONST16(.15f,15),sc0));
+ Dvar1 = FLOAT_ADD(
+ FLOAT_MULT(VAR1_SMOOTH,Dvar1),
+ FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.4f,15),Sff),
+ MULT16_32_Q15(QCONST16(.4f,15),Dbf)));
+ Dvar2 = FLOAT_ADD(
+ FLOAT_MULT(VAR2_SMOOTH,Dvar2),
+ FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.15f,15),Sff),
+ MULT16_32_Q15(QCONST16(.15f,15),Dbf)));
+#else
+ register spx_word32_t sc0 = Sff - See;
+ register spx_word32_t sc1 = Sff * Dbf;
+
+ Davg1 = .6*Davg1 + .4*sc0;
+ Davg2 = .85*Davg2 + .15*sc0;
+ Dvar1 = VAR1_SMOOTH*Dvar1 + .16*sc1;
+ Dvar2 = VAR2_SMOOTH*Dvar2 + .0225*sc1;
+#endif
+
+ update_foreground =
+ mux( FLOAT_GT(FLOAT_MUL32U(sc0, VABS(sc0)), sc1), 1,
+ mux( FLOAT_GT(FLOAT_MUL32U(Davg1, VABS(Davg1)), FLOAT_MULT(VAR1_UPDATE,(Dvar1))), 1,
+ mux( FLOAT_GT(FLOAT_MUL32U(Davg2, VABS(Davg2)), FLOAT_MULT(VAR2_UPDATE,(Dvar2))), 1, 0)));
+
+ if ( update_foreground )
+ {
+ register spx_word16_t * restrict windowf = st->window + framesize;
+ register spx_word16_t * restrict window = st->window;
+
+ st->Davg1 = st->Davg2 = 0;
+ st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
+
+ memcpy(st->foreground, st->W, N*M*sizeof(spx_word32_t));
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<framesize ; ++i)
+ { register spx_word16_t wi = window[i];
+ register spx_word16_t wfi = windowf[i];
+ register spx_word16_t ei = ee[i];
+ register spx_word16_t yi = y[i];
+
+ ee[i] = MULT16_16_Q15(wfi,ei) + MULT16_16_Q15(wi,yi);
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ } else
+ {
+ register int reset_background;
+
+ reset_background =
+ mux( FLOAT_GT(FLOAT_MUL32U(-(sc0),VABS(sc0)), FLOAT_MULT(VAR_BACKTRACK,sc1)), 1,
+ mux( FLOAT_GT(FLOAT_MUL32U(-(Davg1), VABS(Davg1)), FLOAT_MULT(VAR_BACKTRACK,Dvar1)), 1,
+ mux( FLOAT_GT(FLOAT_MUL32U(-(Davg2), VABS(Davg2)), FLOAT_MULT(VAR_BACKTRACK,Dvar2)), 1, 0)));
+
+ if ( reset_background )
+ {
+ memcpy(st->W, st->foreground, N*M*sizeof(spx_word32_t));
+ memcpy(y, ee, framesize * sizeof(spx_word16_t));
+ mdf_sub(xx,input,y,framesize);
+ See = Sff;
+ st->Davg1 = st->Davg2 = 0;
+ st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
+ } else
+ {
+ st->Davg1 = Davg1;
+ st->Davg2 = Davg2;
+ st->Dvar1 = Dvar1;
+ st->Dvar2 = Dvar2;
+ }
+ }
+
+ return See;
+}
+#endif
+
+void mdf_compute_error_signal(
+ SpeexEchoState * restrict st,
+ const spx_int16_t * restrict in,
+ spx_int16_t * restrict out,
+ int framesize
+)
+{
+ register spx_word16_t preemph = st->preemph;
+ register spx_word16_t memE = st->memE;
+ register int saturated = st->saturated;
+ register spx_word16_t * restrict e = st->e;
+ register spx_word16_t * restrict ee = st->e + framesize;
+ register spx_word16_t * restrict input = st->input;
+ register spx_word16_t * restrict xx = st->x + framesize;
+ register int i;
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<framesize ; ++i )
+ {
+ register spx_word32_t tmp_out;
+ register spx_int16_t ini = in[i];
+ register int flg;
+
+#ifdef FIXED_POINT
+
+#ifdef TWO_PATH
+ tmp_out = SUB32(EXTEND32(input[i]), EXTEND32(ee[i]));
+ tmp_out = iclipi(tmp_out,32767);
+#else
+ tmp_out = SUB32(EXTEND32(input[i]), EXTEND32(y[i]));
+ tmp_out = iclipi(tmp_out,32767);
+#endif
+
+#else
+#ifdef TWO_PATH
+ tmp_out = SUB32(EXTEND32(input[i]), EXTEND32(ee[i]));
+#else
+ tmp_out = SUB32(EXTEND32(input[i]), EXTEND32(y[i]));
+#endif
+ tmp_out =
+ fmux( tmp_out > 32767, 32767,
+ fmux( tmp_out < -32768, -32768, tmp_out));
+#endif
+
+ tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(preemph,memE)));
+ flg = iabs(ini) >= 32000;
+ tmp_out = VMUX( flg, 0, tmp_out);
+ saturated = mux( flg && (saturated == 0), 1, saturated);
+
+ out[i] = (spx_int16_t)tmp_out;
+ memE = tmp_out;
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ st->memE = memE;
+ st->saturated = saturated;
+ memset(e, 0, framesize * sizeof(spx_word16_t));
+ memcpy(ee, xx, framesize * sizeof(spx_word16_t));
+}
+
+inline int mdf_check(
+ SpeexEchoState * restrict st,
+ spx_int16_t * out,
+ spx_word32_t Syy,
+ spx_word32_t Sxx,
+ spx_word32_t See,
+ spx_word32_t Sff,
+ spx_word32_t Sdd
+)
+{
+ register int N = st->window_size;
+ register spx_word32_t N1e9 = N * 1e9;
+ register int screwed_up = st->screwed_up;
+ register int framesize = st->frame_size;
+
+ if (!(Syy>=0 && Sxx>=0 && See >= 0)
+#ifndef FIXED_POINT
+ || !(Sff < N1e9 && Syy < N1e9 && Sxx < N1e9 )
+#endif
+ )
+ {
+ screwed_up += 50;
+ memset(out, 0, framesize * sizeof(spx_int16_t));
+
+ } else
+ { screwed_up = mux( SHR32(Sff, 2) > ADD32(Sdd, SHR32(MULT16_16(N, 10000),6)), screwed_up+1, 0);
+ }
+
+ st->screwed_up = screwed_up;
+
+ return screwed_up;
+}
+
+void mdf_smooth(
+ spx_word32_t * restrict power,
+ spx_word32_t * restrict Xf,
+ int framesize,
+ int M
+)
+{
+ register spx_word16_t ss, ss_1, pf, xff;
+ register int j;
+
+#ifdef FIXED_POINT
+ ss=DIV32_16(11469,M);
+ ss_1 = SUB16(32767,ss);
+#else
+ ss=.35/M;
+ ss_1 = 1-ss;
+#endif
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( j=0 ; j<framesize ; ++j )
+ { register spx_word32_t pi = power[j];
+ register spx_word32_t xfi = Xf[j];
+
+ power[j] = MULT16_32_Q15(ss_1,pi) + 1 + MULT16_32_Q15(ss,xfi);
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ pf = power[framesize];
+ xff = Xf[framesize];
+ power[framesize] = MULT16_32_Q15(ss_1,pf) + 1 + MULT16_32_Q15(ss,xff);
+}
+
+void mdf_compute_filtered_spectra_crosscorrelations(
+ SpeexEchoState * restrict st,
+ spx_word32_t Syy,
+ spx_word32_t See,
+ int framesize
+)
+{
+ register spx_float_t Pey = FLOAT_ONE;
+ register spx_float_t Pyy = FLOAT_ONE;
+ register spx_word16_t spec_average = st->spec_average;
+ register spx_word32_t * restrict pRf = st->Rf;
+ register spx_word32_t * restrict pYf = st->Yf;
+ register spx_word32_t * restrict pEh = st->Eh;
+ register spx_word32_t * restrict pYh = st->Yh;
+ register spx_word16_t beta0 = st->beta0;
+ register spx_word16_t beta_max = st->beta_max;
+ register spx_float_t alpha, alpha_1;
+ register spx_word32_t tmp32, tmpx;
+ register spx_float_t sPey = st->Pey;
+ register spx_float_t sPyy = st->Pyy;
+ register spx_float_t tmp;
+ register spx_word16_t leak_estimate;
+ register int j;
+ register spx_float_t Eh, Yh;
+ register spx_word32_t _Ehj, _Rfj, _Yfj, _Yhj;
+
+#ifdef FIXED_POINT
+ register spx_word16_t spec_average1 = SUB16(32767,spec_average);
+#else
+ register spx_word16_t spec_average1 = 1 - spec_average;
+#endif
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for (j=framesize; j>0 ; --j)
+ {
+ _Ehj = pEh[j];
+ _Rfj = pRf[j];
+ _Yfj = pYf[j];
+ _Yhj = pYh[j];
+
+ Eh = PSEUDOFLOAT(_Rfj - _Ehj);
+ Yh = PSEUDOFLOAT(_Yfj - _Yhj);
+
+ Pey = FLOAT_ADD(Pey,FLOAT_MULT(Eh,Yh));
+ Pyy = FLOAT_ADD(Pyy,FLOAT_MULT(Yh,Yh));
+
+ pEh[j] = MAC16_32_Q15(MULT16_32_Q15(spec_average1, _Ehj), spec_average, _Rfj);
+ pYh[j] = MAC16_32_Q15(MULT16_32_Q15(spec_average1, _Yhj), spec_average, _Yfj);
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ _Ehj = pEh[0];
+ _Rfj = pRf[0];
+ _Yfj = pYf[0];
+ _Yhj = pYh[0];
+
+ Eh = PSEUDOFLOAT(_Rfj - _Ehj);
+ Yh = PSEUDOFLOAT(_Yfj - _Yhj);
+
+ Pey = FLOAT_ADD(Pey,FLOAT_MULT(Eh,Yh));
+ Pyy = FLOAT_ADD(Pyy,FLOAT_MULT(Yh,Yh));
+
+ pEh[0] = MAC16_32_Q15(MULT16_32_Q15(spec_average1, _Ehj), spec_average, _Rfj);
+ pYh[0] = MAC16_32_Q15(MULT16_32_Q15(spec_average1, _Yhj), spec_average, _Yfj);
+
+ Pyy = FLOAT_SQRT(Pyy);
+ Pey = FLOAT_DIVU(Pey,Pyy);
+
+ tmp32 = MULT16_32_Q15(beta0,Syy);
+ tmpx = MULT16_32_Q15(beta_max,See);
+ tmp32 = VMUX(tmp32 > tmpx, tmpx, tmp32);
+ alpha = FLOAT_DIV32(tmp32, See);
+ alpha_1 = FLOAT_SUB(FLOAT_ONE, alpha);
+
+ sPey = FLOAT_ADD(FLOAT_MULT(alpha_1,sPey) , FLOAT_MULT(alpha,Pey));
+ sPyy = FLOAT_ADD(FLOAT_MULT(alpha_1,sPyy) , FLOAT_MULT(alpha,Pyy));
+ tmp = FLOAT_MULT(MIN_LEAK,sPyy);
+
+#ifndef FIXED_POINT
+ sPyy = VMUX(FLOAT_LT(sPyy, FLOAT_ONE), FLOAT_ONE, sPyy);
+ sPey = VMUX(FLOAT_LT(sPey, tmp), tmp, sPey);
+ sPey = VMUX(FLOAT_LT(sPey, sPyy), sPey, sPyy);
+#else
+ sPyy = FLOAT_LT(sPyy, FLOAT_ONE) ? FLOAT_ONE : sPyy;
+ sPey = FLOAT_LT(sPey, tmp) ? tmp : sPey;
+ sPey = FLOAT_LT(sPey, sPyy) ? sPey : sPyy;
+#endif
+
+ leak_estimate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIVU(sPey, sPyy),14));
+
+ leak_estimate = VMUX( leak_estimate > 16383, 32767, SHL16(leak_estimate,1));
+ st->Pey = sPey;
+ st->Pyy = sPyy;
+ st->leak_estimate = leak_estimate;
+}
+
+inline spx_word16_t mdf_compute_RER(
+ spx_word32_t See,
+ spx_word32_t Syy,
+ spx_word32_t Sey,
+ spx_word32_t Sxx,
+ spx_word16_t leake
+)
+{
+ register spx_word16_t RER;
+
+#ifdef FIXED_POINT
+ register spx_word32_t tmp32;
+ register spx_word32_t tmp;
+ spx_float_t bound = PSEUDOFLOAT(Sey);
+
+ tmp32 = MULT16_32_Q15(leake,Syy);
+ tmp32 = ADD32(SHR32(Sxx,13), ADD32(tmp32, SHL32(tmp32,1)));
+
+ bound = FLOAT_DIVU(FLOAT_MULT(bound, bound), PSEUDOFLOAT(ADD32(1,Syy)));
+ tmp = FLOAT_EXTRACT32(bound);
+ tmp32 = imux( FLOAT_GT(bound, PSEUDOFLOAT(See)), See,
+ imux( tmp32 < tmp, tmp, tmp32));
+
+ tmp = SHR32(See,1);
+ tmp32 = imux(tmp32 > tmp, tmp, tmp32);
+ RER = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32,See),15));
+#else
+ register spx_word32_t r0;
+
+ r0 = (Sey * Sey)/(1 + See * Syy);
+
+ RER = (.0001*Sxx + 3.* MULT16_32_Q15(leake,Syy)) / See;
+ RER = fmux( RER < r0, r0, RER);
+ RER = fmux( RER > .5, .5, RER);
+#endif
+
+ return RER;
+}
+
+void mdf_adapt(
+ SpeexEchoState * restrict st,
+ spx_word16_t RER,
+ spx_word32_t Syy,
+ spx_word32_t See,
+ spx_word32_t Sxx
+)
+{
+ register spx_float_t * restrict power_1 = st->power_1;
+ register spx_word32_t * restrict power = st->power;
+ register int adapted = st->adapted;
+ register spx_word32_t sum_adapt = st->sum_adapt;
+ register spx_word16_t leake = st->leak_estimate;
+ register int framesize = st->frame_size;
+ register int i;
+ register int M = st->M;
+
+ adapted = mux( !adapted && sum_adapt > QCONST32(M,15) &&
+ MULT16_32_Q15(leake,Syy) > MULT16_32_Q15(QCONST16(.03f,15),Syy), 1, adapted);
+
+ if ( adapted )
+ { register spx_word32_t * restrict Yf = st->Yf;
+ register spx_word32_t * restrict Rf = st->Rf;
+ register spx_word32_t r, e, e2;
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<framesize ; ++i )
+ {
+ r = SHL32(Yf[i],3);
+ r = MULT16_32_Q15(leake,r);
+ e = SHL32(Rf[i],3)+1;
+
+#ifdef FIXED_POINT
+ e2 = SHR32(e,1);
+ r = mux( r > e2, e2, r);
+#else
+ e2 = e * .5;
+ r = fmux( r > e2, e2, r);
+#endif
+
+ r = MULT16_32_Q15(QCONST16(.7,15),r) +
+ MULT16_32_Q15(QCONST16(.3,15),(spx_word32_t)(MULT16_32_Q15(RER,e)));
+
+ power_1[i] = FLOAT_SHL(FLOAT_DIV32_FLOAT(r,FLOAT_MUL32U(e,power[i]+10)),WEIGHT_SHIFT+16);
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ r = SHL32(Yf[framesize],3);
+ r = MULT16_32_Q15(leake,r);
+ e = SHL32(Rf[framesize],3)+1;
+
+#ifdef FIXED_POINT
+ e2 = SHR32(e,1);
+ r = mux( r > e2, e2, r);
+#else
+ e2 = e * .5;
+ r = fmux( r > e2, e2, r);
+#endif
+
+ r = MULT16_32_Q15(QCONST16(.7,15),r) +
+ MULT16_32_Q15(QCONST16(.3,15),(spx_word32_t)(MULT16_32_Q15(RER,e)));
+
+ power_1[framesize] = FLOAT_SHL(FLOAT_DIV32_FLOAT(r,FLOAT_MUL32U(e,power[framesize]+10)),WEIGHT_SHIFT+16);
+
+ } else
+ {
+ register spx_word16_t adapt_rate=0;
+ register int N = st->window_size;
+
+ if ( Sxx > SHR32(MULT16_16(N, 1000),6) )
+ { register spx_word32_t tmp32, tmp32q;
+
+ tmp32 = MULT16_32_Q15(QCONST16(.25f, 15), Sxx);
+#ifdef FIXED_POINT
+ tmp32q = SHR32(See,2);
+ tmp32 = mux(tmp32 > tmp32q, tmp32q, tmp32);
+#else
+ tmp32q = 0.25 * See;
+ tmp32 = fmux(tmp32 > tmp32q, tmp32q, tmp32);
+#endif
+ adapt_rate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32, See),15));
+ }
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for (i=0;i<framesize;i++)
+ power_1[i] = FLOAT_SHL(FLOAT_DIV32(EXTEND32(adapt_rate),ADD32(power[i],10)),WEIGHT_SHIFT+1);
+#if (TM_UNROLL && TM_UNROLL_SPEEXECHOCANCELLATION)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ power_1[framesize] = FLOAT_SHL(FLOAT_DIV32(EXTEND32(adapt_rate),ADD32(power[framesize],10)),WEIGHT_SHIFT+1);
+ sum_adapt = ADD32(sum_adapt,adapt_rate);
+ }
+
+ st->sum_adapt = sum_adapt;
+ st->adapted = adapted;
+}
+
+#define OVERRIDE_ECHO_CANCELLATION
+void speex_echo_cancellation(
+ SpeexEchoState * restrict st,
+ const spx_int16_t * restrict in,
+ const spx_int16_t * restrict far_end,
+ spx_int16_t * restrict out
+)
+{
+ register int framesize = st->frame_size;
+ register spx_word16_t * restrict x = st->x;
+ register spx_word16_t * restrict xx = st->x + framesize;
+ register spx_word16_t * restrict yy = st->y + framesize;
+ register spx_word16_t * restrict ee = st->e + framesize;
+ register spx_word32_t Syy, See, Sxx, Sdd, Sff;
+ register spx_word16_t RER;
+ register spx_word32_t Sey;
+ register int j;
+ register int N,M;
+#ifdef TWO_PATH
+ register spx_word32_t Dbf;
+#endif
+
+ N = st->window_size;
+ M = st->M;
+ st->cancel_count++;
+
+ filter_dc_notch16(in, st->notch_radius, st->input, framesize, st->notch_mem);
+ mdf_preemph(st, xx, far_end, framesize);
+
+ {
+
+ register spx_word16_t * restrict X = st->X;
+
+ for ( j=M-1 ; j>=0 ; j-- )
+ { register spx_word16_t * restrict Xdes = &(X[(j+1)*N]);
+ register spx_word16_t * restrict Xsrc = &(X[j*N]);
+
+ memcpy(Xdes, Xsrc, N * sizeof(spx_word16_t));
+ }
+
+ spx_fft(st->fft_table, x, X);
+ memcpy(st->last_y, st->x, N * sizeof(spx_word16_t));
+ Sxx = mdf_inner_prod(xx, xx, framesize);
+ memcpy(x, xx, framesize * sizeof(spx_word16_t));
+
+#ifdef TWO_PATH
+ spectral_mul_accum(st->X, st->foreground, st->Y, N, M);
+ spx_ifft(st->fft_table, st->Y, st->e);
+ mdf_sub(xx, st->input, ee, framesize);
+ Sff = mdf_inner_prod(xx, xx, framesize);
+#endif
+
+ mdf_adjust_prop (st->W, N, M, st->prop);
+
+ if (st->saturated == 0)
+ { mdf_compute_weight_gradient(st, X, N, M);
+ } else
+ { st->saturated--;
+ }
+ }
+
+ mdf_update_weight(st, N, M, framesize);
+ spectral_mul_accum(st->X, st->W, st->Y, N, M);
+ spx_ifft(st->fft_table, st->Y, st->y);
+
+#ifdef TWO_PATH
+ mdf_sub(xx, ee, yy, framesize);
+ Dbf = 10+mdf_inner_prod(xx, xx, framesize);
+#endif
+
+ mdf_sub(xx, st->input, yy, framesize);
+ See = mdf_inner_prod(xx, xx, framesize);
+
+#ifndef TWO_PATH
+ Sff = See;
+#else
+ See = mdf_update_foreground(st,Dbf,Sff,See);
+#endif
+
+
+ mdf_compute_error_signal(st, in, out, framesize);
+ Sey = mdf_inner_prod(ee, yy, framesize);
+ Syy = mdf_inner_prod(yy, yy, framesize);
+ Sdd = mdf_inner_prod(st->input, st->input, framesize);
+
+ if ( mdf_check(st,out,Syy,Sxx,See,Sff,Sdd) >= 50 )
+ { speex_warning("The echo canceller started acting funny and got slapped (reset). It swears it will behave now.");
+ speex_echo_state_reset(st);
+ return;
+ }
+
+ See = MAX32(See, SHR32(MULT16_16(N, 100),6));
+ spx_fft(st->fft_table, st->e, st->E);
+ memset(st->y, 0, framesize * sizeof(spx_word16_t));
+ spx_fft(st->fft_table, st->y, st->Y);
+ power_spectrum(st->E, st->Rf, N);
+ power_spectrum(st->Y, st->Yf, N);
+ power_spectrum(st->X, st->Xf, N);
+
+ mdf_smooth(st->power,st->Xf,framesize, M);
+ mdf_compute_filtered_spectra_crosscorrelations(st,Syy,See,framesize);
+ RER = mdf_compute_RER(See,Syy,Sey,Sxx,st->leak_estimate);
+ mdf_adapt(st, RER, Syy, See, Sxx);
+
+ if ( st->adapted )
+ { register spx_word16_t * restrict last_yy = st->last_y + framesize;
+
+ memcpy(st->last_y, last_yy, framesize * sizeof(spx_word16_t));
+ mdf_sub_int(last_yy, in, out, framesize);
+
+ }
+}
+
+
+
diff --git a/include/speex/speex_noglobals.h b/tmv/misc_tm.h index 1d46993..4d6cea7 100644 --- a/include/speex/speex_noglobals.h +++ b/tmv/misc_tm.h @@ -1,60 +1,92 @@ -/* Copyright (C) 2004 CSIRO Australia */ -/* Copyright (C) 2002 Jean-Marc Valin*/ -/** - @file speex_noglobals.h - @brief Dynamically allocates the different modes of the codec -*/ -/* - 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 the Xiph.org Foundation 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 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 SPEEX_NOGLOBALS_H -#define SPEEX_NOGLOBALS_H - -/* See README.symbian in the Speex source distribution for information - * on using this API */ - -typedef struct SpeexMode SpeexMode; - -#ifdef __cplusplus -extern "C" { -#endif - -/** Instantiate a mode */ -const SpeexMode * speex_mode_new (int modeID); - -/** Destroy a mode */ -void speex_mode_destroy (const SpeexMode * mode); - -#ifdef __cplusplus -} -#endif - - -#endif +/* Copyright (C) 2007 Hong Zhiqian */
+/**
+ @file misc_tm.h
+ @author Hong Zhiqian
+ @brief Various compatibility routines for Speex (TriMedia version)
+*/
+/*
+ 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 the Xiph.org Foundation 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 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.
+*/
+#include <tmml.h>
+
+
+#if TM_PROFILE
+int __profile_begin;
+int __profile_end;
+#endif
+
+#define OVERRIDE_SPEEX_ALLOC
+void *speex_alloc (int size)
+{
+ void *ptr;
+
+ if ( tmmlMalloc(0, size, (pVoid*)&ptr, tmmlMallocCacheAligned | tmmlMallocCleared) != TM_OK )
+ { return NULL;
+ }
+
+ return ptr;
+}
+
+
+#define OVERRIDE_SPEEX_ALLOC_SCRATCH
+void *speex_alloc_scratch (int size)
+{
+ void *ptr;
+
+ if ( tmmlMalloc(0, size, (pVoid*)&ptr, tmmlMallocCacheAligned | tmmlMallocCleared) != TM_OK )
+ { return NULL;
+ }
+
+ return ptr;
+}
+
+
+#define OVERRIDE_SPEEX_REALLOC
+void *speex_realloc (void *ptr, int size)
+{
+ if ( tmmlRealloc(0, size, (pVoid)ptr, (pVoid*)&ptr, tmmlMallocCacheAligned | tmmlMallocCleared) != TM_OK )
+ { return NULL;
+ }
+
+ return ptr;
+}
+
+
+#define OVERRIDE_SPEEX_FREE
+void speex_free (void *ptr)
+{
+ tmmlFree(ptr);
+}
+
+
+#define OVERRIDE_SPEEX_FREE_SCRATCH
+void speex_free_scratch (void *ptr)
+{
+ tmmlFree(ptr);
+}
+
diff --git a/tmv/preprocess_tm.h b/tmv/preprocess_tm.h new file mode 100644 index 0000000..f903b73 --- /dev/null +++ b/tmv/preprocess_tm.h @@ -0,0 +1,1135 @@ +/* Copyright (C) 2007 Hong Zhiqian */
+/**
+ @file preprocess_tm.h
+ @author Hong Zhiqian
+ @brief Various compatibility routines for Speex (TriMedia version)
+*/
+/*
+ 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 the Xiph.org Foundation 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 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.
+*/
+#include <ops/custom_defs.h>
+#include "profile_tm.h"
+
+#ifdef FIXED_POINT
+#define OVERRIDE_PREPROCESS_ANALYSIS
+static void preprocess_analysis(SpeexPreprocessState * restrict st, spx_int16_t * restrict x)
+{
+ register int i, j, framesize = st->frame_size;
+ register int N = st->ps_size;
+ register int N3 = 2*N - framesize;
+ register int N4 = framesize - N3;
+ register int * restrict ps = st->ps;
+ register int * restrict frame;
+ register int * restrict inbuf;
+ register int * restrict ptr;
+ register int max_val;
+
+ frame = (int*)(st->frame);
+ inbuf = (int*)(st->inbuf);
+ ptr = (int*)(st->frame+N3);
+
+ TMDEBUG_ALIGNMEM(x);
+ TMDEBUG_ALIGNMEM(frame);
+ TMDEBUG_ALIGNMEM(inbuf);
+
+ PREPROCESSANAYLSIS_START();
+
+ N3 >>= 1;
+ framesize >>= 1;
+ max_val = 0;
+
+ for ( i=0,j=0 ; i<N3 ; i+=2,j+=8 )
+ { register int r1, r2;
+
+ r1 = ld32x(inbuf,i);
+ r2 = ld32x(inbuf,i+1);
+
+ st32d(j, frame, r1);
+ st32d(j+4, frame, r2);
+ }
+
+ for ( i=0,j=0 ; i<framesize ; i+=2,j+=8 )
+ { register int r1, r2;
+
+ r1 = ld32x(x, i);
+ r2 = ld32x(x, i+1);
+
+ st32d(j, ptr, r1);
+ st32d(j+4,ptr, r2);
+ }
+
+ for ( i=0,j=0,ptr=(int*)(x+N4) ; i<N3 ; i+=2,j+=8 )
+ { register int r1, r2;
+
+ r1 = ld32x(ptr, i);
+ r2 = ld32x(ptr, i+1);
+
+ st32d(j, inbuf, r1);
+ st32d(j+4,inbuf, r2);
+ }
+#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS)
+#pragma TCS_unroll=2
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0,j=0,ptr=(int*)st->window ; i<N ; ++i,j+=4 )
+ { register int f10, w10, r0, r1;
+
+ f10 = ld32x(frame, i);
+ w10 = ld32x(ptr, i);
+
+ r0 = (sex16(f10) * sex16(w10)) >> 15;
+ r1 = (asri(16,f10) * asri(16,w10)) >> 15;
+
+ max_val = imax(iabs(sex16(r0)), max_val);
+ max_val = imax(iabs(sex16(r1)), max_val);
+
+ r0 = pack16lsb(r1, r0);
+ st32d(j, frame, r0);
+ }
+#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ max_val = 14 - spx_ilog2(max_val);
+ st->frame_shift = max_val;
+
+ if ( max_val != 0 )
+ {
+#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0,j=0 ; i<N ; ++i,j+=4 )
+ { register int f10;
+
+ f10 = ld32x(frame, i);
+ f10 = dualasl(f10, max_val);
+ st32d(j, frame, f10);
+
+ }
+#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ }
+
+ spx_fft(st->fft_lookup, st->frame, st->ft);
+ power_spectrum(st->ft, ps, N << 1);
+
+#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0,ptr=(int*)st->ps,max_val<<=1,j=((1<<((max_val))>>1)) ;i<N ; ++i )
+ {
+ ps[i] = (ps[i] + j) >> max_val;
+ }
+#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ filterbank_compute_bank32(st->bank, ps, ps+N);
+
+ PREPROCESSANAYLSIS_STOP();
+}
+
+#define _MULT16_32_Q15(a,b,c) ADD32(MULT16_16((a),(b)), SHR(MULT16_16((a),(c)),15))
+
+#define OVERRIDE_UPDATE_NOISE_PROB
+static void update_noise_prob(SpeexPreprocessState * restrict st)
+{
+ register int i;
+ register int min_range, nb_adapt;
+ register int N = st->ps_size;
+ register int * restrict Smin = (int*)st->Smin;
+ register int * restrict Stmp = (int*)st->Stmp;
+ register int * restrict S = (int*)st->S;
+
+ UPDATENOISEPROB_START();
+
+ {
+ register int psi_lsb, psi_msb, ips_lsb, ips_msb, psii_lsb, psii_msb;
+ register int psiii_lsb, psiii_msb;
+ register int q8, q05, q2, q1;
+ register int *ps = (int*)st->ps;
+ register int si_lsb, si_msb, sii_lsb, sii_msb;
+
+ q8 = QCONST16(.8f,15);
+ q05 = QCONST16(.05f,15);
+ q2 = QCONST16(.2f,15);
+ q1 = QCONST16(.1f,15);
+
+ ips_lsb = ps[0];
+ psi_lsb = ps[1];
+ si_lsb = S[0];
+ ips_msb = ips_lsb >> 15;
+ psi_msb = psi_lsb >> 15;
+ si_msb = si_lsb >> 15;
+
+ ips_lsb &= 0x00007fff;
+ psi_lsb &= 0x00007fff;
+ si_lsb &= 0x00007fff;
+
+ S[0] = _MULT16_32_Q15(q8,si_msb,si_lsb) + _MULT16_32_Q15(q2,ips_msb,ips_lsb);
+
+ for ( i=1 ; i<N-1 ; i+=2 )
+ {
+ psii_lsb = ps[i+1];
+ si_lsb = S[i];
+
+ psii_msb = psii_lsb >> 15;
+ si_msb = si_lsb >> 15;
+ si_lsb &= 0x00007fff;
+ psii_lsb &= 0x00007fff;
+
+ S[i]= _MULT16_32_Q15(q8,si_msb,si_lsb) +
+ _MULT16_32_Q15(q05,ips_msb,ips_lsb) +
+ _MULT16_32_Q15(q1,psi_msb,psi_lsb) +
+ _MULT16_32_Q15(q05,psii_msb,psii_lsb);
+
+ psiii_lsb = ps[i+2];
+ sii_lsb = S[i+1];
+
+ sii_msb = sii_lsb >> 15;
+ psiii_msb= psiii_lsb >> 15;
+ sii_lsb &= 0x00007fff;
+ psiii_lsb&= 0x00007fff;
+
+ S[i+1]= _MULT16_32_Q15(q8,sii_msb,sii_lsb) +
+ _MULT16_32_Q15(q05,psi_msb,psi_lsb) +
+ _MULT16_32_Q15(q1,psii_msb,psii_lsb) +
+ _MULT16_32_Q15(q05,psiii_msb,psiii_lsb);
+
+ ips_lsb = psii_lsb;
+ ips_msb = psii_msb;
+ psi_lsb = psiii_lsb;
+ psi_msb = psiii_msb;
+ }
+
+ S[N-1] = MULT16_32_Q15(q8,S[N-1]) + MULT16_32_Q15(q2,ps[N-1]);
+ }
+
+ nb_adapt = st->nb_adapt;
+
+ if ( nb_adapt==1 )
+ { for ( i=0 ; i<N ; ++i )
+ Smin[i] = Stmp[i] = 0;
+
+ }
+
+ min_range = mux(nb_adapt < 100, 15,
+ mux(nb_adapt < 1000, 50,
+ mux(nb_adapt < 10000, 150, 300)));
+
+ if ( st->min_count > min_range )
+ {
+ st->min_count = 0;
+
+#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB)
+#pragma TCS_unroll=2
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<N ; ++i )
+ { register int si, stmpi;
+
+ si = S[i];
+ stmpi = Stmp[i];
+
+ Smin[i] = imin(stmpi,si);
+ Stmp[i] = si;
+ }
+#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ } else
+ {
+
+#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB)
+#pragma TCS_unroll=2
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<N ; ++i )
+ { register int si, stmpi, smini;
+
+ si = S[i];
+ stmpi = Stmp[i];
+ smini = Smin[i];
+
+ Smin[i] = imin(smini,si);
+ Stmp[i] = imin(stmpi,si);
+ }
+#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ }
+
+
+ {
+ register int q4;
+ register int * restrict update_prob = (int*)st->update_prob;
+
+ q4 = QCONST16(.4f,15);
+
+#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<N ; ++i )
+ { register int si;
+ register int smini;
+
+ si = S[i];
+ smini = Smin[i];
+ update_prob[i] = mux(MULT16_32_Q15(q4,si) > ADD32(smini,20), 1, 0);
+ }
+#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ }
+
+ UPDATENOISEPROB_STOP();
+}
+
+#else
+
+#define OVERRIDE_PREPROCESS_ANALYSIS
+static void preprocess_analysis(SpeexPreprocessState * restrict st, spx_int16_t * restrict x)
+{
+ register int i;
+ register int framesize = st->frame_size;
+ register int N = st->ps_size;
+ register int N3 = 2*N - framesize;
+ register int N4 = framesize - N3;
+ register float * restrict ps = st->ps;
+ register float * restrict frame = st->frame;
+ register float * restrict inbuf = st->inbuf;
+
+ PREPROCESSANAYLSIS_START();
+
+#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<N3 ; ++i )
+ {
+ frame[i] = inbuf[i];
+ }
+#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<framesize ; ++i )
+ { frame[N3+i] = x[i];
+ }
+#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0,x+=N4 ; i<N3 ; ++i )
+ { inbuf[i] = x[i];
+ }
+#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ inbuf = st->window;
+
+#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<2*N ; ++i )
+ {
+ frame[i] = frame[i] * inbuf[i];
+ }
+#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ spx_fft(st->fft_lookup, frame, st->ft);
+ power_spectrum(st->ft, ps, N << 1);
+ filterbank_compute_bank32(st->bank, ps, ps+N);
+
+ PREPROCESSANAYLSIS_STOP();
+}
+
+
+#define OVERRIDE_UPDATE_NOISE_PROB
+static void update_noise_prob(SpeexPreprocessState * restrict st)
+{
+
+ register float * restrict S = st->S;
+ register float * restrict ps = st->ps;
+ register int N = st->ps_size;
+ register int min_range;
+ register int i;
+ register int nb_adapt;
+ register float * restrict Smin = st->Smin;
+ register float * restrict Stmp = st->Stmp;
+
+ UPDATENOISEPROB_START();
+
+ {
+ register float ips, psi;
+
+ ips = ps[0];
+ psi = ps[1];
+
+ S[0] = .8f * S[0] + .2f * ips;
+
+ for ( i=1 ; i<N-1 ; i+=2 )
+ {
+ register float psii, psiii;
+
+ psii = ps[i+1];
+ psiii = ps[i+2];
+ S[i] = .8f * S[i] + .05f * ips + .1f * psi + .05f * psii;
+ S[i+1] = .8f * S[i+1] + .05f * psi + .1f * psii + .05f * psiii;
+ ips = psii;
+ psi = psiii;
+ }
+
+ S[N-1] = .8f * S[N-1] + .2f * ps[N-1];
+ }
+
+ nb_adapt = st->nb_adapt;
+
+ if ( nb_adapt==1 )
+ {
+ for (i=0;i<N;i++)
+ Smin[i] = st->Stmp[i] = 0;
+ }
+
+ min_range = mux(nb_adapt < 100, 15,
+ mux(nb_adapt < 1000, 50,
+ mux(nb_adapt < 10000, 150, 300)));
+
+
+ if ( st->min_count > min_range )
+ {
+ st->min_count = 0;
+#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<N ; ++i )
+ {
+ register float stmpi, si;
+
+ stmpi = Stmp[i];
+ si = S[i];
+
+ Smin[i] = fmin(stmpi,si);
+ Stmp[i] = si;
+ }
+#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ } else
+ {
+ register float * restrict Smin = st->Smin;
+
+#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<N ; ++i )
+ {
+ register float stmpi, si, smini;
+
+ stmpi = Stmp[i];
+ si = S[i];
+ smini = Smin[i];
+
+ Smin[i] = fmin(smini,si);
+ Stmp[i] = fmin(stmpi,si);
+ }
+#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ }
+
+ {
+ register int * restrict update_prob = (int*)st->update_prob;
+
+#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for (i=0;i<N;i++)
+ { register float si;
+ register float smini;
+
+ si = S[i];
+ smini = Smin[i];
+ update_prob[i] = mux( (.4 * si) > (smini + 20.f), 1, 0);
+
+ }
+#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ }
+
+ UPDATENOISEPROB_STOP();
+}
+
+
+#define OVERRIDE_COMPUTE_GAIN_FLOOR
+static void compute_gain_floor(
+ int noise_suppress,
+ int effective_echo_suppress,
+ float * restrict noise,
+ float * restrict echo,
+ float * gain_floor,
+ int len
+)
+{
+ register int i;
+ register float echo_floor;
+ register float noise_floor;
+
+ COMPUTEGAINFLOOR_START();
+
+ noise_floor = exp(.2302585f*noise_suppress);
+ echo_floor = exp(.2302585f*effective_echo_suppress);
+
+#if (TM_UNROLL && TM_UNROLL_COMPUTEGAINFLOOR)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for (i=0;i<len;i++)
+ { register float noisei, echoi;
+
+ noisei = noise[i];
+ echoi = echo[i];
+
+ gain_floor[i] = FRAC_SCALING * sqrt(noise_floor * noisei + echo_floor * echoi) / sqrt(1+noisei+echoi);
+
+ }
+#if (TM_UNROLL && TM_UNROLL_COMPUTEGAINFLOOR)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ COMPUTEGAINFLOOR_STOP();
+}
+
+#endif
+
+static inline spx_word32_t hypergeom_gain(spx_word32_t xx);
+static inline spx_word16_t qcurve(spx_word16_t x);
+static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, spx_word32_t *noise, spx_word32_t *echo, spx_word16_t *gain_floor, int len);
+void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len);
+
+#ifndef FIXED_POINT
+static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx_word16_t *ft);
+#endif
+
+void preprocess_residue_echo(
+ SpeexPreprocessState * restrict st,
+ int N,
+ int NM
+)
+{
+ if (st->echo_state)
+ {
+ register spx_word32_t * restrict r_echo = st->residual_echo;
+ register spx_word32_t * restrict e_noise = st->echo_noise;
+ register int i;
+
+#ifndef FIXED_POINT
+ register spx_word32_t r;
+#endif
+
+ speex_echo_get_residual(st->echo_state, r_echo, N);
+
+#ifndef FIXED_POINT
+ r = r_echo[0];
+ if (!(r >=0 && r < N*1e9f) )
+ {
+ memset(r_echo, 0, N * sizeof(spx_word32_t));
+ }
+#endif
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for (i=0;i<N;i++)
+ { register spx_word32_t eni = e_noise[i];
+ e_noise[i] = MAX32(MULT16_32_Q15(QCONST16(.6f,15),eni), r_echo[i]);
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ filterbank_compute_bank32(st->bank, e_noise, e_noise+N);
+
+ } else
+ { memset(st->echo_noise, 0, (NM) * sizeof(spx_word32_t));
+ }
+}
+
+void preprocess_update_noise(
+ SpeexPreprocessState * restrict st,
+ spx_word32_t * restrict ps,
+ int N
+)
+{
+ register spx_word16_t beta, beta_1;
+ register int * restrict up = st->update_prob;
+ register spx_word32_t * restrict noise = st->noise;
+ register int i;
+
+ beta = MAX16(QCONST16(.03,15),DIV32_16(Q15_ONE,st->nb_adapt));
+ beta_1 = Q15_ONE-beta;
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for (i=0;i<N;i++)
+ { register spx_word32_t ni = noise[i];
+ register spx_word32_t psi = ps[i];
+
+ if ( !up[i] || psi < PSHR32(ni, NOISE_SHIFT) )
+ { noise[i] = MAX32(EXTEND32(0),MULT16_32_Q15(beta_1,ni) +
+ MULT16_32_Q15(beta,SHL32(psi,NOISE_SHIFT)));
+ }
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ filterbank_compute_bank32(st->bank, noise, noise+N);
+}
+
+void preprocess_compute_SNR(
+ SpeexPreprocessState * restrict st,
+ spx_word32_t * restrict ps,
+ int NM
+)
+{
+ register spx_word32_t * restrict noise = st->noise;
+ register spx_word32_t * restrict echo = st->echo_noise;
+ register spx_word32_t * restrict reverb = st->reverb_estimate;
+ register spx_word16_t * restrict post = st->post;
+ register spx_word32_t * restrict old_ps = st->old_ps;
+ register spx_word16_t * restrict prior = st->prior;
+ register int i;
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<NM ; i++)
+ {
+ register spx_word16_t gamma;
+ register spx_word32_t tot_noise;
+ register spx_word16_t posti;
+ register spx_word32_t opsi;
+ register spx_word16_t priori;
+
+ tot_noise = ADD32(ADD32(ADD32(EXTEND32(1), PSHR32(noise[i],NOISE_SHIFT)), echo[i]) , reverb[i]);
+
+ posti = SUB16(DIV32_16_Q8(ps[i],tot_noise), QCONST16(1.f,SNR_SHIFT));
+ posti = MIN16(posti, QCONST16(100.f,SNR_SHIFT));
+ post[i] = posti;
+
+ opsi = old_ps[i];
+
+ gamma = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.89f,15),SQR16_Q15(DIV32_16_Q15(opsi,ADD32(opsi,tot_noise))));
+
+ priori = EXTRACT16(PSHR32(ADD32(MULT16_16(gamma,MAX16(0,posti)), MULT16_16(Q15_ONE-gamma,DIV32_16_Q8(opsi,tot_noise))), 15));
+ prior[i]=MIN16(priori, QCONST16(100.f,SNR_SHIFT));
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+}
+
+spx_word32_t preprocess_smooth_SNR(
+ SpeexPreprocessState * restrict st,
+ int N,
+ int NM
+)
+{
+ register spx_word16_t * restrict zeta = st->zeta;
+ register spx_word16_t * restrict prior = st->prior;
+ register spx_word32_t Zframe;
+ register spx_word16_t iprior, priori;
+ register int _N = N-1;
+ register int i;
+
+ iprior = prior[0];
+ priori = prior[1];
+ zeta[0] = PSHR32(ADD32(MULT16_16(QCONST16(.7f,15),zeta[0]), MULT16_16(QCONST16(.3f,15),iprior)),15);
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unroll=2
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=1 ; i<_N ; i++)
+ { register spx_word16_t zetai = zeta[i];
+ register spx_word16_t priorii = prior[i+1];
+
+ zeta[i] = PSHR32(ADD32(ADD32(ADD32(MULT16_16(QCONST16(.7f,15),zetai), MULT16_16(QCONST16(.15f,15),priori)),
+ MULT16_16(QCONST16(.075f,15),iprior)), MULT16_16(QCONST16(.075f,15),priorii)),15);
+
+ iprior = priori;
+ priori = priorii;
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ for (i=_N; i<NM ; i++)
+ { register spx_word16_t zetai = zeta[i];
+
+ priori = prior[i];
+ zeta[i] = PSHR32(ADD32(MULT16_16(QCONST16(.7f,15),zetai), MULT16_16(QCONST16(.3f,15),priori)),15);
+ }
+
+ Zframe = 0;
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=N ; i<NM ; i++ )
+ { Zframe = ADD32(Zframe, EXTEND32(zeta[i]));
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ return Zframe;
+}
+
+void preprocess_compute_emgain(
+ SpeexPreprocessState * restrict st,
+ spx_word32_t * restrict ps,
+ spx_word16_t Pframe,
+ int NM
+)
+{
+ register spx_word16_t * restrict zeta = st->zeta;
+ register spx_word16_t * restrict prior = st->prior;
+ register spx_word16_t * restrict gain = st->gain;
+ register spx_word32_t * restrict old_ps = st->old_ps;
+ register spx_word16_t * restrict post = st->post;
+ register spx_word16_t * restrict gain2 = st->gain2;
+ register int i;
+ register int N=st->ps_size;
+
+ for ( i=N ; i<NM ; ++i )
+ {
+ register spx_word32_t theta;
+ register spx_word32_t MM;
+ register spx_word16_t prior_ratio;
+ register spx_word16_t P1;
+ register spx_word16_t q;
+
+#ifdef FIXED_POINT
+ register spx_word16_t tmp;
+#endif
+ register spx_word16_t priori = prior[i];
+
+ prior_ratio = PDIV32_16(SHL32(EXTEND32(priori), 15), ADD16(priori, SHL32(1,SNR_SHIFT)));
+ theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(post[i]),EXPIN_SHIFT-SNR_SHIFT));
+
+ MM = hypergeom_gain(theta);
+ gain[i] = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM)));
+ old_ps[i] = MULT16_32_P15(QCONST16(.2f,15),old_ps[i]) + MULT16_32_P15(MULT16_16_P15(QCONST16(.8f,15),SQR16_Q15(gain[i])),ps[i]);
+
+ P1 = QCONST16(.199f,15)+MULT16_16_Q15(QCONST16(.8f,15),qcurve (zeta[i]));
+ q = Q15_ONE-MULT16_16_Q15(Pframe,P1);
+
+#ifdef FIXED_POINT
+ theta = MIN32(theta, EXTEND32(32767));
+ tmp = MULT16_16_Q15((SHL32(1,SNR_SHIFT)+priori),EXTRACT16(MIN32(Q15ONE,SHR32(spx_exp(-EXTRACT16(theta)),1))));
+ tmp = MIN16(QCONST16(3.,SNR_SHIFT), tmp);
+ tmp = EXTRACT16(PSHR32(MULT16_16(PDIV32_16(SHL32(EXTEND32(q),8),(Q15_ONE-q)),tmp),8));
+ gain2[i]=DIV32_16(SHL32(EXTEND32(32767),SNR_SHIFT), ADD16(256,tmp));
+#else
+ gain2[i]=1/(1.f + (q/(1.f-q))*(1+priori)*exp(-theta));
+#endif
+ }
+
+ filterbank_compute_psd16(st->bank,gain2+N, gain2);
+ filterbank_compute_psd16(st->bank,gain+N, gain);
+}
+
+void preprocess_compute_linear_gain(
+ SpeexPreprocessState * restrict st,
+ spx_word32_t * restrict ps,
+ int N
+)
+{
+ register spx_word16_t * restrict gain_floor = st->gain_floor;
+ register spx_word16_t * restrict prior = st->prior;
+ register spx_word16_t * restrict gain = st->gain;
+ register spx_word32_t * restrict old_ps = st->old_ps;
+ register spx_word16_t * restrict post = st->post;
+ register spx_word16_t * restrict gain2 = st->gain2;
+ register int i;
+
+ filterbank_compute_psd16(st->bank,gain_floor+N,gain_floor);
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for (i=0;i<N;i++)
+ {
+ register spx_word32_t MM;
+ register spx_word32_t theta;
+ register spx_word16_t prior_ratio;
+ register spx_word16_t tmp;
+ register spx_word16_t p;
+ register spx_word16_t g;
+ register spx_word16_t gfi = gain_floor[i];
+
+ prior_ratio = PDIV32_16(SHL32(EXTEND32(st->prior[i]), 15), ADD16(prior[i], SHL32(1,SNR_SHIFT)));
+ theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(post[i]),EXPIN_SHIFT-SNR_SHIFT));
+ MM = hypergeom_gain(theta);
+
+ g = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM)));
+ p = gain2[i];
+
+ g = VMUX( MULT16_16_Q15(QCONST16(.333f,15),g) > gain[i], MULT16_16(3,gain[i]), g);
+
+ old_ps[i]= MULT16_32_P15(QCONST16(.2f,15),old_ps[i]) +
+ MULT16_32_P15(MULT16_16_P15(QCONST16(.8f,15),SQR16_Q15(g)),ps[i]);
+
+ g = VMUX( g < gfi, gfi, g );
+ gain[i] = g;
+
+ tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(g),15))) +
+ MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(gfi),15)));
+
+ gain2[i]=SQR16_Q15(tmp);
+
+ /* Use this if you want a log-domain MMSE estimator instead */
+ /* gain2[i] = pow(g, p) * pow(gfi,1.f-p);*/
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+}
+
+
+#if 0
+void preprocess_compute_bark_gain(
+ SpeexPreprocessState * restrict st,
+ int N,
+ int NM
+)
+{
+ register spx_word16_t * restrict gain_floor = st->gain_floor;
+ register spx_word16_t * restrict gain = st->gain;
+ register spx_word16_t * restrict gain2 = st->gain2;
+ register int i;
+
+ for (i=N;i<NM;i++)
+ {
+ register spx_word16_t tmp;
+ register spx_word16_t p = gain2[i];
+ register spx_word16_t gaini;
+ register spx_word16_t gfi = gain_floor[i];
+
+ gaini = MAX16(gain[i], gfi);
+
+ gain[i] = gaini;
+
+ tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(gaini),15))) +
+ MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(gfi),15)));
+
+ gain2[i]=SQR16_Q15(tmp);
+ }
+
+ filterbank_compute_psd16(st->bank,gain2+N, gain2);
+}
+#endif
+
+void preprocess_apply_gain(
+ SpeexPreprocessState * restrict st,
+ int N
+)
+{
+ register spx_word16_t * restrict ft = st->ft;
+ register spx_word16_t * restrict gain2 = st->gain2;
+ register int j, i;
+
+ ft[0] = MULT16_16_P15(gain2[0],ft[0]);
+
+ for (i=1,j=1; i<N ; i++,j+=2)
+ {
+ register spx_word16_t gain2i = gain2[i];
+ register spx_word16_t ftj = ft[j];
+ register spx_word16_t ftjj = ft[j+1];
+
+ ft[j] = MULT16_16_P15(gain2i,ftj);
+ ft[j+1] = MULT16_16_P15(gain2i,ftjj);
+ }
+
+ ft[(N<<1)-1] = MULT16_16_P15(gain2[N-1],ft[(N<<1)-1]);
+}
+
+#ifdef FIXED_POINT
+void preprocess_scale(
+ SpeexPreprocessState * restrict st,
+ int N
+)
+{
+ register spx_word16_t * restrict frame = st->frame;
+ register int shift = st->frame_shift;
+ register int i;
+ register int N2 = N << 1;
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<N2 ;i++)
+ { register spx_word16_t framei = frame[i];
+
+ frame[i] = PSHR16(framei,shift);
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+}
+
+#else
+
+void preprocess_apply_agc(
+ SpeexPreprocessState * restrict st,
+ int N
+)
+{
+ register spx_word16_t max_sample=0;
+ register spx_word16_t * restrict frame = st->frame;
+ register int i;
+ register int N2 = N << 1;
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for (i=0;i<N2;i++)
+ { register spx_word16_t framei = VABS(frame[i]);
+
+ max_sample = VMUX( framei > max_sample, framei, max_sample);
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ if ( max_sample > 28000.f )
+ {
+ float damp = 28000.f/max_sample;
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i< N2 ; i++ )
+ { frame[i] *= damp;
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ }
+}
+#endif
+
+
+void preprocess_update(
+ SpeexPreprocessState * restrict st,
+ spx_int16_t * restrict x,
+ int N
+)
+{
+ register spx_word16_t * restrict frame = st->frame;
+ register spx_word16_t * restrict window = st->window;
+ register spx_word16_t * restrict outbuf = st->outbuf;
+ register int framesize = st->frame_size;
+ register int N2 = N << 1;
+ register int N3 = N2 - framesize;
+ register int N4 = (framesize) - N3;
+ register int i;
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<N2 ; i++)
+ { register spx_word16_t fi = frame[i];
+ register spx_word16_t wi = window[i];
+
+ frame[i] = MULT16_16_Q15(fi, wi);
+ }
+ for (i=0;i<N3;i++)
+ { x[i] = outbuf[i] + frame[i];
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+ for ( i=0;i<N4;i++)
+ { x[N3+i] = frame[N3+i];
+ }
+
+ memcpy(outbuf, frame+framesize, (N3) * sizeof(spx_word16_t));
+}
+
+#define OVERRIDE_SPEEX_PREPROCESS_RUN
+int speex_preprocess_run(SpeexPreprocessState * restrict st, spx_int16_t * restrict x)
+{
+ register int i, N, M, NM;
+ register spx_word32_t * restrict ps=st->ps;
+ register spx_word32_t Zframe;
+ register spx_word16_t Pframe;
+
+ st->nb_adapt++;
+ st->min_count++;
+ N = st->ps_size;
+ M = st->nbands;
+ NM = N + M;
+
+ preprocess_residue_echo(st, N, NM);
+ preprocess_analysis(st, x);
+ update_noise_prob(st);
+ preprocess_update_noise(st, ps, N);
+
+ if ( st->nb_adapt == 1 )
+ { memcpy(st->old_ps, ps, (NM) * sizeof(spx_word32_t));
+ }
+
+ preprocess_compute_SNR(st, ps, NM);
+ Zframe = preprocess_smooth_SNR(st, N, NM);
+
+
+ {
+ register spx_word16_t effective_echo_suppress;
+
+ Pframe = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.899f,15),qcurve(DIV32_16(Zframe,M)));
+ effective_echo_suppress = EXTRACT16(PSHR32(ADD32(MULT16_16(SUB16(Q15_ONE,Pframe), st->echo_suppress),
+ MULT16_16(Pframe, st->echo_suppress_active)),15));
+ compute_gain_floor(st->noise_suppress, effective_echo_suppress, st->noise+N, st->echo_noise+N, st->gain_floor+N, M);
+
+ }
+
+ preprocess_compute_emgain(st, ps, Pframe, NM);
+ preprocess_compute_linear_gain(st, ps, N);
+
+
+ if (!st->denoise_enabled)
+ {
+ register spx_word16_t * restrict gain2 = st->gain2;
+
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0 ; i<NM ; i++ )
+ { gain2[i] = Q15_ONE;
+ }
+#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+ }
+
+ preprocess_apply_gain(st, N);
+
+#ifndef FIXED_POINT
+ if (st->agc_enabled)
+ { speex_compute_agc(st, Pframe, st->ft);
+ }
+#endif
+
+
+ spx_ifft(st->fft_lookup, st->ft, st->frame);
+
+#ifdef FIXED_POINT
+ preprocess_scale(st, N);
+#endif
+
+#ifndef FIXED_POINT
+ if ( st->agc_enabled )
+ { preprocess_apply_agc(st, N);
+ }
+#endif
+
+ preprocess_update(st, x, N);
+
+ if ( st->vad_enabled )
+ {
+ if (Pframe > st->speech_prob_start || (st->was_speech && Pframe > st->speech_prob_continue))
+ { st->was_speech=1;
+ return 1;
+
+ } else
+ { st->was_speech=0;
+ return 0;
+ }
+ } else
+ { return 1;
+ }
+}
diff --git a/tmv/profile_tm.h b/tmv/profile_tm.h new file mode 100644 index 0000000..8588e26 --- /dev/null +++ b/tmv/profile_tm.h @@ -0,0 +1,407 @@ +/* Copyright (C) 2007 Hong Zhiqian */
+/**
+ @file profile_tm.h
+ @author Hong Zhiqian
+ @brief Various compatibility routines for Speex (TriMedia version)
+*/
+/*
+ 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 the Xiph.org Foundation 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 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.
+*/
+/**
+* @remarks This file provide some capabilities to measure clock cycles.
+* Use this if unable to compile with TriMedia profile options
+*/
+
+extern int __profile_begin;
+extern int __profile_end;
+
+#if TM_PROFILE
+#define PROFILE_START() \
+ { \
+ __profile_begin = cycles(); \
+ } \
+
+#define PROFILE_STOP() \
+ { \
+ __profile_end = cycles(); \
+ printf("%s\t%d\n", __FUNCTION__, end - begin); \
+ } \
+
+#else
+#define PROFILE_START()
+#define PROFILE_STOP()
+#endif
+
+#if TM_PROFILE_SPXAUTOCORR
+#define _SPX_AUTOCORR_START() PROFILE_START()
+#define _SPX_AUTOCORR_STOP() PROFILE_STOP()
+#else
+#define _SPX_AUTOCORR_START()
+#define _SPX_AUTOCORR_STOP()
+#endif
+
+#if TM_PROFILE_INNERPROD
+#define INNERPROD_START() PROFILE_START()
+#define INNERPROD_STOP() PROFILE_STOP()
+#else
+#define INNERPROD_START()
+#define INNERPROD_STOP()
+#endif
+
+#if TM_PROFILE_PITCHXCORR
+#define PITCHXCORR_START() PROFILE_START()
+#define PITCHXCORR_STOP() PROFILE_STOP()
+#else
+#define PITCHXCORR_START()
+#define PITCHXCORR_STOP()
+#endif
+
+#if TM_PROFILE_COMPUTEPITCHERROR
+#define COMPUTEPITCHERROR_START() PROFILE_START()
+#define COMPUTEPITCHERROR_STOP() PROFILE_STOP()
+#else
+#define COMPUTEPITCHERROR_START()
+#define COMPUTEPITCHERROR_STOP()
+#endif
+
+#if TM_PROFILE_PITCHGAINSEARCH3TAPVQ
+#define PITCHGAINSEARCH3TAPVQ_START() PROFILE_START()
+#define PITCHGAINSEARCH3TAPVQ_STOP() PROFILE_STOP()
+#else
+#define PITCHGAINSEARCH3TAPVQ_START()
+#define PITCHGAINSEARCH3TAPVQ_STOP()
+#endif
+
+#if TM_PROFILE_OPENLOOPNBESTPITCH
+#define OPENLOOPNBESTPITCH_START() PROFILE_START()
+#define OPENLOOPNBESTPITCH_STOP() PROFILE_STOP()
+#else
+#define OPENLOOPNBESTPITCH_START()
+#define OPENLOOPNBESTPITCH_STOP()
+#endif
+
+
+#if TM_PROFILE_LSP_INTERPOLATE
+#define LSPINTERPOLATE_START() PROFILE_START()
+#define LSPINTERPOLATE_STOP() PROFILE_STOP()
+#else
+#define LSPINTERPOLATE_START()
+#define LSPINTERPOLATE_STOP()
+#endif
+
+#if TM_PROFILE_CHEBPOLYEVA
+#define CHEBPOLYEVA_START() PROFILE_START()
+#define CHEBPOLYEVA_STOP() PROFILE_STOP()
+#else
+#define CHEBPOLYEVA_START()
+#define CHEBPOLYEVA_STOP()
+#endif
+
+
+#if TM_PROFILE_COMPUTEQUANTWEIGHTS
+#define COMPUTEQUANTWEIGHTS_START() PROFILE_START()
+#define COMPUTEQUANTWEIGHTS_STOP() PROFILE_STOP()
+#else
+#define COMPUTEQUANTWEIGHTS_START()
+#define COMPUTEQUANTWEIGHTS_STOP()
+#endif
+
+#if TM_PROFILE_LSPQUANT
+#define LSPQUANT_START() PROFILE_START()
+#define LSPQUANT_STOP() PROFILE_STOP()
+#else
+#define LSPQUANT_START()
+#define LSPQUANT_STOP()
+#endif
+
+#if TM_PROFILE_LSPWEIGHTQUANT
+#define LSPWEIGHTQUANT_START() PROFILE_START()
+#define LSPWEIGHTQUANT_STOP() PROFILE_STOP()
+#else
+#define LSPWEIGHTQUANT_START()
+#define LSPWEIGHTQUANT_STOP()
+#endif
+
+#if TM_PROFILE_FIRMEM16
+#define FIRMEM16_START() PROFILE_START()
+#define FIRMEM16_STOP() PROFILE_STOP()
+#else
+#define FIRMEM16_START()
+#define FIRMEM16_STOP()
+#endif
+
+#if TM_PROFILE_IIRMEM16
+#define IIRMEM16_START() PROFILE_START()
+#define IIRMEM16_STOP() PROFILE_STOP()
+#else
+#define IIRMEM16_START()
+#define IIRMEM16_STOP()
+#endif
+
+#if TM_PROFILE_FILTERMEM16
+#define FILTERMEM16_START() PROFILE_START()
+#define FILTERMEM16_STOP() PROFILE_STOP()
+#else
+#define FILTERMEM16_START()
+#define FILTERMEM16_STOP()
+#endif
+
+#if TM_PROFILE_COMPUTERMS16
+#define COMPUTERMS16_START() PROFILE_START()
+#define COMPUTERMS16_STOP() PROFILE_STOP()
+#else
+#define COMPUTERMS16_START()
+#define COMPUTERMS16_STOP()
+#endif
+
+#if TM_PROFILE_NORMALIZE16
+#define NORMALIZE16_START() PROFILE_START()
+#define NORMALIZE16_STOP() PROFILE_STOP()
+#else
+#define NORMALIZE16_START()
+#define NORMALIZE16_STOP()
+#endif
+
+#if TM_PROFILE_BWLPC
+#define BWLPC_START() PROFILE_START()
+#define BWLPC_STOP() PROFILE_STOP()
+#else
+#define BWLPC_START()
+#define BWLPC_STOP()
+#endif
+
+#if TM_PROFILE_HIGHPASS
+#define HIGHPASS_START() PROFILE_START()
+#define HIGHPASS_STOP() PROFILE_STOP()
+#else
+#define HIGHPASS_START()
+#define HIGHPASS_STOP()
+#endif
+
+#if TM_PROFILE_SIGNALMUL
+#define SIGNALMUL_START() PROFILE_START()
+#define SIGNALMUL_STOP() PROFILE_STOP()
+#else
+#define SIGNALMUL_START()
+#define SIGNALMUL_STOP()
+#endif
+
+#if TM_PROFILE_SIGNALDIV
+#define SIGNALDIV_START() PROFILE_START()
+#define SIGNALDIV_STOP() PROFILE_STOP()
+#else
+#define SIGNALDIV_START()
+#define SIGNALDIV_STOP()
+#endif
+
+#if TM_PROFILE_COMPUTEIMPULSERESPONSE
+#define COMPUTEIMPULSERESPONSE_START() PROFILE_START()
+#define COMPUTEIMPULSERESPONSE_STOP() PROFILE_STOP()
+#else
+#define COMPUTEIMPULSERESPONSE_START()
+#define COMPUTEIMPULSERESPONSE_STOP()
+#endif
+
+#if TM_PROFILE_COMPUTEWEIGHTEDCODEBOOK
+#define COMPUTEWEIGHTEDCODEBOOK_START() PROFILE_START()
+#define COMPUTEWEIGHTEDCODEBOOK_STOP() PROFILE_STOP()
+#else
+#define COMPUTEWEIGHTEDCODEBOOK_START()
+#define COMPUTEWEIGHTEDCODEBOOK_STOP()
+#endif
+
+#if TM_PROFILE_TARGETUPDATE
+#define TARGETUPDATE_START() PROFILE_START()
+#define TARGETUPDATE_STOP() PROFILE_STOP()
+#else
+#define TARGETUPDATE_START()
+#define TARGETUPDATE_STOP()
+#endif
+
+
+#if TM_PROFILE_VQNBEST
+#define VQNBEST_START() PROFILE_START()
+#define VQNBEST_STOP() PROFILE_STOP()
+#else
+#define VQNBEST_START()
+#define VQNBEST_STOP()
+#endif
+
+#if TM_PROFILE_VQNBESTSIGN
+#define VQNBESTSIGN_START() PROFILE_START()
+#define VQNBESTSIGN_STOP() PROFILE_STOP()
+#else
+#define VQNBESTSIGN_START()
+#define VQNBESTSIGN_STOP()
+#endif
+
+#if TM_PROFILE_PREPROCESSANALYSIS
+#define PREPROCESSANAYLSIS_START() PROFILE_START()
+#define PREPROCESSANAYLSIS_STOP() PROFILE_STOP()
+#else
+#define PREPROCESSANAYLSIS_START()
+#define PREPROCESSANAYLSIS_STOP()
+#endif
+
+#if TM_PROFILE_UPDATENOISEPROB
+#define UPDATENOISEPROB_START() PROFILE_START()
+#define UPDATENOISEPROB_STOP() PROFILE_STOP()
+#else
+#define UPDATENOISEPROB_START()
+#define UPDATENOISEPROB_STOP()
+#endif
+
+#if TM_PROFILE_COMPUTEGAINFLOOR
+#define COMPUTEGAINFLOOR_START() PROFILE_START()
+#define COMPUTEGAINFLOOR_STOP() PROFILE_STOP()
+#else
+#define COMPUTEGAINFLOOR_START()
+#define COMPUTEGAINFLOOR_STOP()
+#endif
+
+#if TM_PROFILE_FILTERDCNOTCH16
+#define FILTERDCNOTCH16_START() PROFILE_START()
+#define FILTERDCNOTCH16_STOP() PROFILE_STOP()
+#else
+#define FILTERDCNOTCH16_START()
+#define FILTERDCNOTCH16_STOP()
+#endif
+
+#if TM_PROFILE_MDFINNERPROD
+#define MDFINNERPROD_START() PROFILE_START()
+#define MDFINNERPROD_STOP() PROFILE_STOP()
+#else
+#define MDFINNERPROD_START()
+#define MDFINNERPROD_STOP()
+#endif
+
+#if TM_PROFILE_SPECTRALMULACCUM
+#define SPECTRALMULACCUM_START() PROFILE_START()
+#define SPECTRALMULACCUM_STOP() PROFILE_STOP()
+#else
+#define SPECTRALMULACCUM_START()
+#define SPECTRALMULACCUM_STOP()
+#endif
+
+#if TM_PROFILE_WEIGHTEDSPECTRALMULCONJ
+#define WEIGHTEDSPECTRALMULCONJ_START() PROFILE_START()
+#define WEIGHTEDSPECTRALMULCONJ_STOP() PROFILE_STOP()
+#else
+#define WEIGHTEDSPECTRALMULCONJ_START()
+#define WEIGHTEDSPECTRALMULCONJ_STOP()
+#endif
+
+#if TM_PROFILE_MDFADJUSTPROP
+#define MDFADJUSTPROP_START() PROFILE_START()
+#define MDFADJUSTPROP_STOP() PROFILE_STOP()
+#else
+#define MDFADJUSTPROP_START()
+#define MDFADJUSTPROP_STOP()
+#endif
+
+#if TM_PROFILE_SPEEXECHOGETRESIDUAL
+#define SPEEXECHOGETRESIDUAL_START() PROFILE_START()
+#define SPEEXECHOGETRESIDUAL_STOP() PROFILE_STOP()
+#else
+#define SPEEXECHOGETRESIDUAL_START()
+#define SPEEXECHOGETRESIDUAL_STOP()
+#endif
+
+#if TM_PROFILE_LSPENFORCEMARGIN
+#define LSPENFORCEMARGIN_START() PROFILE_START()
+#define LSPENFORCEMARGIN_STOP() PROFILE_STOP()
+#else
+#define LSPENFORCEMARGIN_START()
+#define LSPENFORCEMARGIN_STOP()
+#endif
+
+#if TM_PROFILE_LSPTOLPC
+#define LSPTOLPC_START() PROFILE_START()
+#define LSPTOLPC_STOP() PROFILE_STOP()
+#else
+#define LSPTOLPC_START()
+#define LSPTOLPC_STOP()
+#endif
+
+#if TM_PROFILE_MAXIMIZERANGE
+#define MAXIMIZERANGE_START() PROFILE_START()
+#define MAXIMIZERANGE_STOP() PROFILE_STOP()
+#else
+#define MAXIMIZERANGE_START()
+#define MAXIMIZERANGE_STOP()
+#endif
+
+#if TM_PROFILE_RENORMRANGE
+#define RENORMRANGE_START() PROFILE_START()
+#define RENORMRANGE_STOP() PROFILE_STOP()
+#else
+#define RENORMRANGE_START()
+#define RENORMRANGE_STOP()
+#endif
+
+#if TM_PROFILE_POWERSPECTRUM
+#define POWERSPECTRUM_START() PROFILE_START()
+#define POWERSPECTRUM_STOP() PROFILE_STOP()
+#else
+#define POWERSPECTRUM_START()
+#define POWERSPECTRUM_STOP()
+#endif
+
+#if TM_PROFILE_QMFSYNTH
+#define QMFSYNTH_START() PROFILE_START()
+#define QMFSYNTH_STOP() PROFILE_STOP()
+#else
+#define QMFSYNTH_START()
+#define QMFSYNTH_STOP()
+#endif
+
+#if TM_PROFILE_QMFDECOMP
+#define QMFDECOMP_START() PROFILE_START()
+#define QMFDECOMP_STOP() PROFILE_STOP()
+#else
+#define QMFDECOMP_START()
+#define QMFDECOMP_STOP()
+#endif
+
+#if TM_PROFILE_FILTERBANKCOMPUTEBANK32
+#define FILTERBANKCOMPUTEBANK32_START() PROFILE_START()
+#define FILTERBANKCOMPUTEBANK32_STOP() PROFILE_STOP()
+#else
+#define FILTERBANKCOMPUTEBANK32_START()
+#define FILTERBANKCOMPUTEBANK32_STOP()
+#endif
+
+#if TM_PROFILE_FILTERBANKCOMPUTEPSD16
+#define FILTERBANKCOMPUTEPSD16_START() PROFILE_START()
+#define FILTERBANKCOMPUTEPSD16_STOP() PROFILE_STOP()
+#else
+#define FILTERBANKCOMPUTEPSD16_START()
+#define FILTERBANKCOMPUTEPSD16_STOP()
+#endif
+
+
diff --git a/tmv/quant_lsp_tm.h b/tmv/quant_lsp_tm.h new file mode 100644 index 0000000..e704eae --- /dev/null +++ b/tmv/quant_lsp_tm.h @@ -0,0 +1,448 @@ +/* Copyright (C) 2007 Hong Zhiqian */
+/**
+ @file quant_lsp_tm.h
+ @author Hong Zhiqian
+ @brief Various compatibility routines for Speex (TriMedia version)
+*/
+/*
+ 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 the Xiph.org Foundation 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 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.
+*/
+#include <ops/custom_defs.h>
+#include "profile_tm.h"
+
+#ifdef FIXED_POINT
+
+#define OVERRIDE_COMPUTE_QUANT_WEIGHTS
+static void compute_quant_weights(Int16 *qlsp, Int16 *qw, int order)
+{
+ int qlspi, qlspii;
+ int w1, w2;
+ int i;
+
+ TMDEBUG_ALIGNMEM(qlsp);
+ TMDEBUG_ALIGNMEM(qw);
+
+ COMPUTEQUANTWEIGHTS_START();
+
+ --order;
+
+ qlspi = (int)qlsp[0];
+ qlspii = (int)qlsp[1];
+ w1 = qlspi;
+ w2 = qlspii - qlspi;
+
+ qw[0] = 81920 / (300 + imin(w1,w2));
+
+ for ( i=1 ; i<order ; ++i )
+ { qlspi = qlspii;
+ qlspii = qlsp[i+1];
+
+ w1 = w2;
+ w2 = qlspii - qlspi;
+
+ qw[i] = 81920 / (300 + imin(w1,w2));
+ }
+
+ w1 = LSP_PI - qlspii;
+ qw[i] = 81920 / (300 + imin(w1,w2));
+
+ COMPUTEQUANTWEIGHTS_STOP();
+}
+
+
+
+#define OVERRIDE_LSP_QUANT
+static int lsp_quant(Int16 *x, const signed char *cdbk, int nbVec, int nbDim)
+{
+ register int best_dist=VERY_LARGE32;
+ register int best_id=0;
+ register int i, j;
+ register int dt0, dt1, dt2, dt3;
+ register int cb0, cb1, cb2, cb3, xx;
+ register int ptr_inc = nbDim * 3;
+ register int five = 5;
+ const signed char *ptr;
+
+ TMDEBUG_ALIGNMEM(x);
+
+ LSPQUANT_START();
+
+ for ( i=0, ptr=cdbk ; i<nbVec ; i+=4, ptr += ptr_inc )
+ { dt3 = dt2 = dt1 = dt0 = 0;
+
+ for ( j=0 ; j <nbDim ; j += 2 )
+ {
+ xx = ld32x(x,j>>1);
+ cb0 = pack16lsb((int)ptr[1], (int)ptr[0]);
+ cb0 = dualasl(cb0,five);
+ cb0 = dspidualsub(xx,cb0);
+ dt0 += ifir16(cb0,cb0);
+
+ cb1 = pack16lsb((int)ptr[nbDim+1], (int)ptr[nbDim]);
+ cb1 = dualasl(cb1,five);
+ cb1 = dspidualsub(xx,cb1);
+ dt1 += ifir16(cb1, cb1);
+
+ cb2 = pack16lsb((int)ptr[nbDim*2+1], (int)ptr[nbDim*2]);
+ cb2 = dualasl(cb2,five);
+ cb2 = dspidualsub(xx,cb2);
+ dt2 += ifir16(cb2, cb2);
+
+ cb3 = pack16lsb((int)ptr[nbDim*3+1], (int)ptr[nbDim*3]);
+ cb3 = dualasl(cb3,five);
+ cb3 = dspidualsub(xx,cb3);
+ dt3 += ifir16(cb3, cb3);
+
+ ptr += 2;
+ }
+
+ if ( dt0<best_dist )
+ { best_dist = dt0;
+ best_id = i;
+ }
+
+ if ( dt1<best_dist )
+ { best_dist = dt1;
+ best_id = i+1;
+ }
+
+ if ( dt2<best_dist )
+ { best_dist = dt2;
+ best_id = i+2;
+ }
+
+ if ( dt3<best_dist )
+ { best_dist = dt3;
+ best_id = i+3;
+ }
+ }
+
+ for ( j=0,ptr=cdbk+best_id*nbDim ; j<nbDim ; j+=2 )
+ { xx = ld32x(x,j>>1);
+ cb0 = pack16lsb((int)ptr[j+1], (int)ptr[j]);
+ cb0 = dualasl(cb0,five);
+ dt0 = dspidualsub(xx,cb0);
+ st32d(j<<1, x, dt0);
+ }
+
+ LSPQUANT_STOP();
+ return best_id;
+}
+
+
+#define OVERRIDE_LSP_WEIGHT_QUANT
+static int lsp_weight_quant(Int16 *x, Int16 *weight, const signed char *cdbk, int nbVec, int nbDim)
+{
+ register int best_dist=VERY_LARGE32;
+ register int best_id=0;
+ register int i, j;
+ register int dt1, dt2, dt3, dt4;
+ register int cb1, cb2, cb3, cb4, wt, xx;
+ register int ptr_inc = nbDim * 3;
+ const signed char *ptr;
+
+ LSPWEIGHTQUANT_START();
+
+ for ( i=0, ptr=cdbk ; i<nbVec ; i+=4, ptr += ptr_inc )
+ { dt4 = dt3 = dt2 = dt1 = 0;
+
+ for ( j=0 ; j<nbDim ; ++j )
+ { wt = weight[j];
+ xx = x[j];
+
+ cb1 = xx - (ptr[0] << 5);
+ cb2 = xx - (ptr[nbDim] << 5);
+ cb3 = xx - (ptr[nbDim*2] << 5);
+ cb4 = xx - (ptr[nbDim*3] << 5);
+
+ ++ptr;
+
+ cb1 *= cb1;
+ cb2 *= cb2;
+ cb3 *= cb3;
+ cb4 *= cb4;
+
+ dt1 += (wt * (cb1 >> 15)) + ((wt * (cb1 & 0x7fff)) >> 15);
+ dt2 += (wt * (cb2 >> 15)) + ((wt * (cb2 & 0x7fff)) >> 15);
+ dt3 += (wt * (cb3 >> 15)) + ((wt * (cb3 & 0x7fff)) >> 15);
+ dt4 += (wt * (cb4 >> 15)) + ((wt * (cb4 & 0x7fff)) >> 15);
+
+ }
+
+ if ( dt1<best_dist )
+ { best_dist = dt1;
+ best_id = i;
+ }
+
+ if ( dt2<best_dist )
+ { best_dist = dt2;
+ best_id = i+1;
+ }
+
+ if ( dt3<best_dist )
+ { best_dist = dt3;
+ best_id = i+2;
+ }
+
+ if ( dt4<best_dist )
+ { best_dist = dt4;
+ best_id = i+3;
+ }
+ }
+
+ for ( j=0 ; j<nbDim ; ++j )
+ { x[j] = x[j] - ((Int16)cdbk[best_id*nbDim+j] << 5);
+ }
+
+ LSPWEIGHTQUANT_STOP();
+
+ return best_id;
+}
+
+#if 0
+// TODO: unroll loops
+#define OVERRIDE_LSP_QUANT_NB
+void lsp_quant_nb(spx_lsp_t *lsp, spx_lsp_t *qlsp, int order, SpeexBits *bits)
+{
+ int i;
+ int id;
+ spx_word16_t quant_weight[10];
+
+ for (i=0;i<order;i++)
+ qlsp[i]=lsp[i];
+
+ compute_quant_weights(qlsp, quant_weight, order);
+
+ for (i=0;i<order;i++)
+ qlsp[i]=SUB16(qlsp[i],LSP_LINEAR(i));
+
+#ifndef FIXED_POINT
+ for (i=0;i<order;i++)
+ qlsp[i] = LSP_SCALE*qlsp[i];
+#endif
+ id = lsp_quant(qlsp, cdbk_nb, NB_CDBK_SIZE, order);
+ speex_bits_pack(bits, id, 6);
+
+ for (i=0;i<order;i++)
+ qlsp[i]*=2;
+
+ id = lsp_weight_quant(qlsp, quant_weight, cdbk_nb_low1, NB_CDBK_SIZE_LOW1, 5);
+ speex_bits_pack(bits, id, 6);
+
+ for (i=0;i<5;i++)
+ qlsp[i]*=2;
+
+ id = lsp_weight_quant(qlsp, quant_weight, cdbk_nb_low2, NB_CDBK_SIZE_LOW2, 5);
+ speex_bits_pack(bits, id, 6);
+
+ id = lsp_weight_quant(qlsp+5, quant_weight+5, cdbk_nb_high1, NB_CDBK_SIZE_HIGH1, 5);
+ speex_bits_pack(bits, id, 6);
+
+ for (i=5;i<10;i++)
+ qlsp[i]*=2;
+
+ id = lsp_weight_quant(qlsp+5, quant_weight+5, cdbk_nb_high2, NB_CDBK_SIZE_HIGH2, 5);
+ speex_bits_pack(bits, id, 6);
+
+#ifdef FIXED_POINT
+ for (i=0;i<order;i++)
+ qlsp[i]=PSHR16(qlsp[i],2);
+#else
+ for (i=0;i<order;i++)
+ qlsp[i]=qlsp[i] * .00097656;
+#endif
+
+ for (i=0;i<order;i++)
+ qlsp[i]=lsp[i]-qlsp[i];
+}
+
+
+#define OVERRIDE_LSP_UNQUANT_NB
+void lsp_unquant_nb(spx_lsp_t *lsp, int order, SpeexBits *bits)
+{
+ int i, id;
+ for (i=0;i<order;i++)
+ lsp[i]=LSP_LINEAR(i);
+
+ id=speex_bits_unpack_unsigned(bits, 6);
+ for (i=0;i<10;i++)
+ lsp[i] = ADD32(lsp[i], LSP_DIV_256(cdbk_nb[id*10+i]));
+
+ id=speex_bits_unpack_unsigned(bits, 6);
+ for (i=0;i<5;i++)
+ lsp[i] = ADD16(lsp[i], LSP_DIV_512(cdbk_nb_low1[id*5+i]));
+
+ id=speex_bits_unpack_unsigned(bits, 6);
+ for (i=0;i<5;i++)
+ lsp[i] = ADD32(lsp[i], LSP_DIV_1024(cdbk_nb_low2[id*5+i]));
+
+ id=speex_bits_unpack_unsigned(bits, 6);
+ for (i=0;i<5;i++)
+ lsp[i+5] = ADD32(lsp[i+5], LSP_DIV_512(cdbk_nb_high1[id*5+i]));
+
+ id=speex_bits_unpack_unsigned(bits, 6);
+ for (i=0;i<5;i++)
+ lsp[i+5] = ADD32(lsp[i+5], LSP_DIV_1024(cdbk_nb_high2[id*5+i]));
+}
+
+#define OVERRIDE_LSP_QUANT_LBR
+void lsp_quant_lbr(spx_lsp_t *lsp, spx_lsp_t *qlsp, int order, SpeexBits *bits)
+{
+ int i;
+ int id;
+ spx_word16_t quant_weight[10];
+
+ for (i=0;i<order;i++)
+ qlsp[i]=lsp[i];
+
+ compute_quant_weights(qlsp, quant_weight, order);
+
+ for (i=0;i<order;i++)
+ qlsp[i]=SUB16(qlsp[i],LSP_LINEAR(i));
+#ifndef FIXED_POINT
+ for (i=0;i<order;i++)
+ qlsp[i]=qlsp[i]*LSP_SCALE;
+#endif
+ id = lsp_quant(qlsp, cdbk_nb, NB_CDBK_SIZE, order);
+ speex_bits_pack(bits, id, 6);
+
+ for (i=0;i<order;i++)
+ qlsp[i]*=2;
+
+ id = lsp_weight_quant(qlsp, quant_weight, cdbk_nb_low1, NB_CDBK_SIZE_LOW1, 5);
+ speex_bits_pack(bits, id, 6);
+
+ id = lsp_weight_quant(qlsp+5, quant_weight+5, cdbk_nb_high1, NB_CDBK_SIZE_HIGH1, 5);
+ speex_bits_pack(bits, id, 6);
+
+#ifdef FIXED_POINT
+ for (i=0;i<order;i++)
+ qlsp[i] = PSHR16(qlsp[i],1);
+#else
+ for (i=0;i<order;i++)
+ qlsp[i] = qlsp[i]*0.0019531;
+#endif
+
+ for (i=0;i<order;i++)
+ qlsp[i]=lsp[i]-qlsp[i];
+}
+
+#define OVERRIDE_LSP_UNQUANT_LBR
+void lsp_unquant_lbr(spx_lsp_t *lsp, int order, SpeexBits *bits)
+{
+ int i, id;
+ for (i=0;i<order;i++)
+ lsp[i]=LSP_LINEAR(i);
+
+
+ id=speex_bits_unpack_unsigned(bits, 6);
+ for (i=0;i<10;i++)
+ lsp[i] += LSP_DIV_256(cdbk_nb[id*10+i]);
+
+ id=speex_bits_unpack_unsigned(bits, 6);
+ for (i=0;i<5;i++)
+ lsp[i] += LSP_DIV_512(cdbk_nb_low1[id*5+i]);
+
+ id=speex_bits_unpack_unsigned(bits, 6);
+ for (i=0;i<5;i++)
+ lsp[i+5] += LSP_DIV_512(cdbk_nb_high1[id*5+i]);
+
+}
+
+extern const signed char high_lsp_cdbk[];
+extern const signed char high_lsp_cdbk2[];
+
+#define OVERRIDE_LSP_UNQUANT_HIGH
+void lsp_unquant_high(spx_lsp_t *lsp, int order, SpeexBits *bits)
+{
+
+ int i, id;
+ for (i=0;i<order;i++)
+ lsp[i]=LSP_LINEAR_HIGH(i);
+
+
+ id=speex_bits_unpack_unsigned(bits, 6);
+ for (i=0;i<order;i++)
+ lsp[i] += LSP_DIV_256(high_lsp_cdbk[id*order+i]);
+
+
+ id=speex_bits_unpack_unsigned(bits, 6);
+ for (i=0;i<order;i++)
+ lsp[i] += LSP_DIV_512(high_lsp_cdbk2[id*order+i]);
+}
+
+#define OVERRIDE_LSP_QUANT_HIGH
+void lsp_quant_high(spx_lsp_t *lsp, spx_lsp_t *qlsp, int order, SpeexBits *bits)
+{
+ int i;
+ int id;
+ spx_word16_t quant_weight[10];
+
+ for (i=0;i<order;i++)
+ qlsp[i]=lsp[i];
+
+ compute_quant_weights(qlsp, quant_weight, order);
+
+ /* quant_weight[0] = 10/(qlsp[1]-qlsp[0]);
+ quant_weight[order-1] = 10/(qlsp[order-1]-qlsp[order-2]);
+ for (i=1;i<order-1;i++)
+ {
+ tmp1 = 10/(qlsp[i]-qlsp[i-1]);
+ tmp2 = 10/(qlsp[i+1]-qlsp[i]);
+ quant_weight[i] = tmp1 > tmp2 ? tmp1 : tmp2;
+ }*/
+
+ for (i=0;i<order;i++)
+ qlsp[i]=SUB16(qlsp[i],LSP_LINEAR_HIGH(i));
+#ifndef FIXED_POINT
+ for (i=0;i<order;i++)
+ qlsp[i] = qlsp[i]*LSP_SCALE;
+#endif
+ id = lsp_quant(qlsp, high_lsp_cdbk, 64, order);
+ speex_bits_pack(bits, id, 6);
+
+ for (i=0;i<order;i++)
+ qlsp[i]*=2;
+
+ id = lsp_weight_quant(qlsp, quant_weight, high_lsp_cdbk2, 64, order);
+ speex_bits_pack(bits, id, 6);
+
+#ifdef FIXED_POINT
+ for (i=0;i<order;i++)
+ qlsp[i] = PSHR16(qlsp[i],1);
+#else
+ for (i=0;i<order;i++)
+ qlsp[i] = qlsp[i]*0.0019531;
+#endif
+
+ for (i=0;i<order;i++)
+ qlsp[i]=lsp[i]-qlsp[i];
+}
+#endif
+
+#endif
diff --git a/tmv/speex_config_types.h b/tmv/speex_config_types.h new file mode 100644 index 0000000..e63303f --- /dev/null +++ b/tmv/speex_config_types.h @@ -0,0 +1,31 @@ +#ifndef __SPEEX_TYPES_H__
+#define __SPEEX_TYPES_H__
+
+#ifdef __TCS__
+
+#include <tmNxTypes.h>
+
+
+
+typedef Int16 spx_int16_t;
+typedef UInt16 spx_uint16_t;
+typedef Int32 spx_int32_t;
+typedef UInt32 spx_uint32_t;
+
+#ifdef FIXED_POINT
+#define VMUX(a,b,c) mux((a),(b),(c))
+#define VABS(a) iabs((a))
+#define VMAX(a,b) imax((a),(b))
+#define VMIN(a,b) imin((a),(b))
+#else
+#define VMUX(a,b,c) fmux((a),(b),(c))
+#define VABS(a) fabs((a))
+#define VMAX(a,b) fmax((a),(b))
+#define VMIN(a,b) fmin((a),(b))
+#endif
+
+#endif
+
+
+#endif
+
diff --git a/tmv/vq_tm.h b/tmv/vq_tm.h new file mode 100644 index 0000000..c8c6109 --- /dev/null +++ b/tmv/vq_tm.h @@ -0,0 +1,494 @@ +/* Copyright (C) 2007 Hong Zhiqian */
+/**
+ @file vq_tm.h
+ @author Hong Zhiqian
+ @brief Various compatibility routines for Speex (TriMedia version)
+*/
+/*
+ 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 the Xiph.org Foundation 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 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.
+*/
+#include <ops/custom_defs.h>
+#include "profile_tm.h"
+
+#ifdef FIXED_POINT
+
+inline void vq_nbest_dist(int i, int N, int dist, int *used, int *nbest, Int32 *best_dist)
+{
+ register int k;
+
+ if (i<N || dist<best_dist[N-1])
+ {
+ for (k=N-1; (k >= 1) && (k > *used || dist < best_dist[k-1]); k--)
+ { best_dist[k]=best_dist[k-1];
+ nbest[k] = nbest[k-1];
+ }
+
+ best_dist[k]=dist;
+ nbest[k]=i;
+ *used++;
+ }
+}
+
+void vq_nbest_5(Int16 *in, const Int16 *codebook, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist)
+{
+ register int i, j;
+ register int in10, in32, in4;
+ int used = 0;
+
+ in10 = pack16lsb(in[1],in[0]); /* Note: memory is not align here */
+ in32 = pack16lsb(in[3],in[2]);
+ in4 = sex16(in[4]);
+
+#if (TM_UNROLL && TM_UNROLL_VQNBEST > 0)
+#pragma TCS_unroll=2
+#pragma TCS_unrollexact=1
+#endif
+
+ for ( i=0,j=0 ; i<entries ; i+=2,j+=5 )
+ {
+ register int dist1, dist2;
+ register int cb10, cb32, cb54, cb76, cb98, cb87, cb65;
+
+ cb10 = ld32x(codebook,j);
+ cb32 = ld32x(codebook,j+1);
+ cb54 = ld32x(codebook,j+2);
+ cb76 = ld32x(codebook,j+3);
+ cb98 = ld32x(codebook,j+4);
+
+ dist1 = sex16(cb54) * in4;
+ dist1 += ifir16(in10,cb10) + ifir16(in32,cb32);
+ dist1 = (E[i] >> 1) - dist1;
+
+ cb65 = funshift2(cb76,cb54);
+ cb87 = funshift2(cb98,cb76);
+ dist2 = asri(16,cb98) * in4;
+ dist2 += ifir16(in10,cb65) + ifir16(in32,cb87);
+ dist2 = (E[i+1] >> 1) - dist2;
+
+ vq_nbest_dist(i,N,dist1,&used,nbest,best_dist);
+ vq_nbest_dist(i+1,N,dist2,&used,nbest,best_dist);
+ }
+
+#if (TM_UNROLL && TM_UNROLL_VQNBEST > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+}
+
+
+void vq_nbest_8(Int16 *in, const Int16 *codebook, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist)
+{
+ register int i, j;
+ register int in10, in32, in54, in76;
+ int used = 0;
+
+ in10 = pack16lsb(in[1],in[0]); /* Note: memory is not align here */
+ in32 = pack16lsb(in[3],in[2]);
+ in54 = pack16lsb(in[5],in[4]);
+ in76 = pack16lsb(in[7],in[6]);
+
+#if (TM_UNROLL && TM_UNROLL_VQNBEST > 0)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0,j=0 ; i<entries ; ++i,j+=4 )
+ {
+ register int dist;
+ register int cb10, cb32, cb54, cb76;
+
+ cb10 = ld32x(codebook,j);
+ cb32 = ld32x(codebook,j+1);
+ cb54 = ld32x(codebook,j+2);
+ cb76 = ld32x(codebook,j+3);
+
+ dist = ifir16(in10,cb10) + ifir16(in32,cb32);
+ dist += ifir16(in54,cb54) + ifir16(in76,cb76);
+ dist = (E[i] >> 1) - dist;
+
+ vq_nbest_dist(i,N,dist,&used,nbest,best_dist);
+ }
+#if (TM_UNROLL && TM_UNROLL_VQNBEST > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+
+}
+
+
+void vq_nbest_10(Int16 *in, const Int16 *codebook, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist)
+{
+ register int i, j;
+ register int in10, in32, in54, in76, in98;
+ int used = 0;
+
+ in10 = pack16lsb(in[1],in[0]);
+ in32 = pack16lsb(in[3],in[2]);
+ in54 = pack16lsb(in[5],in[4]);
+ in76 = pack16lsb(in[7],in[6]);
+ in98 = pack16lsb(in[9],in[8]);
+
+#if (TM_UNROLL && TM_UNROLL_VQNBEST > 0)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0,j=0 ; i<entries ; ++i,j+=5 )
+ {
+ register int dist;
+ register int cb10, cb32, cb54, cb76, cb98;
+
+ cb10 = ld32x(codebook,j);
+ cb32 = ld32x(codebook,j+1);
+ cb54 = ld32x(codebook,j+2);
+ cb76 = ld32x(codebook,j+3);
+ cb98 = ld32x(codebook,j+4);
+
+ dist = ifir16(in10,cb10) + ifir16(in32,cb32);
+ dist += ifir16(in54,cb54) + ifir16(in76,cb76);
+ dist += ifir16(in98,cb98);
+ dist = (E[i] >> 1) - dist;
+
+ vq_nbest_dist(i,N,dist,&used,nbest,best_dist);
+ }
+#if (TM_UNROLL && TM_UNROLL_VQNBEST > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+}
+
+void vq_nbest_20(Int16 *in, const Int16 *codebook, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist)
+{
+ register int i, j;
+ register int in10, in32, in54, in76, in98, in_10, in_32, in_54, in_76, in_98;
+ int used = 0;
+
+ in10 = pack16lsb(in[1],in[0]); /* Note: memory is not align here */
+ in32 = pack16lsb(in[3],in[2]);
+ in54 = pack16lsb(in[5],in[4]);
+ in76 = pack16lsb(in[6],in[6]);
+ in98 = pack16lsb(in[9],in[8]);
+ in_10 = pack16lsb(in[11],in[10]);
+ in_32 = pack16lsb(in[13],in[12]);
+ in_54 = pack16lsb(in[15],in[14]);
+ in_76 = pack16lsb(in[17],in[16]);
+ in_98 = pack16lsb(in[19],in[18]);
+
+#if (TM_UNROLL && TM_UNROLL_VQNBEST > 0)
+#pragma TCS_unroll=2
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0,j=0 ; i<entries ; ++i,j+=10 )
+ {
+ register int dist;
+ register int cb10, cb32, cb54, cb76, cb98, cb_10, cb_32, cb_54, cb_76, cb_98;
+
+ cb10 = ld32x(codebook,j);
+ cb32 = ld32x(codebook,j+1);
+ cb54 = ld32x(codebook,j+2);
+ cb76 = ld32x(codebook,j+3);
+ cb98 = ld32x(codebook,j+4);
+ cb_10 = ld32x(codebook,j+5);
+ cb_32 = ld32x(codebook,j+6);
+ cb_54 = ld32x(codebook,j+7);
+ cb_76 = ld32x(codebook,j+8);
+ cb_98 = ld32x(codebook,j+9);
+
+ dist = ifir16(in10,cb10) + ifir16(in32,cb32);
+ dist += ifir16(in54,cb54) + ifir16(in76,cb76);
+ dist += ifir16(in98,cb98) + ifir16(in_10,cb_10);
+ dist += ifir16(in_32,cb_32) + ifir16(in_54,cb_54);
+ dist += ifir16(in_76,cb_76) + ifir16(in_98,cb_98);
+
+ dist = (E[i] >> 1) - dist;
+ vq_nbest_dist(i,N,dist,&used,nbest,best_dist);
+ }
+#if (TM_UNROLL && TM_UNROLL_VQNBEST > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+}
+
+
+#define OVERRIDE_VQ_NBEST
+void vq_nbest (Int16 *in, const Int16 *codebook, int len, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist, char *stack)
+{
+ TMDEBUG_ALIGNMEM(codebook);
+
+ VQNBEST_START();
+ if( len==5 )
+ vq_nbest_5(in,codebook,entries,E,N,nbest,best_dist);
+ else if ( len==8 )
+ vq_nbest_8(in,codebook,entries,E,N,nbest,best_dist);
+ else if ( len==10 )
+ vq_nbest_10(in,codebook,entries,E,N,nbest,best_dist);
+ else if ( len==20 )
+ vq_nbest_20(in,codebook,entries,E,N,nbest,best_dist);
+
+#ifndef REMARK_ON
+ (void)stack;
+#endif
+
+ VQNBEST_STOP();
+}
+
+inline void vq_nbest_sign_dist(int i, int N, int dist, int sign, int entries, int *used, int *nbest, Int32 *best_dist)
+{
+ register int k;
+
+ if (i<N || dist<best_dist[N-1])
+ { for (k=N-1; (k >= 1) && (k > *used || dist < best_dist[k-1]); k--)
+ {
+ best_dist[k]=best_dist[k-1];
+ nbest[k] = nbest[k-1];
+ }
+
+ if ( sign ) i += entries;
+ best_dist[k]=dist;
+ *used++;
+ nbest[k] = i;
+ }
+}
+
+void vq_nbest_sign_5(Int16 *in, const Int16 *codebook, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist)
+{
+ register int i, j;
+ register int in10, in32, in4;
+ int used = 0;
+
+ in10 = ld32(in);
+ in32 = ld32x(in,1);
+ in4 = sex16(in[4]);
+
+#if (TM_UNROLL && TM_UNROLL_VQSIGNNBEST > 0)
+#pragma TCS_unroll=2
+#pragma TCS_unrollexact=1
+#endif
+
+ for ( i=0,j=0 ; i<entries ; i+=2,j+=5 )
+ {
+ register int dist1, dist2, sign1, sign2;
+ register int cb10, cb32, cb54, cb76, cb98, cb87, cb65;
+
+ cb10 = ld32x(codebook,j);
+ cb32 = ld32x(codebook,j+1);
+ cb54 = ld32x(codebook,j+2);
+ cb76 = ld32x(codebook,j+3);
+ cb98 = ld32x(codebook,j+4);
+
+ dist1 = sex16(cb54) * in4;
+ dist1 += ifir16(in10,cb10) + ifir16(in32,cb32);
+
+ sign1 = mux(dist1>0,0,1);
+ dist1 = iflip(dist1>0,dist1);
+ dist1 = (E[i] >> 1) + dist1;
+
+ cb65 = funshift2(cb76,cb54);
+ cb87 = funshift2(cb98,cb76);
+ dist2 = asri(16,cb98) * in4;
+ dist2 += ifir16(in10,cb65) + ifir16(in32,cb87);
+
+ sign2 = mux(dist2>0,0,1);
+ dist2 = iflip(dist2>0,dist2);
+ dist2 = (E[i] >> 1) + dist2;
+
+ vq_nbest_sign_dist(i,N,dist1,sign1,entries,&used,nbest,best_dist);
+ vq_nbest_sign_dist(i+1,N,dist2,sign2,entries,&used,nbest,best_dist);
+ }
+#if (TM_UNROLL && TM_UNROLL_VQSIGNNBEST > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+}
+
+void vq_nbest_sign_8(Int16 *in, const Int16 *codebook, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist)
+{
+ register int i, j;
+ register int sign;
+ register int in10, in32, in54, in76;
+ int used = 0;
+
+ in10 = ld32(in);
+ in32 = ld32x(in,1);
+ in54 = ld32x(in,2);
+ in76 = ld32x(in,3);
+
+#if (TM_UNROLL && TM_UNROLL_VQSIGNNBEST > 0)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+
+ for ( i=0,j=0 ; i<entries ; ++i,j+=4 )
+ {
+ register int dist;
+ register int cb10, cb32, cb54, cb76;
+
+ cb10 = ld32x(codebook,j);
+ cb32 = ld32x(codebook,j+1);
+ cb54 = ld32x(codebook,j+2);
+ cb76 = ld32x(codebook,j+3);
+
+ dist = ifir16(in10,cb10) + ifir16(in32,cb32);
+ dist += ifir16(in54,cb54) + ifir16(in76,cb76);
+
+ sign = mux(dist>0,0,1);
+ dist = iflip(dist>0,dist);
+ dist = (E[i] >> 1) + dist;
+
+ vq_nbest_sign_dist(i,N,dist,sign,entries,&used,nbest,best_dist);
+ }
+#if (TM_UNROLL && TM_UNROLL_VQSIGNNBEST > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+}
+
+void vq_nbest_sign_10(Int16 *in, const Int16 *codebook, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist)
+{
+ register int i, j;
+ register int sign;
+ register int in10, in32, in54, in76, in98;
+ int used = 0;
+
+ in10 = ld32(in);
+ in32 = ld32x(in,1);
+ in54 = ld32x(in,2);
+ in76 = ld32x(in,3);
+ in98 = ld32x(in,4);
+
+#if (TM_UNROLL && TM_UNROLL_VQSIGNNBEST > 0)
+#pragma TCS_unroll=4
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0,j=0 ; i<entries ; ++i,j+=5 )
+ {
+ register int dist;
+ register int cb10, cb32, cb54, cb76, cb98;
+
+ cb10 = ld32x(codebook,j);
+ cb32 = ld32x(codebook,j+1);
+ cb54 = ld32x(codebook,j+2);
+ cb76 = ld32x(codebook,j+3);
+ cb98 = ld32x(codebook,j+4);
+
+ dist = ifir16(in10,cb10) + ifir16(in32,cb32);
+ dist += ifir16(in54,cb54) + ifir16(in76,cb76);
+ dist += ifir16(in98,cb98);
+
+ sign = mux(dist>0,0,1);
+ dist = iflip(dist>0,dist);
+ dist = (E[i] >> 1) + dist;
+
+ vq_nbest_sign_dist(i,N,dist,sign,entries,&used,nbest,best_dist);
+ }
+#if (TM_UNROLL && TM_UNROLL_VQSIGNNBEST > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+}
+
+void vq_nbest_sign_20(Int16 *in, const Int16 *codebook, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist)
+{
+ register int i, j;
+ register int sign;
+ register int in10, in32, in54, in76, in98, in_10, in_32, in_54, in_76, in_98;
+ int used = 0;
+
+ in10 = ld32(in);
+ in32 = ld32x(in,1);
+ in54 = ld32x(in,2);
+ in76 = ld32x(in,3);
+ in98 = ld32x(in,4);
+ in_10 = ld32x(in,5);
+ in_32 = ld32x(in,6);
+ in_54 = ld32x(in,7);
+ in_76 = ld32x(in,8);
+ in_98 = ld32x(in,9);
+
+#if (TM_UNROLL && TM_UNROLL_VQSIGNNBEST > 0)
+#pragma TCS_unroll=2
+#pragma TCS_unrollexact=1
+#endif
+ for ( i=0,j=0 ; i<entries ; ++i,j+=10 )
+ {
+ register int dist;
+ register int cb10, cb32, cb54, cb76, cb98, cb_10, cb_32, cb_54, cb_76, cb_98;
+
+ cb10 = ld32x(codebook,j);
+ cb32 = ld32x(codebook,j+1);
+ cb54 = ld32x(codebook,j+2);
+ cb76 = ld32x(codebook,j+3);
+ cb98 = ld32x(codebook,j+4);
+ cb_10 = ld32x(codebook,j+5);
+ cb_32 = ld32x(codebook,j+6);
+ cb_54 = ld32x(codebook,j+7);
+ cb_76 = ld32x(codebook,j+8);
+ cb_98 = ld32x(codebook,j+9);
+
+ dist = ifir16(in10,cb10) + ifir16(in32,cb32);
+ dist += ifir16(in54,cb54) + ifir16(in76,cb76);
+ dist += ifir16(in98,cb98) + ifir16(in_10,cb_10);
+ dist += ifir16(in_32,cb_32) + ifir16(in_54,cb_54);
+ dist += ifir16(in_76,cb_76) + ifir16(in_98,cb_98);
+
+ sign = mux(dist>0,0,1);
+ dist = iflip(dist>0,dist);
+ dist = (E[i] >> 1) + dist;
+
+ vq_nbest_sign_dist(i,N,dist,sign,entries,&used,nbest,best_dist);
+ }
+#if (TM_UNROLL && TM_UNROLL_VQSIGNNBEST > 0)
+#pragma TCS_unrollexact=0
+#pragma TCS_unroll=0
+#endif
+}
+
+#define OVERRIDE_VQ_NBEST_SIGN
+void vq_nbest_sign (Int16 *in, const Int16 *codebook, int len, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist, char *stack)
+{
+ TMDEBUG_ALIGNMEM(in);
+ TMDEBUG_ALIGNMEM(codebook);
+
+ VQNBESTSIGN_START();
+
+ if( len==5 )
+ vq_nbest_sign_5(in,codebook,entries,E,N,nbest,best_dist);
+ else if ( len==8 )
+ vq_nbest_sign_8(in,codebook,entries,E,N,nbest,best_dist);
+ else if ( len==10 )
+ vq_nbest_sign_10(in,codebook,entries,E,N,nbest,best_dist);
+ else if ( len==20 )
+ vq_nbest_sign_20(in,codebook,entries,E,N,nbest,best_dist);
+
+#ifndef REMARK_ON
+ (void)stack;
+#endif
+
+ VQNBESTSIGN_STOP();
+}
+
+#endif
+
diff --git a/win32/VS2005/libspeex/libspeex.vcproj b/win32/VS2005/libspeex/libspeex.vcproj index 34cf8a0..34565f7 100644 --- a/win32/VS2005/libspeex/libspeex.vcproj +++ b/win32/VS2005/libspeex/libspeex.vcproj @@ -1418,6 +1418,10 @@ >
</File>
<File
+ RelativePath="..\..\..\libspeex\filterbank.c"
+ >
+ </File>
+ <File
RelativePath="..\..\..\libspeex\filters.c"
>
</File>
|