Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/xiph/speex.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Marc Valin <Jean-Marc.Valin@csiro.au>2007-05-04 09:11:18 +0400
committerJean-Marc Valin <Jean-Marc.Valin@csiro.au>2008-05-19 08:53:14 +0400
commit3d7a6f0bd0a60145d8ac3a2f4037da623f407fba (patch)
treef90d32540ec3269ef8a405a2e97daaf2f83ffcab
parent6bd022014a21ecca9c27d6041397009a5933ac39 (diff)
parentd2cddf7e2f3c1a75265c43cabaa391037c830745 (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
-rw-r--r--COPYING2
-rw-r--r--Doxyfile1011
-rw-r--r--README.Trimedia191
-rw-r--r--Speex.kdevelop71
-rw-r--r--TODO51
-rwxr-xr-xautogen.sh20
-rw-r--r--configure.ac14
-rw-r--r--doc/echo_path.eps1298
-rw-r--r--doc/echo_path.odgbin0 -> 29078 bytes
-rw-r--r--doc/manual.lyx1322
-rw-r--r--include/speex/Makefile.am3
-rw-r--r--include/speex/speex.h34
-rw-r--r--include/speex/speex_bits.h24
-rw-r--r--include/speex/speex_callbacks.h10
-rw-r--r--include/speex/speex_echo.h7
-rw-r--r--include/speex/speex_header.h7
-rw-r--r--include/speex/speex_jitter.h117
-rw-r--r--include/speex/speex_preprocess.h159
-rw-r--r--include/speex/speex_resampler.h328
-rw-r--r--include/speex/speex_stereo.h6
-rw-r--r--libspeex/Makefile.am16
-rw-r--r--libspeex/_kiss_fft_guts.h13
-rw-r--r--libspeex/arch.h8
-rw-r--r--libspeex/bits.c14
-rw-r--r--libspeex/cb_search.c32
-rw-r--r--libspeex/cb_search_bfin.h5
-rw-r--r--libspeex/echo_diagnostic.m72
-rw-r--r--libspeex/fftwrap.c44
-rw-r--r--libspeex/filterbank.c226
-rw-r--r--libspeex/filterbank.h66
-rw-r--r--libspeex/filters.c387
-rw-r--r--libspeex/filters.h16
-rw-r--r--libspeex/filters_arm4.h292
-rw-r--r--libspeex/filters_bfin.h273
-rw-r--r--libspeex/filters_sse.h36
-rw-r--r--libspeex/fixed_debug.h127
-rw-r--r--libspeex/fixed_generic.h8
-rw-r--r--libspeex/jitter.c227
-rw-r--r--libspeex/kiss_fft.c354
-rw-r--r--libspeex/kiss_fftr.c155
-rw-r--r--libspeex/kiss_fftr.h5
-rw-r--r--libspeex/lbr_48k_tables.c132
-rw-r--r--libspeex/lsp.c2
-rw-r--r--libspeex/ltp.c216
-rw-r--r--libspeex/ltp_arm4.h17
-rw-r--r--libspeex/ltp_bfin.h10
-rw-r--r--libspeex/math_approx.c204
-rw-r--r--libspeex/math_approx.h14
-rw-r--r--libspeex/mdf.c639
-rw-r--r--libspeex/misc.c85
-rw-r--r--libspeex/misc.h32
-rw-r--r--libspeex/modes.c13
-rw-r--r--libspeex/modes.h19
-rw-r--r--libspeex/nb_celp.c336
-rw-r--r--libspeex/nb_celp.h6
-rw-r--r--libspeex/preprocess.c1386
-rw-r--r--libspeex/pseudofloat.h124
-rw-r--r--libspeex/quant_lsp.c2
-rw-r--r--libspeex/resample.c1062
-rw-r--r--libspeex/sb_celp.c819
-rw-r--r--libspeex/sb_celp.h35
-rw-r--r--libspeex/speex.c8
-rw-r--r--libspeex/speex_callbacks.c12
-rw-r--r--libspeex/speex_header.c4
-rw-r--r--libspeex/testdenoise.c6
-rw-r--r--libspeex/testecho.c6
-rw-r--r--libspeex/testenc.c4
-rw-r--r--libspeex/testenc_uwb.c4
-rw-r--r--libspeex/testenc_wb.c4
-rw-r--r--libspeex/testresample.c86
-rw-r--r--libspeex/vbr.c32
-rw-r--r--libspeex/window.c50
-rw-r--r--macosx/Speex.xcodeproj/project.pbxproj314
-rw-r--r--speex.pc.in2
-rw-r--r--speexclient/README18
-rw-r--r--speexclient/alsa_device.c431
-rw-r--r--speexclient/alsa_device.h69
-rwxr-xr-xspeexclient/compile.sh3
-rw-r--r--speexclient/speexclient.c249
-rw-r--r--src/speexdec.c24
-rw-r--r--src/speexenc.c23
-rw-r--r--src/wav_io.c47
-rw-r--r--src/wav_io.h28
-rw-r--r--symbian/bld.inf14
-rw-r--r--symbian/speex.mmp4
-rw-r--r--ti/testenc-TI-C5x.c4
-rw-r--r--ti/testenc-TI-C64x.c4
-rw-r--r--tmv/_kiss_fft_guts_tm.h188
-rw-r--r--tmv/cb_search_tm.h149
-rw-r--r--tmv/config.h98
-rw-r--r--tmv/fftwrap_tm.h233
-rw-r--r--tmv/filterbank_tm.h289
-rw-r--r--tmv/filters_tm.h1521
-rw-r--r--tmv/fixed_tm.h100
-rw-r--r--tmv/kiss_fft_tm.h599
-rw-r--r--tmv/kiss_fftr_tm.h235
-rw-r--r--tmv/lpc_tm.h150
-rw-r--r--tmv/lsp_tm.h310
-rw-r--r--tmv/ltp_tm.h479
-rw-r--r--tmv/mdf_tm.h1192
-rw-r--r--tmv/misc_tm.h (renamed from include/speex/speex_noglobals.h)152
-rw-r--r--tmv/preprocess_tm.h1135
-rw-r--r--tmv/profile_tm.h407
-rw-r--r--tmv/quant_lsp_tm.h448
-rw-r--r--tmv/speex_config_types.h31
-rw-r--r--tmv/vq_tm.h494
-rw-r--r--win32/VS2005/libspeex/libspeex.vcproj4
107 files changed, 17232 insertions, 4636 deletions
diff --git a/COPYING b/COPYING
index 3b6b579..4461c07 100644
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,4 @@
-Copyright 2002-2006
+Copyright 2002-2007
Xiph.org Foundation
Jean-Marc Valin
David Rowe
diff --git a/Doxyfile b/Doxyfile
index f24545b..772934f 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -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>
diff --git a/TODO b/TODO
index 2cfee5e..924258a 100644
--- a/TODO
+++ b/TODO
@@ -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?
diff --git a/autogen.sh b/autogen.sh
index 2b3f046..bf650f2 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -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
new file mode 100644
index 0000000..460af84
--- /dev/null
+++ b/doc/echo_path.odg
Binary files differ
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,&param))
+ 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>