diff --git a/libs/speex/COPYING b/libs/speex/COPYING
index 3b6b579cf3..de6fbe2c91 100644
--- a/libs/speex/COPYING
+++ b/libs/speex/COPYING
@@ -1,10 +1,11 @@
-Copyright 2002-2006
- Xiph.org Foundation
- Jean-Marc Valin
- David Rowe
- EpicGames
- Analog Devices
- Commonwealth Scientific and Industrial Research Organisation (CSIRO)
+Copyright 2002-2008 Xiph.org Foundation
+Copyright 2002-2008 Jean-Marc Valin
+Copyright 2005-2007 Analog Devices Inc.
+Copyright 2005-2008 Commonwealth Scientific and Industrial Research
+ Organisation (CSIRO)
+Copyright 1993, 2002, 2006 David Rowe
+Copyright 2003 EpicGames
+Copyright 1992-1994 Jutta Degener, Carsten Bormann
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
diff --git a/libs/speex/Makefile.am b/libs/speex/Makefile.am
index 5f6c7bbdf8..4b99faf55e 100644
--- a/libs/speex/Makefile.am
+++ b/libs/speex/Makefile.am
@@ -2,18 +2,18 @@
# To disable automatic dependency tracking if using other tools than
# gcc and gmake, add the option 'no-dependencies'
-AUTOMAKE_OPTIONS = 1.7
+AUTOMAKE_OPTIONS = 1.8
m4datadir = $(datadir)/aclocal
m4data_DATA = speex.m4
pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = speex.pc
+pkgconfig_DATA = speex.pc speexdsp.pc
EXTRA_DIST = Speex.spec Speex.spec.in Speex.kdevelop speex.m4 speex.pc.in README.blackfin README.symbian README.TI-DSP
#Fools KDevelop into including all files
-SUBDIRS = libspeex include doc win32 symbian ti
+SUBDIRS = libspeex include @src@ doc win32 symbian ti
DIST_SUBDIRS = libspeex include src doc win32 symbian ti
diff --git a/libs/speex/Speex.kdevelop b/libs/speex/Speex.kdevelop
index e4e07493ca..1b3d683b07 100644
--- a/libs/speex/Speex.kdevelop
+++ b/libs/speex/Speex.kdevelop
@@ -11,11 +11,14 @@
false
+ kdevsubversion
+
+ Speex
libspeex/libspeex.la
- default
+ float
src/Speex
@@ -25,23 +28,47 @@
false
true
+ false
+ false
-
- optimized
- GccOptions
- GppOptions
- G77Options
- -O2 -g0
-
-
- --enable-debug=full
- debug
- GccOptions
- GppOptions
- G77Options
- -O0 -g3
-
+
+ float
+ kdevgccoptions
+ kdevgppoptions
+ kdevpgf77options
+ -O2 -g -Wall
+
+ --disable-shared
+
+
+
+
+
+
+
+
+
+
+ --enable-fixed-point --disable-shared
+ fixed
+ kdevgccoptions
+ kdevgppoptions
+ kdevpgf77options
+ -O2 -g -Wall
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -49,9 +76,11 @@
false
- 1
+ 4
false
+ true
+ 0
@@ -69,6 +98,7 @@
false
true
+ 10
@@ -88,10 +118,50 @@
true
true
true
- 250
+ 350
400
250
+ false
+ 0
+ true
+ true
+ false
+ std=_GLIBCXX_STD;__gnu_cxx=std
+ true
+ true
+ false
+ false
+ true
+ true
+ true
+ true
+ .;
+ false
+ false
+
+ false
+ 3
+ /usr/share/qt3
+ 3
+ EmbeddedKDevDesigner
+ /usr/share/qt3/bin/qmake
+ /usr/bin/designer-qt3
+
+
+
+
+ set
+ m_,_
+ theValue
+ true
+ true
+
+
+ true
+ true
+ Horizontal
+
@@ -101,6 +171,7 @@
*.o,*.lo,CVS
true
+ false
@@ -120,4 +191,11 @@
.cpp
+
+
+
+
+
+
+
diff --git a/libs/speex/Speex.spec b/libs/speex/Speex.spec
index 4aab2877ce..e0ae03024c 100644
--- a/libs/speex/Speex.spec
+++ b/libs/speex/Speex.spec
@@ -1,5 +1,5 @@
%define name speex
-%define ver 1.2beta1
+%define ver 1.2rc1
%define rel 1
Summary: An open-source, patent-free speech codec
@@ -67,4 +67,5 @@ make DESTDIR=$RPM_BUILD_ROOT install
%{_includedir}/speex/speex*.h
/usr/share/aclocal/speex.m4
%{_libdir}/pkgconfig/speex.pc
+%{_libdir}/pkgconfig/speexdsp.pc
%{_libdir}/libspeex*.a
diff --git a/libs/speex/Speex.spec.in b/libs/speex/Speex.spec.in
index 416f435699..bccfc2351a 100644
--- a/libs/speex/Speex.spec.in
+++ b/libs/speex/Speex.spec.in
@@ -67,4 +67,5 @@ make DESTDIR=$RPM_BUILD_ROOT install
%{_includedir}/speex/speex*.h
/usr/share/aclocal/speex.m4
%{_libdir}/pkgconfig/speex.pc
+%{_libdir}/pkgconfig/speexdsp.pc
%{_libdir}/libspeex*.a
diff --git a/libs/speex/TODO b/libs/speex/TODO
index 61f8f99d4d..fd3c953aa2 100644
--- a/libs/speex/TODO
+++ b/libs/speex/TODO
@@ -1,29 +1,43 @@
-Better saturation handling in mdf?
-get rid of crap that shouldn't be exposed in speex.h
+For 1.2:
+Major points:
+- Make documentation match the actual code (especially jitter buffer, AEC and preprocessor)
+- Get AGC to work in fixed-point even if not totally converted
+- Stabilise all APIs (need feedback)
+- Short-term estimate in jitter buffer
+- Control delay in new AEC API.
+- NaN checks?
+- Better error reporting
+- Make kiss-fft 32-bit safe
+
+Minor issues:
+- Fix last frame of speexenc
+
+
+Post 1.2:
+improve float<->int conversion
+split encoder and decoder?
+Merge TriMedia stuff
+packet dump
+Do VAD properly
+--enable-{aec,preprocessor,jitter,resampler}
+
+Optimisations
+- Add restrict in a few places?
+- enable 4x4 version of pitch_xcorr() at least on some archs?
+- use __builtin_expect() (likely()/unlikely())
Would be nice:
+Implement wideband split as IIR instead of QMF?
-Allocator override (speex_lib_ctl)
-Better error handling
+Allocator override (speex_lib_ctl?)
Fixed-point:
- - Wideband
- - Initialization
+ - VBR
- Jitter buffer
+ - AGC
Denoiser:
- - Smooth gain (remove musical noise)
- Better noise adaptation
- - Do some tuning
AGC:
- - 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)
+ - Use median filtering instead of "non-linear mean"?
Standards
-Complete Speex RTP profile
@@ -32,4 +46,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/libs/speex/acinclude.m4 b/libs/speex/acinclude.m4
index 9f9333b010..0e1f1abf59 100644
--- a/libs/speex/acinclude.m4
+++ b/libs/speex/acinclude.m4
@@ -19,7 +19,7 @@ AC_ARG_ENABLE(oggtest, [ --disable-oggtest Do not try to compile and run
elif test "x$ogg_prefix" != "x" ; then
OGG_LIBS="-L$ogg_prefix/lib"
elif test "x$prefix" != "xNONE" ; then
- OGG_LIBS=""
+ OGG_LIBS="-L$prefix/lib"
fi
OGG_LIBS="$OGG_LIBS -logg"
diff --git a/libs/speex/config.h.in b/libs/speex/config.h.in
index 05399fc597..959340983f 100644
--- a/libs/speex/config.h.in
+++ b/libs/speex/config.h.in
@@ -9,14 +9,17 @@
/* Make use of Blackfin assembly optimizations */
#undef BFIN_ASM
-/* Disable wideband codec */
-#undef DISABLE_WIDEBAND
+/* Disable all parts of the API that are using floats */
+#undef DISABLE_FLOAT_API
+
+/* Disable VBR and VAD from the codec */
+#undef DISABLE_VBR
/* Enable valgrind extra checks */
#undef ENABLE_VALGRIND
-/* Enable support for Epic 4.8 kbps mode */
-#undef EPIC_48K
+/* Symbol visibility prefix */
+#undef EXPORT
/* Debug fixed-point implementation */
#undef FIXED_DEBUG
@@ -24,9 +27,18 @@
/* Compile as fixed-point */
#undef FIXED_POINT
+/* Compile as floating-point */
+#undef FLOATING_POINT
+
+/* Define to 1 if you have the header file. */
+#undef HAVE_ALLOCA_H
+
/* Define to 1 if you have the header file. */
#undef HAVE_DLFCN_H
+/* Define to 1 if you have the header file. */
+#undef HAVE_GETOPT_H
+
/* Define to 1 if you have the `getopt_long' function. */
#undef HAVE_GETOPT_LONG
@@ -84,16 +96,13 @@
/* Define to the version of this package. */
#undef PACKAGE_VERSION
-/* Reduce precision to 16 bits (EXPERIMENTAL) */
-#undef PRECISION16
-
-/* The size of a `int', as computed by sizeof. */
+/* The size of `int', as computed by sizeof. */
#undef SIZEOF_INT
-/* The size of a `long', as computed by sizeof. */
+/* The size of `long', as computed by sizeof. */
#undef SIZEOF_LONG
-/* The size of a `short', as computed by sizeof. */
+/* The size of `short', as computed by sizeof. */
#undef SIZEOF_SHORT
/* Version extra */
@@ -120,12 +129,21 @@
/* Make use of alloca */
#undef USE_ALLOCA
+/* Use FFTW3 for FFT */
+#undef USE_GPL_FFTW3
+
+/* Use Intel Math Kernel Library for FFT */
+#undef USE_INTEL_MKL
+
+/* Use KISS Fast Fourier Transform */
+#undef USE_KISS_FFT
+
+/* Use FFT from OggVorbis */
+#undef USE_SMALLFT
+
/* Use C99 variable-size arrays */
#undef VAR_ARRAYS
-/* Enable Vorbis-style psychoacoustics (EXPERIMENTAL) */
-#undef VORBIS_PSYCHO
-
/* Define to 1 if your processor stores words with the most significant byte
first (like Motorola and SPARC, unlike Intel and VAX). */
#undef WORDS_BIGENDIAN
diff --git a/libs/speex/configure.ac b/libs/speex/configure.ac
index a3a2395c7f..df7f01dc6b 100644
--- a/libs/speex/configure.ac
+++ b/libs/speex/configure.ac
@@ -6,15 +6,15 @@ AM_CONFIG_HEADER([config.h])
SPEEX_MAJOR_VERSION=1
SPEEX_MINOR_VERSION=1
-SPEEX_MICRO_VERSION=13
+SPEEX_MICRO_VERSION=16
SPEEX_EXTRA_VERSION=
#SPEEX_VERSION=
-SPEEX_VERSION=$SPEEX_MAJOR_VERSION.$SPEEX_MINOR_VERSION.$SPEEX_MICRO_VERSION$SPEEX_EXTRA_VERSION
-SPEEX_VERSION="1.2beta1"
+#SPEEX_VERSION=$SPEEX_MAJOR_VERSION.$SPEEX_MINOR_VERSION.$SPEEX_MICRO_VERSION$SPEEX_EXTRA_VERSION
+SPEEX_VERSION="1.2rc1"
-SPEEX_LT_CURRENT=5
+SPEEX_LT_CURRENT=6
SPEEX_LT_REVISION=0
-SPEEX_LT_AGE=4
+SPEEX_LT_AGE=5
AC_SUBST(SPEEX_LT_CURRENT)
AC_SUBST(SPEEX_LT_REVISION)
@@ -30,6 +30,7 @@ AM_INIT_AUTOMAKE($PACKAGE, $VERSION, no-define)
AM_MAINTAINER_MODE
AC_CANONICAL_HOST
+AC_LIBTOOL_WIN32_DLL
AM_PROG_LIBTOOL
AC_C_BIGENDIAN
@@ -40,7 +41,8 @@ AC_C_RESTRICT
AC_MSG_CHECKING(for C99 variable-size arrays)
AC_TRY_COMPILE( , [
-int foo=10;
+int foo;
+foo = 10;
int array[foo];
],
[has_var_arrays=yes;AC_DEFINE([VAR_ARRAYS], [], [Use C99 variable-size arrays])
@@ -49,8 +51,14 @@ has_var_arrays=no
)
AC_MSG_RESULT($has_var_arrays)
+AC_CHECK_HEADERS([alloca.h getopt.h])
AC_MSG_CHECKING(for alloca)
-AC_TRY_COMPILE( [#include ], [
+AC_TRY_COMPILE( [
+#ifdef HAVE_ALLOCA_H
+# include
+#endif
+#include
+], [
int foo=10;
int *array = alloca(foo);
],
@@ -64,9 +72,49 @@ has_alloca=no
)
AC_MSG_RESULT($has_alloca)
+AC_MSG_CHECKING(for SSE in current arch/CFLAGS)
+AC_LINK_IFELSE([
+AC_LANG_PROGRAM([[
+#include
+__m128 testfunc(float *a, float *b) {
+ return _mm_add_ps(_mm_loadu_ps(a), _mm_loadu_ps(b));
+}
+]])],
+[
+has_sse=yes
+],
+[
+has_sse=no
+]
+)
+AC_MSG_RESULT($has_sse)
+
+SAVE_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -fvisibility=hidden"
+AC_MSG_CHECKING(for ELF visibility)
+AC_COMPILE_IFELSE([
+AC_LANG_PROGRAM([[
+#pragma GCC visibility push(hidden)
+__attribute__((visibility("default")))
+int var=10;
+]])],
+[
+has_visibility=yes
+AC_DEFINE([EXPORT], [__attribute__((visibility("default")))], [Symbol visibility prefix])
+],
+[
+has_visibility=no
+AC_DEFINE([EXPORT], [], [Symbol visibility prefix])
+CFLAGS="$SAVE_CFLAGS"
+]
+)
+AC_MSG_RESULT($has_visibility)
AC_CHECK_HEADERS(sys/soundcard.h sys/audioio.h)
+XIPH_PATH_OGG([src="src"], [src=""])
+AC_SUBST(src)
+
AC_CHECK_LIB(m, sin)
# Check for getopt_long; if not found, use included source.
@@ -86,30 +134,45 @@ AC_DEFINE_UNQUOTED(SPEEX_MINOR_VERSION, ${SPEEX_MINOR_VERSION}, [Version minor])
AC_DEFINE_UNQUOTED(SPEEX_MICRO_VERSION, ${SPEEX_MICRO_VERSION}, [Version micro])
AC_DEFINE_UNQUOTED(SPEEX_EXTRA_VERSION, "${SPEEX_EXTRA_VERSION}", [Version extra])
-AC_ARG_ENABLE(wideband, [ --disable-wideband Disable wideband codec],
-[if test "$enableval" = no; then
- AC_DEFINE([DISABLE_WIDEBAND], , [Disable wideband codec])
-fi])
-
-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 (EXPERIMENTAL)])
-fi])
-
AC_ARG_ENABLE(valgrind, [ --enable-valgrind Enable valgrind extra checks],
[if test "$enableval" = yes; then
AC_DEFINE([ENABLE_VALGRIND], , [Enable valgrind extra checks])
fi])
-AC_ARG_ENABLE(sse, [ --enable-sse Enable SSE support], [if test "$enableval" = yes; then
-AC_DEFINE([_USE_SSE], , [Enable SSE support])
+AC_ARG_ENABLE(sse, [ --enable-sse Enable SSE support], [
+if test "x$enableval" != xno; then
+has_sse=yes
CFLAGS="$CFLAGS -O3 -msse"
+else
+has_sse=no
fi
])
+
+FFT=smallft
+
AC_ARG_ENABLE(fixed-point, [ --enable-fixed-point Compile as fixed-point],
[if test "$enableval" = yes; then
+ FFT=kiss
+ has_sse=no
AC_DEFINE([FIXED_POINT], , [Compile as fixed-point])
+else
+ AC_DEFINE([FLOATING_POINT], , [Compile as floating-point])
+fi],
+AC_DEFINE([FLOATING_POINT], , [Compile as floating-point]))
+
+if test "$has_sse" = yes; then
+ AC_DEFINE([_USE_SSE], , [Enable SSE support])
+fi
+
+AC_ARG_ENABLE(float-api, [ --disable-float-api Disable the floating-point API],
+[if test "$enableval" = no; then
+ AC_DEFINE([DISABLE_FLOAT_API], , [Disable all parts of the API that are using floats])
+fi])
+
+AC_ARG_ENABLE(vbr, [ --disable-vbr Disable VBR and VAD from the codec],
+[if test "$enableval" = no; then
+ AC_DEFINE([DISABLE_VBR], , [Disable VBR and VAD from the codec])
fi])
AC_ARG_ENABLE(arm4-asm, [ --enable-arm4-asm Make use of ARM4 assembly optimizations],
@@ -122,7 +185,7 @@ AC_ARG_ENABLE(arm5e-asm, [ --enable-arm5e-asm Make use of ARM5E assembly o
AC_DEFINE([ARM5E_ASM], , [Make use of ARM5E assembly optimizations])
fi])
-AC_ARG_ENABLE(blackfin-asm, [ --enable-blackfin-asm Make use of Blackfin assembly optimizations],
+AC_ARG_ENABLE(blackfin-asm, [ --enable-blackfin-asm Make use of Blackfin assembly optimizations],
[if test "$enableval" = yes; then
AC_DEFINE([BFIN_ASM], , [Make use of Blackfin assembly optimizations])
LDFLAGS="-Wl,-elf2flt=-s100000"
@@ -133,21 +196,49 @@ AC_ARG_ENABLE(fixed-point-debug, [ --enable-fixed-point-debug Debug fixed-poin
AC_DEFINE([FIXED_DEBUG], , [Debug fixed-point implementation])
fi])
-AC_ARG_ENABLE(epic-48k, [ --enable-epic-48k Enable support for Epic 4.8 kbps mode],
-[if test "$enableval" = yes; then
- AC_DEFINE([EPIC_48K], , [Enable support for Epic 4.8 kbps mode])
-fi])
-
AC_ARG_ENABLE(ti-c55x, [ --enable-ti-c55x Enable support for TI C55X DSP],
[if test "$enableval" = yes; then
has_char16=yes;
AC_DEFINE([TI_C55X], , [Enable support for TI C55X DSP])
fi])
-AC_ARG_ENABLE(16bit-precision, [ --enable-16bit-precision Reduce precision to 16 bits (EXPERIMENTAL)],
-[if test "$enableval" = yes; then
- AC_DEFINE([PRECISION16], , [Reduce precision to 16 bits (EXPERIMENTAL)])
-fi])
+AC_ARG_WITH([fft], [AS_HELP_STRING([--with-fft=choice],[use an alternate FFT implementation. The available choices are
+kiss (default fixed point), smallft (default floating point), gpl-fftw3 and proprietary-intel-mkl])],
+[FFT=$withval]
+)
+
+FFT_PKGCONFIG=
+AS_CASE([$FFT],
+ [kiss], [
+ AC_DEFINE([USE_KISS_FFT], [], [Use KISS Fast Fourier Transform])
+ ],
+ [smallft], [
+ AC_DEFINE([USE_SMALLFT], [], [Use FFT from OggVorbis])
+ ],
+ [gpl-fftw3], [
+ AC_DEFINE([USE_GPL_FFTW3], [], [Use FFTW3 for FFT])
+ PKG_CHECK_MODULES(FFT, fftw3f)
+ ],
+ [proprietary-intel-mkl], [
+ AC_DEFINE([USE_INTEL_MKL], [], [Use Intel Math Kernel Library for FFT])
+ AC_MSG_CHECKING(for valid MKL)
+ AC_LINK_IFELSE([
+ AC_LANG_PROGRAM([[
+#include
+void func() {
+ DFTI_DESCRIPTOR_HANDLE h;
+ MKL_LONG result=DftiCreateDescriptor(&h, DFTI_SINGLE, DFTI_REAL, 0);
+}]])],
+ [AC_MSG_RESULT(yes)],
+ [AC_MSG_FAILURE([Failed to compile MKL test program. Make sure you set CFLAGS to include the include directory and set LDFLAGS to include the library directory and all necesarry libraries.])]
+ )
+ ],
+ [AC_MSG_FAILURE([Unknown FFT $FFT specified for --with-fft])]
+)
+AM_CONDITIONAL(BUILD_KISS_FFT, [test "$FFT" = "kiss"])
+AM_CONDITIONAL(BUILD_SMALLFT, [test "$FFT" = "smallft"])
+AC_SUBST(FFT_PKGCONFIG)
+
AC_CHECK_SIZEOF(short)
AC_CHECK_SIZEOF(int)
@@ -182,47 +273,28 @@ fi
AC_SUBST(SIZE16)
AC_SUBST(SIZE32)
-
-AC_DEFUN([AX_COMPILER_VENDOR],
-[
-AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor,
- [ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=unknown
- # note: don't check for gcc first since some other compilers define __GNUC__
- for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do
- vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")"
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[
-#if !($vencpp)
- thisisanerror;
-#endif
-])], [ax_cv_]_AC_LANG_ABBREV[_compiler_vendor=`echo $ventest | cut -d: -f1`; break])
- done
- ])
-])
-
-AX_COMPILER_VENDOR
-
-# Enable 64 bit build
-AC_ARG_ENABLE(64,
-[AC_HELP_STRING([--enable-64],[build with 64 bit support])],[enable_64="$enable_64"],[enable_64="no"])
-
-if test "x${ax_cv_c_compiler_vendor}" = "xsun" ; then
- if test "${enable_64}" = "yes"; then
- CFLAGS="$CFLAGS -m64"
- CXXFLAGS="$CXXFLAGS -m64"
- fi
-fi
-
AC_OUTPUT([Makefile libspeex/Makefile src/Makefile doc/Makefile Speex.spec
- include/Makefile include/speex/Makefile speex.pc
+ include/Makefile include/speex/Makefile speex.pc speexdsp.pc
win32/Makefile win32/libspeex/Makefile win32/speexenc/Makefile
win32/speexdec/Makefile symbian/Makefile
- win32/VS2003/Makefile win32/VS2005/Makefile
+ win32/VS2003/Makefile
+ win32/VS2003/tests/Makefile
win32/VS2003/libspeex/Makefile
+ win32/VS2003/libspeexdsp/Makefile
win32/VS2003/speexdec/Makefile
win32/VS2003/speexenc/Makefile
+ win32/VS2005/Makefile
win32/VS2005/libspeex/Makefile
win32/VS2005/speexdec/Makefile
win32/VS2005/speexenc/Makefile
+ win32/VS2005/libspeexdsp/Makefile
+ win32/VS2005/tests/Makefile
+ win32/VS2008/libspeexdsp/Makefile
+ win32/VS2008/Makefile
+ win32/VS2008/speexdec/Makefile
+ win32/VS2008/tests/Makefile
+ win32/VS2008/libspeex/Makefile
+ win32/VS2008/speexenc/Makefile
include/speex/speex_config_types.h ti/Makefile
ti/speex_C54_test/Makefile ti/speex_C55_test/Makefile
ti/speex_C64_test/Makefile ])
diff --git a/libs/speex/doc/Makefile.am b/libs/speex/doc/Makefile.am
index a70a97b31a..d2896efabb 100644
--- a/libs/speex/doc/Makefile.am
+++ b/libs/speex/doc/Makefile.am
@@ -1,5 +1,3 @@
-docdir=$(prefix)/share/doc/@PACKAGE@-@VERSION@
-
doc_DATA = manual.pdf
EXTRA_DIST = $(doc_DATA)
diff --git a/libs/speex/doc/manual.pdf b/libs/speex/doc/manual.pdf
index ec77341ead..292f304def 100644
Binary files a/libs/speex/doc/manual.pdf and b/libs/speex/doc/manual.pdf differ
diff --git a/libs/speex/include/speex/Makefile.am b/libs/speex/include/speex/Makefile.am
index f7b65faf58..2ae34f9f80 100644
--- a/libs/speex/include/speex/Makefile.am
+++ b/libs/speex/include/speex/Makefile.am
@@ -3,13 +3,7 @@
nodist_pkginclude_HEADERS = speex_config_types.h
-pkginclude_HEADERS = speex.h \
- speex_types.h \
- speex_bits.h \
- speex_header.h \
- speex_callbacks.h \
- speex_stereo.h \
- speex_preprocess.h \
- speex_jitter.h \
- speex_echo.h
+pkginclude_HEADERS = speex.h speex_bits.h speex_buffer.h speex_callbacks.h \
+ speex_echo.h speex_header.h speex_jitter.h speex_preprocess.h speex_resampler.h \
+ speex_stereo.h speex_types.h
diff --git a/libs/speex/include/speex/speex.h b/libs/speex/include/speex/speex.h
index 7f8afa6062..82ba016237 100644
--- a/libs/speex/include/speex/speex.h
+++ b/libs/speex/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,19 +155,9 @@ 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
+/** Get "activity level" of the last decoded frame, i.e.
+ how much damage we cause if we remove the frame */
+#define SPEEX_GET_ACTIVITY 47
/* Preserving compatibility:*/
@@ -218,11 +212,6 @@ extern "C" {
/** modeID for the defined ultra-wideband mode */
#define SPEEX_MODEID_UWB 2
-#ifdef EPIC_48K
-/** modeID for the Epic 48K mode */
-#define SPEEX_MODEID_NB_48K 1000
-#endif
-
struct SpeexMode;
@@ -307,7 +296,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 +307,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 +329,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 +340,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 +375,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 +385,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);
@@ -412,20 +405,20 @@ extern const SpeexMode speex_wb_mode;
/** Default "ultra-wideband" mode */
extern const SpeexMode speex_uwb_mode;
-#ifdef EPIC_48K
-/** 4.8 kbps narrowband mode */
-extern const SpeexMode speex_nb_48k_mode;
-#endif
-
/** List of all modes available */
extern const SpeexMode * const speex_mode_list[SPEEX_NB_MODES];
/** Obtain one of the modes available */
const SpeexMode * speex_lib_get_mode (int mode);
+#ifndef WIN32
+/* We actually override the function in the narrowband case so that we can avoid linking in the wideband stuff */
+#define speex_lib_get_mode(mode) ((mode)==SPEEX_MODEID_NB ? &speex_nb_mode : speex_lib_get_mode (mode))
+#endif
+
#ifdef __cplusplus
}
#endif
-
+/** @}*/
#endif
diff --git a/libs/speex/include/speex/speex_bits.h b/libs/speex/include/speex/speex_bits.h
index b77202fde2..a26fb4ce0c 100644
--- a/libs/speex/include/speex/speex_bits.h
+++ b/libs/speex/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" {
@@ -59,6 +64,9 @@ void speex_bits_init(SpeexBits *bits);
/** Initializes SpeexBits struct using a pre-allocated buffer*/
void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size);
+/** Sets the bits in a SpeexBits struct to use data from an existing buffer (for decoding without copying data) */
+void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size);
+
/** Frees all resources associated to a SpeexBits struct. Right now this does nothing since no resources are allocated, but this could change in the future.*/
void speex_bits_destroy(SpeexBits *bits);
@@ -72,13 +80,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 +129,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 +155,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 +170,5 @@ void speex_bits_insert_terminator(SpeexBits *bits);
}
#endif
+/* @} */
#endif
diff --git a/libs/speex/include/speex/speex_buffer.h b/libs/speex/include/speex/speex_buffer.h
new file mode 100644
index 0000000000..df56f5f18b
--- /dev/null
+++ b/libs/speex/include/speex/speex_buffer.h
@@ -0,0 +1,68 @@
+/* Copyright (C) 2007 Jean-Marc Valin
+
+ File: speex_buffer.h
+ This is a very simple ring buffer implementation. It is not thread-safe
+ so you need to do your own locking.
+
+ 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_BUFFER_H
+#define SPEEX_BUFFER_H
+
+#include "speex/speex_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct SpeexBuffer_;
+typedef struct SpeexBuffer_ SpeexBuffer;
+
+SpeexBuffer *speex_buffer_init(int size);
+
+void speex_buffer_destroy(SpeexBuffer *st);
+
+int speex_buffer_write(SpeexBuffer *st, void *data, int len);
+
+int speex_buffer_writezeros(SpeexBuffer *st, int len);
+
+int speex_buffer_read(SpeexBuffer *st, void *data, int len);
+
+int speex_buffer_get_available(SpeexBuffer *st);
+
+int speex_buffer_resize(SpeexBuffer *st, int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
+
+
diff --git a/libs/speex/include/speex/speex_callbacks.h b/libs/speex/include/speex/speex_callbacks.h
index f6334f22a7..6f450b3a3a 100644
--- a/libs/speex/include/speex/speex_callbacks.h
+++ b/libs/speex/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 enhancer 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/libs/speex/include/speex/speex_echo.h b/libs/speex/include/speex/speex_echo.h
index 4813b5a007..53bcd28a1a 100644
--- a/libs/speex/include/speex/speex_echo.h
+++ b/libs/speex/include/speex/speex_echo.h
@@ -33,7 +33,10 @@
#ifndef SPEEX_ECHO_H
#define SPEEX_ECHO_H
-
+/** @defgroup SpeexEchoState SpeexEchoState: Acoustic echo canceller
+ * This is the acoustic echo canceller module.
+ * @{
+ */
#include "speex/speex_types.h"
#ifdef __cplusplus
@@ -48,41 +51,120 @@ extern "C" {
/** Get sampling rate */
#define SPEEX_ECHO_GET_SAMPLING_RATE 25
+/* Can't set window sizes */
+/** Get size of impulse response (int32) */
+#define SPEEX_ECHO_GET_IMPULSE_RESPONSE_SIZE 27
-/*struct drft_lookup;*/
+/* Can't set window content */
+/** Get impulse response (int32[]) */
+#define SPEEX_ECHO_GET_IMPULSE_RESPONSE 29
+
+/** Internal echo canceller state. Should never be accessed directly. */
struct SpeexEchoState_;
+/** @class SpeexEchoState
+ * This holds the state of the echo canceller. You need one per channel.
+*/
+
+/** Internal echo canceller state. Should never be accessed directly. */
typedef struct SpeexEchoState_ SpeexEchoState;
-/** Creates a new echo canceller state */
+/** Creates a new echo canceller state
+ * @param frame_size Number of samples to process at one time (should correspond to 10-20 ms)
+ * @param filter_length Number of samples of echo to cancel (should generally correspond to 100-500 ms)
+ * @return Newly-created echo canceller state
+ */
SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length);
-/** Destroys an echo canceller state */
+/** Creates a new multi-channel echo canceller state
+ * @param frame_size Number of samples to process at one time (should correspond to 10-20 ms)
+ * @param filter_length Number of samples of echo to cancel (should generally correspond to 100-500 ms)
+ * @param nb_mic Number of microphone channels
+ * @param nb_speakers Number of speaker channels
+ * @return Newly-created echo canceller state
+ */
+SpeexEchoState *speex_echo_state_init_mc(int frame_size, int filter_length, int nb_mic, int nb_speakers);
+
+/** Destroys an echo canceller state
+ * @param st Echo canceller state
+*/
void speex_echo_state_destroy(SpeexEchoState *st);
-/** Performs echo cancellation a frame */
+/** Performs echo cancellation a frame, based on the audio sent to the speaker (no delay is added
+ * to playback in this form)
+ *
+ * @param st Echo canceller state
+ * @param rec Signal from the microphone (near end + far end echo)
+ * @param play Signal played to the speaker (received from far end)
+ * @param out Returns near-end signal with echo removed
+ */
+void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *rec, const spx_int16_t *play, spx_int16_t *out);
+
+/** Performs echo cancellation a frame (deprecated) */
void speex_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 speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out, spx_int32_t *Yout);
+/** Perform echo cancellation using internal playback buffer, which is delayed by two frames
+ * to account for the delay introduced by most soundcards (but it could be off!)
+ * @param st Echo canceller state
+ * @param rec Signal from the microphone (near end + far end echo)
+ * @param out Returns near-end signal with echo removed
+*/
+void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out);
-/** Let the echo canceller know that a frame was just played */
+/** Let the echo canceller know that a frame was just queued to the soundcard
+ * @param st Echo canceller state
+ * @param play Signal played to the speaker (received from far end)
+*/
void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play);
-/** Reset the echo canceller state */
+/** Reset the echo canceller to its original state
+ * @param st Echo canceller state
+ */
void speex_echo_state_reset(SpeexEchoState *st);
/** Used like the ioctl function to control the echo canceller parameters
*
- * @param state Encoder state
+ * @param st Echo canceller state
* @param request ioctl-type request (one of the SPEEX_ECHO_* macros)
* @param ptr Data exchanged to-from function
* @return 0 if no error, -1 if request in unknown
*/
int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr);
+
+
+struct SpeexDecorrState_;
+
+typedef struct SpeexDecorrState_ SpeexDecorrState;
+
+
+/** Create a state for the channel decorrelation algorithm
+ This is useful for multi-channel echo cancellation only
+ * @param rate Sampling rate
+ * @param channels Number of channels (it's a bit pointless if you don't have at least 2)
+ * @param frame_size Size of the frame to process at ones (counting samples *per* channel)
+*/
+SpeexDecorrState *speex_decorrelate_new(int rate, int channels, int frame_size);
+
+/** Remove correlation between the channels by modifying the phase and possibly
+ adding noise in a way that is not (or little) perceptible.
+ * @param st Decorrelator state
+ * @param in Input audio in interleaved format
+ * @param out Result of the decorrelation (out *may* alias in)
+ * @param strength How much alteration of the audio to apply from 0 to 100.
+*/
+void speex_decorrelate(SpeexDecorrState *st, const spx_int16_t *in, spx_int16_t *out, int strength);
+
+/** Destroy a Decorrelation state
+ * @param st State to destroy
+*/
+void speex_decorrelate_destroy(SpeexDecorrState *st);
+
+
#ifdef __cplusplus
}
#endif
+
+/** @}*/
#endif
diff --git a/libs/speex/include/speex/speex_header.h b/libs/speex/include/speex/speex_header.h
index 32fb81f64d..f85b2496ae 100644
--- a/libs/speex/include/speex/speex_header.h
+++ b/libs/speex/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 */
@@ -78,9 +83,12 @@ char *speex_header_to_packet(SpeexHeader *header, int *size);
/** Creates a SpeexHeader from a packet */
SpeexHeader *speex_packet_to_header(char *packet, int size);
+/** Frees the memory allocated by either speex_header_to_packet() or speex_packet_to_header() */
+void speex_header_free(void *ptr);
+
#ifdef __cplusplus
}
#endif
-
+/** @} */
#endif
diff --git a/libs/speex/include/speex/speex_jitter.h b/libs/speex/include/speex/speex_jitter.h
index 22f5e14f9a..d68674b13a 100644
--- a/libs/speex/include/speex/speex_jitter.h
+++ b/libs/speex/include/speex/speex_jitter.h
@@ -35,83 +35,163 @@
#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"
+#include "speex/speex_types.h"
#ifdef __cplusplus
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) */
+ spx_uint16_t sequence; /**< RTP Sequence number if available (0 otherwise) */
+ spx_uint32_t user_data; /**< Put whatever data you like here (it's ignored by the jitter buffer) */
};
-
+/** Packet has been retrieved */
#define JITTER_BUFFER_OK 0
+/** Packet is lost or is late */
#define JITTER_BUFFER_MISSING 1
-#define JITTER_BUFFER_INCOMPLETE 2
+/** A "fake" packet is meant to be inserted here to increase buffering */
+#define JITTER_BUFFER_INSERTION 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 */
-JitterBuffer *jitter_buffer_init(int tick);
-/** Reset 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_AVAILABLE_COUNT wouldn't make sense */
+
+/** Get the amount of available packets currently buffered */
+#define JITTER_BUFFER_GET_AVAILABLE_COUNT 3
+/** Included because of an early misspelling (will remove in next release) */
+#define JITTER_BUFFER_GET_AVALIABLE_COUNT 3
+
+/** Assign a function to destroy unused packet. When setting that, the jitter
+ buffer no longer copies packet data. */
+#define JITTER_BUFFER_SET_DESTROY_CALLBACK 4
+/** */
+#define JITTER_BUFFER_GET_DESTROY_CALLBACK 5
+
+/** Tell the jitter buffer to only adjust the delay in multiples of the step parameter provided */
+#define JITTER_BUFFER_SET_DELAY_STEP 6
+/** */
+#define JITTER_BUFFER_GET_DELAY_STEP 7
+
+/** Tell the jitter buffer to only do concealment in multiples of the size parameter provided */
+#define JITTER_BUFFER_SET_CONCEALMENT_SIZE 8
+#define JITTER_BUFFER_GET_CONCEALMENT_SIZE 9
+
+/** Absolute max amount of loss that can be tolerated regardless of the delay. Typical loss
+ should be half of that or less. */
+#define JITTER_BUFFER_SET_MAX_LATE_RATE 10
+#define JITTER_BUFFER_GET_MAX_LATE_RATE 11
+
+/** Equivalent cost of one percent late packet in timestamp units */
+#define JITTER_BUFFER_SET_LATE_COST 12
+#define JITTER_BUFFER_GET_LATE_COST 13
+
+
+/** Initialises jitter buffer
+ *
+ * @param step_size Starting value for the size of concleanment packets and delay
+ adjustment steps. Can be changed at any time using JITTER_BUFFER_SET_DELAY_STEP
+ and JITTER_BUFFER_GET_CONCEALMENT_SIZE.
+ * @return Newly created jitter buffer state
+ */
+JitterBuffer *jitter_buffer_init(int step_size);
+
+/** 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 desired_span Number of samples (or units) we wish to get from the buffer (no guarantee)
+ * @param current_timestamp Timestamp for the returned packet
+*/
+int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset);
-/** Get pointer timestamp of jitter buffer */
+/** Used right after jitter_buffer_get() to obtain another packet that would have the same timestamp.
+ * This is mainly useful for media where a single "frame" can be split into several packets.
+ *
+ * @param jitter Jitter buffer state
+ * @param packet Returned packet
+ */
+int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet);
+
+/** 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);
+/** Telling the jitter buffer about the remaining data in the application buffer
+ * @param jitter Jitter buffer state
+ * @param rem Amount of data buffered by the application (timestamp units)
+ */
+void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem);
-/** Speex jitter-buffer state. */
-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 */
- spx_int32_t frame_size; /**< Frame size of Speex decoder */
-} SpeexJitter;
+/** 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);
-/** Initialise jitter buffer */
-void speex_jitter_init(SpeexJitter *jitter, void *decoder, int sampling_rate);
+int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset);
-/** Destroy jitter buffer */
-void speex_jitter_destroy(SpeexJitter *jitter);
-
-/** Put one packet into the jitter buffer */
-void speex_jitter_put(SpeexJitter *jitter, char *packet, int len, int timestamp);
-
-/** Get one packet from the jitter buffer */
-void speex_jitter_get(SpeexJitter *jitter, spx_int16_t *out, int *start_offset);
-
-/** Get pointer timestamp of jitter buffer */
-int speex_jitter_get_pointer_timestamp(SpeexJitter *jitter);
+/* @} */
#ifdef __cplusplus
}
#endif
-
#endif
diff --git a/libs/speex/include/speex/speex_preprocess.h b/libs/speex/include/speex/speex_preprocess.h
index 5bb3a2c424..f8eef2cd91 100644
--- a/libs/speex/include/speex/speex_preprocess.h
+++ b/libs/speex/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
-
-struct drft_lookup;
-
-/** 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 */
+/** State of the preprocessor (one per channel). Should never be accessed directly. */
+struct SpeexPreprocessState_;
- 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 */
+/** State of the preprocessor (one per channel). Should never be accessed directly. */
+typedef struct SpeexPreprocessState_ SpeexPreprocessState;
- 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);
@@ -138,9 +110,9 @@ int speex_preprocess_ctl(SpeexPreprocessState *st, int request, void *ptr);
/** Get preprocessor Voice Activity Detection state */
#define SPEEX_PREPROCESS_GET_VAD 5
-/** Set preprocessor Automatic Gain Control level */
+/** Set preprocessor Automatic Gain Control level (float) */
#define SPEEX_PREPROCESS_SET_AGC_LEVEL 6
-/** Get preprocessor Automatic Gain Control level */
+/** Get preprocessor Automatic Gain Control level (float) */
#define SPEEX_PREPROCESS_GET_AGC_LEVEL 7
/** Set preprocessor dereverb state */
@@ -158,14 +130,90 @@ 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
+
+/* Can't set loudness */
+/** Get loudness */
+#define SPEEX_PREPROCESS_GET_AGC_LOUDNESS 33
+
+/* Can't set gain */
+/** Get current gain (int32 percent) */
+#define SPEEX_PREPROCESS_GET_AGC_GAIN 35
+
+/* Can't set spectrum size */
+/** Get spectrum size for power spectrum (int32) */
+#define SPEEX_PREPROCESS_GET_PSD_SIZE 37
+
+/* Can't set power spectrum */
+/** Get power spectrum (int32[] of squared values) */
+#define SPEEX_PREPROCESS_GET_PSD 39
+
+/* Can't set noise size */
+/** Get spectrum size for noise estimate (int32) */
+#define SPEEX_PREPROCESS_GET_NOISE_PSD_SIZE 41
+
+/* Can't set noise estimate */
+/** Get noise estimate (int32[] of squared values) */
+#define SPEEX_PREPROCESS_GET_NOISE_PSD 43
+
+/* Can't set speech probability */
+/** Get speech probability in last frame (int32). */
+#define SPEEX_PREPROCESS_GET_PROB 45
+
+/** Set preprocessor Automatic Gain Control level (int32) */
+#define SPEEX_PREPROCESS_SET_AGC_TARGET 46
+/** Get preprocessor Automatic Gain Control level (int32) */
+#define SPEEX_PREPROCESS_GET_AGC_TARGET 47
+
#ifdef __cplusplus
}
#endif
+/** @}*/
#endif
diff --git a/libs/speex/include/speex/speex_resampler.h b/libs/speex/include/speex/speex_resampler.h
new file mode 100644
index 0000000000..54eef8d7b8
--- /dev/null
+++ b/libs/speex/include/speex/speex_resampler.h
@@ -0,0 +1,340 @@
+/* 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_get_input_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_latency)
+#define speex_resampler_get_output_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_latency)
+#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);
+
+/** Get the latency in input samples introduced by the resampler.
+ * @param st Resampler state
+ */
+int speex_resampler_get_input_latency(SpeexResamplerState *st);
+
+/** Get the latency in output samples introduced by the resampler.
+ * @param st Resampler state
+ */
+int speex_resampler_get_output_latency(SpeexResamplerState *st);
+
+/** 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/libs/speex/include/speex/speex_stereo.h b/libs/speex/include/speex/speex_stereo.h
index 6ccaa318f9..a259713b82 100644
--- a/libs/speex/include/speex/speex_stereo.h
+++ b/libs/speex/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"
@@ -42,7 +46,7 @@
extern "C" {
#endif
-/** State used for decoding (intensity) stereo information */
+/** If you access any of these fields directly, I'll personally come and bite you */
typedef struct SpeexStereoState {
float balance; /**< Left/right balance info */
float e_ratio; /**< Ratio of energies: E(left+right)/[E(left)+E(right)] */
@@ -52,9 +56,18 @@ typedef struct SpeexStereoState {
float reserved2; /**< Reserved for future use */
} SpeexStereoState;
-/** Initialization value for a stereo state */
+/** Deprecated. Use speex_stereo_state_init() instead. */
#define SPEEX_STEREO_STATE_INIT {1,.5,1,1,0,0}
+/** Initialise/create a stereo stereo state */
+SpeexStereoState *speex_stereo_state_init();
+
+/** Reset/re-initialise an already allocated stereo state */
+void speex_stereo_state_reset(SpeexStereoState *stereo);
+
+/** Destroy a stereo stereo state */
+void speex_stereo_state_destroy(SpeexStereoState *stereo);
+
/** Transforms a stereo frame into a mono frame and stores intensity stereo info in 'bits' */
void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits);
@@ -74,5 +87,5 @@ int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data);
}
#endif
-
+/** @} */
#endif
diff --git a/libs/speex/include/speex/speex_types.h b/libs/speex/include/speex/speex_types.h
index c746d4f6f6..852fed801d 100644
--- a/libs/speex/include/speex/speex_types.h
+++ b/libs/speex/include/speex/speex_types.h
@@ -31,10 +31,10 @@
typedef _G_int16_t spx_int16_t;
typedef _G_uint16_t spx_uint16_t;
# elif defined(__MINGW32__)
- typedef short spx_int16_t;
- typedef unsigned short spx_uint16_t;
- typedef int spx_int32_t;
- typedef unsigned int spx_uint32_t;
+ typedef short spx_int16_t;
+ typedef unsigned short spx_uint16_t;
+ typedef int spx_int32_t;
+ typedef unsigned int spx_uint32_t;
# elif defined(__MWERKS__)
typedef int spx_int32_t;
typedef unsigned int spx_uint32_t;
@@ -56,7 +56,7 @@
typedef SInt32 spx_int32_t;
typedef UInt32 spx_uint32_t;
-#elif defined(__MACOSX__) /* MacOS X Framework build */
+#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
# include
typedef int16_t spx_int16_t;
diff --git a/libs/speex/libspeex/Makefile.am b/libs/speex/libspeex/Makefile.am
index 0972172e65..3d4e03f9a6 100644
--- a/libs/speex/libspeex/Makefile.am
+++ b/libs/speex/libspeex/Makefile.am
@@ -2,41 +2,54 @@
#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)
+INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_builddir) @OGG_CFLAGS@ @FFT_CFLAGS@
-lib_LTLIBRARIES = libspeex.la
+lib_LTLIBRARIES = libspeex.la libspeexdsp.la
# Sources for compilation in the library
-libspeex_la_SOURCES = nb_celp.c sb_celp.c lpc.c ltp.c lsp.c quant_lsp.c \
- lsp_tables_nb.c gain_table.c gain_table_lbr.c cb_search.c filters.c bits.c \
- modes.c speex.c vq.c high_lsp_tables.c vbr.c hexc_table.c \
- exc_5_256_table.c exc_5_64_table.c exc_8_128_table.c exc_10_32_table.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
+libspeex_la_SOURCES = cb_search.c exc_10_32_table.c exc_8_128_table.c \
+ filters.c gain_table.c hexc_table.c high_lsp_tables.c lsp.c \
+ ltp.c speex.c stereo.c vbr.c vq.c bits.c exc_10_16_table.c \
+ exc_20_32_table.c exc_5_256_table.c exc_5_64_table.c gain_table_lbr.c hexc_10_32_table.c \
+ lpc.c lsp_tables_nb.c modes.c modes_wb.c nb_celp.c quant_lsp.c sb_celp.c \
+ speex_callbacks.c speex_header.c window.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 \
- modes.h sb_celp.h vbr.h misc.h misc_bfin.h ltp_sse.h ltp_arm4.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
+if BUILD_KISS_FFT
+ FFTSRC=kiss_fft.c _kiss_fft_guts.h kiss_fft.h kiss_fftr.c kiss_fftr.h
+else
+if BUILD_SMALLFT
+ FFTSRC=smallft.c
+else
+ FFTSRC=
+endif
+endif
+
+libspeexdsp_la_SOURCES = preprocess.c jitter.c mdf.c fftwrap.c filterbank.c resample.c buffer.c scal.c $(FFTSRC)
+
+noinst_HEADERS = arch.h cb_search_arm4.h cb_search_bfin.h cb_search_sse.h \
+ filters.h filters_arm4.h filters_bfin.h filters_sse.h fixed_arm4.h \
+ fixed_arm5e.h fixed_bfin.h fixed_debug.h lpc.h lpc_bfin.h ltp.h ltp_arm4.h \
+ ltp_sse.h math_approx.h misc_bfin.h nb_celp.h quant_lsp.h sb_celp.h \
+ stack_alloc.h vbr.h vq.h vq_arm4.h vq_bfin.h vq_sse.h cb_search.h fftwrap.h \
+ filterbank.h fixed_generic.h lsp.h lsp_bfin.h ltp_bfin.h modes.h os_support.h \
+ pseudofloat.h quant_lsp_bfin.h smallft.h vorbis_psy.h resample_sse.h
libspeex_la_LDFLAGS = -no-undefined -version-info @SPEEX_LT_CURRENT@:@SPEEX_LT_REVISION@:@SPEEX_LT_AGE@
+libspeexdsp_la_LDFLAGS = -no-undefined -version-info @SPEEX_LT_CURRENT@:@SPEEX_LT_REVISION@:@SPEEX_LT_AGE@
-noinst_PROGRAMS = testenc testenc_wb testenc_uwb testdenoise testecho
+noinst_PROGRAMS = testenc testenc_wb testenc_uwb testdenoise testecho testjitter
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 = libspeexdsp.la @FFT_LIBS@
testecho_SOURCES = testecho.c
-testecho_LDADD = $(top_builddir)/libspeex/libspeex.la
+testecho_LDADD = libspeexdsp.la @FFT_LIBS@
+testjitter_SOURCES = testjitter.c
+testjitter_LDADD = libspeexdsp.la @FFT_LIBS@
diff --git a/libs/speex/libspeex/_kiss_fft_guts.h b/libs/speex/libspeex/_kiss_fft_guts.h
index 72acee184a..6571e79c0c 100644
--- a/libs/speex/libspeex/_kiss_fft_guts.h
+++ b/libs/speex/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
@@ -44,7 +45,7 @@ struct kiss_fft_state{
C_ADDTO( res , a) : res += a
* */
#ifdef FIXED_POINT
-#include "misc.h"
+#include "arch.h"
# define FRACBITS 15
# define SAMPPROD spx_int32_t
#define SAMP_MAX 32767
@@ -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/libs/speex/libspeex/arch.h b/libs/speex/libspeex/arch.h
index 0500437395..d38c36ce7c 100644
--- a/libs/speex/libspeex/arch.h
+++ b/libs/speex/libspeex/arch.h
@@ -35,12 +35,55 @@
#ifndef ARCH_H
#define ARCH_H
+#ifndef SPEEX_VERSION
+#define SPEEX_MAJOR_VERSION 1 /**< Major Speex version. */
+#define SPEEX_MINOR_VERSION 1 /**< Minor Speex version. */
+#define SPEEX_MICRO_VERSION 15 /**< Micro Speex version. */
+#define SPEEX_EXTRA_VERSION "" /**< Extra Speex version. */
+#define SPEEX_VERSION "speex-1.2beta3" /**< Speex version string. */
+#endif
+
+/* A couple test to catch stupid option combinations */
+#ifdef FIXED_POINT
+
+#ifdef FLOATING_POINT
+#error You cannot compile as floating point and fixed point at the same time
+#endif
+#ifdef _USE_SSE
+#error SSE is only for floating-point
+#endif
+#if ((defined (ARM4_ASM)||defined (ARM4_ASM)) && defined(BFIN_ASM)) || (defined (ARM4_ASM)&&defined(ARM5E_ASM))
+#error Make up your mind. What CPU do you have?
+#endif
+#ifdef VORBIS_PSYCHO
+#error Vorbis-psy model currently not implemented in fixed-point
+#endif
+
+#else
+
+#ifndef FLOATING_POINT
+#error You now need to define either FIXED_POINT or FLOATING_POINT
+#endif
+#if defined (ARM4_ASM) || defined(ARM5E_ASM) || defined(BFIN_ASM)
+#error I suppose you can have a [ARM4/ARM5E/Blackfin] that has float instructions?
+#endif
+#ifdef FIXED_POINT_DEBUG
+#error "Don't you think enabling fixed-point is a good thing to do if you want to debug that?"
+#endif
+
+
+#endif
+
+#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
@@ -64,10 +107,12 @@ typedef spx_word32_t spx_sig_t;
#define LPC_SHIFT 13
#define LSP_SHIFT 13
#define SIG_SHIFT 14
+#define GAIN_SHIFT 6
#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
@@ -80,8 +125,6 @@ typedef spx_word32_t spx_sig_t;
#include "fixed_arm5e.h"
#elif defined (ARM4_ASM)
#include "fixed_arm4.h"
-#elif defined (ARM5E_ASM)
-#include "fixed_arm5e.h"
#elif defined (BFIN_ASM)
#include "fixed_bfin.h"
#endif
@@ -106,13 +149,11 @@ typedef float spx_word32_t;
#define GAIN_SCALING 1.f
#define GAIN_SCALING_1 1.f
-#define LPC_SHIFT 0
-#define LSP_SHIFT 0
-#define SIG_SHIFT 0
#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 +168,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 +189,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))
@@ -186,4 +229,11 @@ typedef float spx_word32_t;
#endif
+
+
+#ifdef FIXED_DEBUG
+extern long long spx_mips;
+#endif
+
+
#endif
diff --git a/libs/speex/libspeex/bits.c b/libs/speex/libspeex/bits.c
index 376e804f92..3ef7c6c1b5 100644
--- a/libs/speex/libspeex/bits.c
+++ b/libs/speex/libspeex/bits.c
@@ -37,14 +37,15 @@
#endif
#include
-#include "misc.h"
+#include "arch.h"
+#include "os_support.h"
/* Maximum size of the bit-stream (for fixed-size allocation) */
#ifndef MAX_CHARS_PER_FRAME
#define MAX_CHARS_PER_FRAME (2000/BYTES_PER_CHAR)
#endif
-void speex_bits_init(SpeexBits *bits)
+EXPORT void speex_bits_init(SpeexBits *bits)
{
bits->chars = (char*)speex_alloc(MAX_CHARS_PER_FRAME);
if (!bits->chars)
@@ -57,7 +58,7 @@ void speex_bits_init(SpeexBits *bits)
speex_bits_reset(bits);
}
-void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size)
+EXPORT void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size)
{
bits->chars = (char*)buff;
bits->buf_size = buf_size;
@@ -67,15 +68,30 @@ void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size)
speex_bits_reset(bits);
}
-void speex_bits_destroy(SpeexBits *bits)
+EXPORT void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size)
+{
+ bits->chars = (char*)buff;
+ bits->buf_size = buf_size;
+
+ bits->owner=0;
+
+ bits->nbBits=buf_size<charPtr=0;
+ bits->bitPtr=0;
+ bits->overflow=0;
+
+}
+
+EXPORT void speex_bits_destroy(SpeexBits *bits)
{
if (bits->owner)
speex_free(bits->chars);
/* Will do something once the allocation is dynamic */
}
-void speex_bits_reset(SpeexBits *bits)
+EXPORT 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;
@@ -83,20 +99,20 @@ void speex_bits_reset(SpeexBits *bits)
bits->overflow=0;
}
-void speex_bits_rewind(SpeexBits *bits)
+EXPORT void speex_bits_rewind(SpeexBits *bits)
{
bits->charPtr=0;
bits->bitPtr=0;
bits->overflow=0;
}
-void speex_bits_read_from(SpeexBits *bits, char *chars, int len)
+EXPORT void speex_bits_read_from(SpeexBits *bits, char *chars, int len)
{
int i;
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 +125,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;
}
}
@@ -130,18 +146,14 @@ void speex_bits_read_from(SpeexBits *bits, char *chars, int len)
static void speex_bits_flush(SpeexBits *bits)
{
- int i;
int nchars = ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR);
if (bits->charPtr>0)
- {
- for (i=bits->charPtr;ichars[i-bits->charPtr]=bits->chars[i];
- }
+ SPEEX_MOVE(bits->chars, &bits->chars[bits->charPtr], nchars-bits->charPtr);
bits->nbBits -= bits->charPtr<charPtr=0;
}
-void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes)
+EXPORT void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes)
{
int i,pos;
int nchars = nbytes/BYTES_PER_CHAR;
@@ -158,10 +170,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;
}
}
@@ -173,7 +185,7 @@ void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes)
bits->nbBits+=nchars<chars[0]=bits->chars[max_nchars];
else
bits->chars[0]=0;
- for (i=1;i<((bits->nbBits)>>LOG2_BITS_PER_CHAR)+1;i++)
- bits->chars[i]=0;
bits->charPtr=0;
bits->nbBits &= (BITS_PER_CHAR-1);
return max_nchars*BYTES_PER_CHAR;
}
-void speex_bits_pack(SpeexBits *bits, int data, int nbBits)
+EXPORT void speex_bits_pack(SpeexBits *bits, int data, int nbBits)
{
unsigned int d=data;
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 {
@@ -260,7 +269,7 @@ void speex_bits_pack(SpeexBits *bits, int data, int nbBits)
}
}
-int speex_bits_unpack_signed(SpeexBits *bits, int nbBits)
+EXPORT int speex_bits_unpack_signed(SpeexBits *bits, int nbBits)
{
unsigned int d=speex_bits_unpack_unsigned(bits,nbBits);
/* If number is negative */
@@ -271,7 +280,7 @@ int speex_bits_unpack_signed(SpeexBits *bits, int nbBits)
return d;
}
-unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits)
+EXPORT unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits)
{
unsigned int d=0;
if ((bits->charPtr<bitPtr+nbBits>bits->nbBits)
@@ -293,7 +302,7 @@ unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits)
return d;
}
-unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits)
+EXPORT unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits)
{
unsigned int d=0;
int bitPtr, charPtr;
@@ -322,7 +331,7 @@ unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits)
return d;
}
-int speex_bits_peek(SpeexBits *bits)
+EXPORT int speex_bits_peek(SpeexBits *bits)
{
if ((bits->charPtr<bitPtr+1>bits->nbBits)
bits->overflow=1;
@@ -331,7 +340,7 @@ int speex_bits_peek(SpeexBits *bits)
return (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1;
}
-void speex_bits_advance(SpeexBits *bits, int n)
+EXPORT void speex_bits_advance(SpeexBits *bits, int n)
{
if (((bits->charPtr<bitPtr+n>bits->nbBits) || bits->overflow){
bits->overflow=1;
@@ -341,7 +350,7 @@ void speex_bits_advance(SpeexBits *bits, int n)
bits->bitPtr = (bits->bitPtr+n) & (BITS_PER_CHAR-1); /* modulo by BITS_PER_CHAR */
}
-int speex_bits_remaining(SpeexBits *bits)
+EXPORT int speex_bits_remaining(SpeexBits *bits)
{
if (bits->overflow)
return -1;
@@ -349,12 +358,12 @@ int speex_bits_remaining(SpeexBits *bits)
return bits->nbBits-((bits->charPtr<bitPtr);
}
-int speex_bits_nbytes(SpeexBits *bits)
+EXPORT int speex_bits_nbytes(SpeexBits *bits)
{
return ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR);
}
-void speex_bits_insert_terminator(SpeexBits *bits)
+EXPORT void speex_bits_insert_terminator(SpeexBits *bits)
{
if (bits->bitPtr)
speex_bits_pack(bits, 0, 1);
diff --git a/libs/speex/libspeex/buffer.c b/libs/speex/libspeex/buffer.c
new file mode 100644
index 0000000000..6cfd5a3413
--- /dev/null
+++ b/libs/speex/libspeex/buffer.c
@@ -0,0 +1,176 @@
+/* Copyright (C) 2007 Jean-Marc Valin
+
+ File: buffer.c
+ This is a very simple ring buffer implementation. It is not thread-safe
+ so you need to do your own locking.
+
+ 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 "os_support.h"
+#include "arch.h"
+#include
+
+struct SpeexBuffer_ {
+ char *data;
+ int size;
+ int read_ptr;
+ int write_ptr;
+ int available;
+};
+
+EXPORT SpeexBuffer *speex_buffer_init(int size)
+{
+ SpeexBuffer *st = speex_alloc(sizeof(SpeexBuffer));
+ st->data = speex_alloc(size);
+ st->size = size;
+ st->read_ptr = 0;
+ st->write_ptr = 0;
+ st->available = 0;
+ return st;
+}
+
+EXPORT void speex_buffer_destroy(SpeexBuffer *st)
+{
+ speex_free(st->data);
+ speex_free(st);
+}
+
+EXPORT int speex_buffer_write(SpeexBuffer *st, void *_data, int len)
+{
+ int end;
+ int end1;
+ char *data = _data;
+ if (len > st->size)
+ {
+ data += len-st->size;
+ len = st->size;
+ }
+ end = st->write_ptr + len;
+ end1 = end;
+ if (end1 > st->size)
+ end1 = st->size;
+ SPEEX_COPY(st->data + st->write_ptr, data, end1 - st->write_ptr);
+ if (end > st->size)
+ {
+ end -= st->size;
+ SPEEX_COPY(st->data, data+end1 - st->write_ptr, end);
+ }
+ st->available += len;
+ if (st->available > st->size)
+ {
+ st->available = st->size;
+ st->read_ptr = st->write_ptr;
+ }
+ st->write_ptr += len;
+ if (st->write_ptr > st->size)
+ st->write_ptr -= st->size;
+ return len;
+}
+
+EXPORT int speex_buffer_writezeros(SpeexBuffer *st, int len)
+{
+ /* This is almost the same as for speex_buffer_write() but using
+ SPEEX_MEMSET() instead of SPEEX_COPY(). Update accordingly. */
+ int end;
+ int end1;
+ if (len > st->size)
+ {
+ len = st->size;
+ }
+ end = st->write_ptr + len;
+ end1 = end;
+ if (end1 > st->size)
+ end1 = st->size;
+ SPEEX_MEMSET(st->data + st->write_ptr, 0, end1 - st->write_ptr);
+ if (end > st->size)
+ {
+ end -= st->size;
+ SPEEX_MEMSET(st->data, 0, end);
+ }
+ st->available += len;
+ if (st->available > st->size)
+ {
+ st->available = st->size;
+ st->read_ptr = st->write_ptr;
+ }
+ st->write_ptr += len;
+ if (st->write_ptr > st->size)
+ st->write_ptr -= st->size;
+ return len;
+}
+
+EXPORT int speex_buffer_read(SpeexBuffer *st, void *_data, int len)
+{
+ int end, end1;
+ char *data = _data;
+ if (len > st->available)
+ {
+ SPEEX_MEMSET(data+st->available, 0, st->size-st->available);
+ len = st->available;
+ }
+ end = st->read_ptr + len;
+ end1 = end;
+ if (end1 > st->size)
+ end1 = st->size;
+ SPEEX_COPY(data, st->data + st->read_ptr, end1 - st->read_ptr);
+
+ if (end > st->size)
+ {
+ end -= st->size;
+ SPEEX_COPY(data+end1 - st->read_ptr, st->data, end);
+ }
+ st->available -= len;
+ st->read_ptr += len;
+ if (st->read_ptr > st->size)
+ st->read_ptr -= st->size;
+ return len;
+}
+
+EXPORT int speex_buffer_get_available(SpeexBuffer *st)
+{
+ return st->available;
+}
+
+EXPORT int speex_buffer_resize(SpeexBuffer *st, int len)
+{
+ int old_len = st->size;
+ if (len > old_len)
+ {
+ st->data = speex_realloc(st->data, len);
+ /* FIXME: move data/pointers properly for growing the buffer */
+ } else {
+ /* FIXME: move data/pointers properly for shrinking the buffer */
+ st->data = speex_realloc(st->data, len);
+ }
+ return len;
+}
diff --git a/libs/speex/libspeex/cb_search.c b/libs/speex/libspeex/cb_search.c
index 5c68826095..63f4c6a4bd 100644
--- a/libs/speex/libspeex/cb_search.c
+++ b/libs/speex/libspeex/cb_search.c
@@ -37,7 +37,9 @@
#include "filters.h"
#include "stack_alloc.h"
#include "vq.h"
-#include "misc.h"
+#include "arch.h"
+#include "math_approx.h"
+#include "os_support.h"
#ifdef _USE_SSE
#include "cb_search_sse.h"
@@ -146,8 +148,7 @@ int update_target
ALLOC(e, nsf, spx_sig_t);
/* FIXME: Do we still need to copy the target? */
- for (i=0;i
-#include "misc.h"
+#include "arch.h"
/** Split codebook parameters. */
typedef struct split_cb_params {
diff --git a/libs/speex/libspeex/cb_search_bfin.h b/libs/speex/libspeex/cb_search_bfin.h
index 52cc4b3bae..ae9cf8343d 100644
--- a/libs/speex/libspeex/cb_search_bfin.h
+++ b/libs/speex/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/libs/speex/libspeex/echo_diagnostic.m b/libs/speex/libspeex/echo_diagnostic.m
new file mode 100644
index 0000000000..aebf390672
--- /dev/null
+++ b/libs/speex/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/libs/speex/libspeex/fftwrap.c b/libs/speex/libspeex/fftwrap.c
index 43a9b18b8b..4f37e1b3fb 100644
--- a/libs/speex/libspeex/fftwrap.c
+++ b/libs/speex/libspeex/fftwrap.c
@@ -36,11 +36,8 @@
#include "config.h"
#endif
-/*#define USE_SMALLFT*/
-#define USE_KISS_FFT
-
-
-#include "misc.h"
+#include "arch.h"
+#include "os_support.h"
#define MAX_FFT_SIZE 2048
@@ -64,7 +61,7 @@ static int maximize_range(spx_word16_t *in, spx_word16_t *out, spx_word16_t boun
}
for (i=0;i> shift;
+ out[i] = PSHR16(in[i], shift);
}
}
#endif
@@ -103,8 +100,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 +117,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;
@@ -130,6 +126,119 @@ void spx_ifft(void *table, float *in, float *out)
spx_drft_backward((struct drft_lookup *)table, out);
}
+#elif defined(USE_INTEL_MKL)
+#include
+
+struct mkl_config {
+ DFTI_DESCRIPTOR_HANDLE desc;
+ int N;
+};
+
+void *spx_fft_init(int size)
+{
+ struct mkl_config *table = (struct mkl_config *) speex_alloc(sizeof(struct mkl_config));
+ table->N = size;
+ DftiCreateDescriptor(&table->desc, DFTI_SINGLE, DFTI_REAL, 1, size);
+ DftiSetValue(table->desc, DFTI_PACKED_FORMAT, DFTI_PACK_FORMAT);
+ DftiSetValue(table->desc, DFTI_PLACEMENT, DFTI_NOT_INPLACE);
+ DftiSetValue(table->desc, DFTI_FORWARD_SCALE, 1.0f / size);
+ DftiCommitDescriptor(table->desc);
+ return table;
+}
+
+void spx_fft_destroy(void *table)
+{
+ struct mkl_config *t = (struct mkl_config *) table;
+ DftiFreeDescriptor(t->desc);
+ speex_free(table);
+}
+
+void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out)
+{
+ struct mkl_config *t = (struct mkl_config *) table;
+ DftiComputeForward(t->desc, in, out);
+}
+
+void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out)
+{
+ struct mkl_config *t = (struct mkl_config *) table;
+ DftiComputeBackward(t->desc, in, out);
+}
+
+#elif defined(USE_GPL_FFTW3)
+
+#include
+
+struct fftw_config {
+ float *in;
+ float *out;
+ fftwf_plan fft;
+ fftwf_plan ifft;
+ int N;
+};
+
+void *spx_fft_init(int size)
+{
+ struct fftw_config *table = (struct fftw_config *) speex_alloc(sizeof(struct fftw_config));
+ table->in = fftwf_malloc(sizeof(float) * (size+2));
+ table->out = fftwf_malloc(sizeof(float) * (size+2));
+
+ table->fft = fftwf_plan_dft_r2c_1d(size, table->in, (fftwf_complex *) table->out, FFTW_PATIENT);
+ table->ifft = fftwf_plan_dft_c2r_1d(size, (fftwf_complex *) table->in, table->out, FFTW_PATIENT);
+
+ table->N = size;
+ return table;
+}
+
+void spx_fft_destroy(void *table)
+{
+ struct fftw_config *t = (struct fftw_config *) table;
+ fftwf_destroy_plan(t->fft);
+ fftwf_destroy_plan(t->ifft);
+ fftwf_free(t->in);
+ fftwf_free(t->out);
+ speex_free(table);
+}
+
+
+void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out)
+{
+ int i;
+ struct fftw_config *t = (struct fftw_config *) table;
+ const int N = t->N;
+ float *iptr = t->in;
+ float *optr = t->out;
+ const float m = 1.0 / N;
+ for(i=0;ifft);
+
+ out[0] = optr[0];
+ for(i=1;iN;
+ float *iptr = t->in;
+ float *optr = t->out;
+
+ iptr[0] = in[0];
+ iptr[1] = 0.0f;
+ for(i=1;iifft);
+
+ for(i=0;ifreq_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 +265,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 +272,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;iN>>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 +288,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;iN>>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;iN;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;iN>>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/libs/speex/libspeex/fftwrap.h b/libs/speex/libspeex/fftwrap.h
index 826b38e979..dfaf489441 100644
--- a/libs/speex/libspeex/fftwrap.h
+++ b/libs/speex/libspeex/fftwrap.h
@@ -35,7 +35,7 @@
#ifndef FFTWRAP_H
#define FFTWRAP_H
-#include "misc.h"
+#include "arch.h"
/** Compute tables for an FFT */
void *spx_fft_init(int size);
diff --git a/libs/speex/libspeex/filterbank.c b/libs/speex/libspeex/filterbank.c
new file mode 100644
index 0000000000..e2fb71d4ba
--- /dev/null
+++ b/libs/speex/libspeex/filterbank.c
@@ -0,0 +1,227 @@
+/* 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 "arch.h"
+#include
+#include "math_approx.h"
+#include "os_support.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(sampling/2));
+ 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 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;inb_banks;i++)
+ bank->scaling[i] = 0;
+ for (i=0;ilen;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;inb_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;inb_banks;i++)
+ mel[i] = 0;
+
+ for (i=0;ilen;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;inb_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;ilen;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;inb_banks;i++)
+ mel[i] = 0;
+
+ for (i=0;ilen;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;inb_banks;i++)
+ mel[i] *= bank->scaling[i];
+}
+
+void filterbank_compute_psd(FilterBank *bank, float *mel, float *ps)
+{
+ int i;
+ for (i=0;ilen;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;inb_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/libs/speex/libspeex/filterbank.h b/libs/speex/libspeex/filterbank.h
new file mode 100644
index 0000000000..3e889a22f7
--- /dev/null
+++ b/libs/speex/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 "arch.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/libs/speex/libspeex/filters.c b/libs/speex/libspeex/filters.c
index a1111ee812..36ef4f697e 100644
--- a/libs/speex/libspeex/filters.c
+++ b/libs/speex/libspeex/filters.c
@@ -36,7 +36,7 @@
#include "filters.h"
#include "stack_alloc.h"
-#include "misc.h"
+#include "arch.h"
#include "math_approx.h"
#include "ltp.h"
#include
@@ -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=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>1;
for (i=0;i>1;
+ N2 = N>>1;
+ ALLOC(xx1, M2+N2, spx_word16_t);
+ ALLOC(xx2, M2+N2, 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 < 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 < N; i += 4) {
+ 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];
+ a0 = a[2*j];
+ a1 = a[2*j+1];
+ x11 = xx1[N2-1+j-i];
+ x21 = xx2[N2-1+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));
+#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];
- a0 = a[j+2];
- a1 = a[j+3];
- x0 = xx[N+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;i16383)
+ {
+ scaledown = 1;
+ break;
+ }
+ }
+ if (scaledown)
+ {
+ for (i=0;i>2), "3" (sig_shift)
@@ -95,295 +94,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
-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/libs/speex/libspeex/fixed_debug.h b/libs/speex/libspeex/fixed_debug.h
index 65c5712d32..54f3866e8f 100644
--- a/libs/speex/libspeex/fixed_debug.h
+++ b/libs/speex/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_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<>1))),shift))
+#define PSHR32(a,shift) (SHR32(ADD32((a),((EXTEND32(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);
- spx_mips++;
- return res;
-}
-static inline short SUB16(int a, int b)
-{
- int res;
- if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
{
- fprintf (stderr, "SUB16: inputs are not short: %d %d\n", a, b);
+ fprintf (stderr, "ADD16: output is not short: %d+%d=%d in %s: line %d\n", a,b,res, file, line);
}
- res = a-b;
- if (!VERIFY_SHORT(res))
- fprintf (stderr, "SUB16: output is not short: %d\n", res);
spx_mips++;
return res;
}
-static inline int ADD32(long long a, long long 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 in %s: line %d\n", a, b, file, line);
+ }
+ res = a-b;
+ if (!VERIFY_SHORT(res))
+ fprintf (stderr, "SUB16: output is not short: %d in %s: line %d\n", res, file, line);
+ spx_mips++;
+ return res;
+}
+
+#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)>=(EXTEND32(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)>=(EXTEND32(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) + ((EXTEND32(1)<>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/libs/speex/libspeex/fixed_generic.h b/libs/speex/libspeex/fixed_generic.h
index 375050c353..3fb096ed90 100644
--- a/libs/speex/libspeex/fixed_generic.h
+++ b/libs/speex/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)+((EXTEND32(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)+((EXTEND32(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/libs/speex/libspeex/jitter.c b/libs/speex/libspeex/jitter.c
index 6d5f2adaee..17bd044fc3 100644
--- a/libs/speex/libspeex/jitter.c
+++ b/libs/speex/libspeex/jitter.c
@@ -32,283 +32,490 @@
*/
+/*
+TODO:
+- Add short-term estimate
+- Defensive programming
+ + warn when last returned < last desired (begative buffering)
+ + warn if update_delay not called between get() and tick() or is called twice in a row
+- Linked list structure for holding the packets instead of the current fixed-size array
+ + return memory to a pool
+ + allow pre-allocation of the pool
+ + optional max number of elements
+- Statistics
+ + drift
+ + loss
+ + late
+ + jitter
+ + buffering delay
+*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#include "misc.h"
+#include "arch.h"
#include
#include
#include
-#include
+#include "os_support.h"
-#define LATE_BINS 10
-#define MAX_MARGIN 30 /**< Number of bins in margin histogram */
+#ifndef NULL
+#define NULL 0
+#endif
#define SPEEX_JITTER_MAX_BUFFER_SIZE 200 /**< Maximum number of packets in jitter buffer */
-
+#define TSUB(a,b) ((spx_int32_t)((a)-(b)))
#define GT32(a,b) (((spx_int32_t)((a)-(b)))>0)
#define GE32(a,b) (((spx_int32_t)((a)-(b)))>=0)
#define LT32(a,b) (((spx_int32_t)((a)-(b)))<0)
#define LE32(a,b) (((spx_int32_t)((a)-(b)))<=0)
-/** Jitter buffer structure */
-struct JitterBuffer_ {
- spx_uint32_t pointer_timestamp; /**< Timestamp of what we will *get* next */
- spx_uint32_t current_timestamp; /**< Timestamp of the local clock (what we will *play* next) */
+#define ROUND_DOWN(x, step) ((x)<0 ? ((x)-(step)+1)/(step)*(step) : (x)/(step)*(step))
- char *buf[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Buffer of packets (NULL if slot is free) */
- spx_uint32_t timestamp[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Timestamp of packet */
- int span[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Timestamp of packet */
- int len[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Number of bytes in packet */
+#define MAX_TIMINGS 40
+#define MAX_BUFFERS 3
+#define TOP_DELAY 40
- 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 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 */
- float loss_rate; /**< Average loss rate */
+/** Buffer that keeps the time of arrival of the latest packets */
+struct TimingBuffer {
+ int filled; /**< Number of entries occupied in "timing" and "counts"*/
+ int curr_count; /**< Number of packet timings we got (including those we discarded) */
+ spx_int32_t timing[MAX_TIMINGS]; /**< Sorted list of all timings ("latest" packets first) */
+ spx_int16_t counts[MAX_TIMINGS]; /**< Order the packets were put in (will be used for short-term estimate) */
};
+static void tb_init(struct TimingBuffer *tb)
+{
+ tb->filled = 0;
+ tb->curr_count = 0;
+}
+
+/* Add the timing of a new packet to the TimingBuffer */
+static void tb_add(struct TimingBuffer *tb, spx_int16_t timing)
+{
+ int pos;
+ /* Discard packet that won't make it into the list because they're too early */
+ if (tb->filled >= MAX_TIMINGS && timing >= tb->timing[tb->filled-1])
+ {
+ tb->curr_count++;
+ return;
+ }
+
+ /* Find where the timing info goes in the sorted list */
+ pos = 0;
+ /* FIXME: Do bisection instead of linear search */
+ while (posfilled && timing >= tb->timing[pos])
+ {
+ pos++;
+ }
+
+ speex_assert(pos <= tb->filled && pos < MAX_TIMINGS);
+
+ /* Shift everything so we can perform the insertion */
+ if (pos < tb->filled)
+ {
+ int move_size = tb->filled-pos;
+ if (tb->filled == MAX_TIMINGS)
+ move_size -= 1;
+ SPEEX_MOVE(&tb->timing[pos+1], &tb->timing[pos], move_size);
+ SPEEX_MOVE(&tb->counts[pos+1], &tb->counts[pos], move_size);
+ }
+ /* Insert */
+ tb->timing[pos] = timing;
+ tb->counts[pos] = tb->curr_count;
+
+ tb->curr_count++;
+ if (tb->filledfilled++;
+}
+
+
+
+/** Jitter buffer structure */
+struct JitterBuffer_ {
+ spx_uint32_t pointer_timestamp; /**< Timestamp of what we will *get* next */
+ spx_uint32_t last_returned_timestamp; /**< Useful for getting the next packet with the same timestamp (for fragmented media) */
+ spx_uint32_t next_stop; /**< Estimated time the next get() will be called */
+
+ spx_int32_t buffered; /**< Amount of data we think is still buffered by the application (timestamp units)*/
+
+ JitterBufferPacket packets[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packets stored in the buffer */
+ spx_uint32_t arrival[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packet arrival time (0 means it was late, even though it's a valid timestamp) */
+
+ void (*destroy) (void *); /**< Callback for destroying a packet */
+
+ spx_int32_t delay_step; /**< Size of the steps when adjusting buffering (timestamp units) */
+ spx_int32_t concealment_size; /**< Size of the packet loss concealment "units" */
+ 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 auto_adjust; /**< Whether to automatically adjust the delay at any time */
+
+ struct TimingBuffer _tb[MAX_BUFFERS]; /**< Don't use those directly */
+ struct TimingBuffer *timeBuffers[MAX_BUFFERS]; /**< Storing arrival time of latest frames so we can compute some stats */
+ int window_size; /**< Total window over which the late frames are counted */
+ int subwindow_size; /**< Sub-window size for faster computation */
+ int max_late_rate; /**< Absolute maximum amount of late packets tolerable (in percent) */
+ int latency_tradeoff; /**< Latency equivalent of losing one percent of packets */
+ int auto_tradeoff; /**< Latency equivalent of losing one percent of packets (automatic default) */
+
+ int lost_count; /**< Number of consecutive lost packets */
+};
+
+/** Based on available data, this computes the optimal delay for the jitter buffer.
+ The optimised function is in timestamp units and is:
+ cost = delay + late_factor*[number of frames that would be late if we used that delay]
+ @param tb Array of buffers
+ @param late_factor Equivalent cost of a late frame (in timestamp units)
+ */
+static spx_int16_t compute_opt_delay(JitterBuffer *jitter)
+{
+ int i;
+ spx_int16_t opt=0;
+ spx_int32_t best_cost=0x7fffffff;
+ int late = 0;
+ int pos[MAX_BUFFERS];
+ int tot_count;
+ float late_factor;
+ int penalty_taken = 0;
+ int best = 0;
+ int worst = 0;
+ spx_int32_t deltaT;
+ struct TimingBuffer *tb;
+
+ tb = jitter->_tb;
+
+ /* Number of packet timings we have received (including those we didn't keep) */
+ tot_count = 0;
+ for (i=0;ilatency_tradeoff != 0)
+ late_factor = jitter->latency_tradeoff * 100.0f / tot_count;
+ else
+ late_factor = jitter->auto_tradeoff * jitter->window_size/tot_count;
+
+ /*fprintf(stderr, "late_factor = %f\n", late_factor);*/
+ for (i=0;idelay_step);
+ pos[next]++;
+
+ /* Actual cost function that tells us how bad using this delay would be */
+ cost = -latest + late_factor*late;
+ /*fprintf(stderr, "cost %d = %d + %f * %d\n", cost, -latest, late_factor, late);*/
+ if (cost < best_cost)
+ {
+ best_cost = cost;
+ opt = latest;
+ }
+ } else {
+ break;
+ }
+
+ /* For the next timing we will consider, there will be one more late packet to count */
+ late++;
+ /* Two-frame penalty if we're going to increase the amount of late frames (hysteresis) */
+ if (latest >= 0 && !penalty_taken)
+ {
+ penalty_taken = 1;
+ late+=4;
+ }
+ }
+
+ deltaT = best-worst;
+ /* This is a default "automatic latency tradeoff" when none is provided */
+ jitter->auto_tradeoff = 1 + deltaT/TOP_DELAY;
+ /*fprintf(stderr, "auto_tradeoff = %d (%d %d %d)\n", jitter->auto_tradeoff, best, worst, i);*/
+
+ /* FIXME: Compute a short-term estimate too and combine with the long-term one */
+
+ /* Prevents reducing the buffer size when we haven't really had much data */
+ if (tot_count < TOP_DELAY && opt > 0)
+ return 0;
+ return opt;
+}
+
+
/** Initialise jitter buffer */
-JitterBuffer *jitter_buffer_init(int tick)
+EXPORT JitterBuffer *jitter_buffer_init(int step_size)
{
JitterBuffer *jitter = (JitterBuffer*)speex_alloc(sizeof(JitterBuffer));
if (jitter)
{
int i;
+ spx_int32_t tmp;
for (i=0;ibuf[i]=NULL;
- jitter->tick_size = tick;
- jitter->buffer_margin = 1;
+ jitter->packets[i].data=NULL;
+ jitter->delay_step = step_size;
+ jitter->concealment_size = step_size;
+ /*FIXME: Should this be 0 or 1?*/
+ jitter->buffer_margin = 0;
+ jitter->late_cutoff = 50;
+ jitter->destroy = NULL;
+ jitter->latency_tradeoff = 0;
+ jitter->auto_adjust = 1;
+ tmp = 4;
+ jitter_buffer_ctl(jitter, JITTER_BUFFER_SET_MAX_LATE_RATE, &tmp);
jitter_buffer_reset(jitter);
}
return jitter;
}
/** Reset jitter buffer */
-void jitter_buffer_reset(JitterBuffer *jitter)
+EXPORT void jitter_buffer_reset(JitterBuffer *jitter)
{
int i;
for (i=0;ibuf[i])
+ if (jitter->packets[i].data)
{
- speex_free(jitter->buf[i]);
- jitter->buf[i] = NULL;
+ if (jitter->destroy)
+ jitter->destroy(jitter->packets[i].data);
+ else
+ speex_free(jitter->packets[i].data);
+ jitter->packets[i].data = NULL;
}
}
/* Timestamp is actually undefined at this point */
jitter->pointer_timestamp = 0;
- jitter->current_timestamp = 0;
+ jitter->next_stop = 0;
jitter->reset_state = 1;
jitter->lost_count = 0;
- jitter->loss_rate = 0;
- for (i=0;ibuffered = 0;
+ jitter->auto_tradeoff = 32000;
+
+ for (i=0;ishortterm_margin[i] = 0;
- jitter->longterm_margin[i] = 0;
+ tb_init(&jitter->_tb[i]);
+ jitter->timeBuffers[i] = &jitter->_tb[i];
}
/*fprintf (stderr, "reset\n");*/
}
/** Destroy jitter buffer */
-void jitter_buffer_destroy(JitterBuffer *jitter)
+EXPORT void jitter_buffer_destroy(JitterBuffer *jitter)
{
jitter_buffer_reset(jitter);
speex_free(jitter);
}
+/** Take the following timing into consideration for future calculations */
+static void update_timings(JitterBuffer *jitter, spx_int32_t timing)
+{
+ if (timing < -32767)
+ timing = -32767;
+ if (timing > 32767)
+ timing = 32767;
+ /* If the current sub-window is full, perform a rotation and discard oldest sub-widow */
+ if (jitter->timeBuffers[0]->curr_count >= jitter->subwindow_size)
+ {
+ int i;
+ /*fprintf(stderr, "Rotate buffer\n");*/
+ struct TimingBuffer *tmp = jitter->timeBuffers[MAX_BUFFERS-1];
+ for (i=MAX_BUFFERS-1;i>=1;i--)
+ jitter->timeBuffers[i] = jitter->timeBuffers[i-1];
+ jitter->timeBuffers[0] = tmp;
+ tb_init(jitter->timeBuffers[0]);
+ }
+ tb_add(jitter->timeBuffers[0], timing);
+}
+
+/** Compensate all timings when we do an adjustment of the buffering */
+static void shift_timings(JitterBuffer *jitter, spx_int16_t amount)
+{
+ int i, j;
+ for (i=0;itimeBuffers[i]->filled;j++)
+ jitter->timeBuffers[i]->timing[j] += amount;
+ }
+}
+
+
/** Put one packet into the jitter buffer */
-void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
+EXPORT void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
{
int i,j;
- spx_int32_t arrival_margin;
+ int late;
/*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/
- if (jitter->reset_state)
- {
- jitter->reset_state=0;
- jitter->pointer_timestamp = packet->timestamp;
- jitter->current_timestamp = packet->timestamp;
- /*fprintf(stderr, "reset to %d\n", timestamp);*/
- }
/* Cleanup buffer (remove old packets that weren't played) */
- for (i=0;ireset_state)
{
- if (jitter->buf[i] && LE32(jitter->timestamp[i] + jitter->span[i], jitter->pointer_timestamp))
+ for (i=0;ibuf[i]);
- jitter->buf[i] = NULL;
- }
- }
-
- /*Find an empty slot in the buffer*/
- for (i=0;ibuf[i]==NULL)
- break;
- }
-
- /*fprintf(stderr, "%d %d %f\n", timestamp, jitter->pointer_timestamp, jitter->drift_average);*/
- /*No place left in the buffer*/
- if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
- {
- int earliest=jitter->timestamp[0];
- i=0;
- for (j=1;jbuf[i] || LT32(jitter->timestamp[j],earliest))
+ /* Make sure we don't discard a "just-late" packet in case we want to play it next (if we interpolate). */
+ if (jitter->packets[i].data && LE32(jitter->packets[i].timestamp + jitter->packets[i].span, jitter->pointer_timestamp))
{
- earliest = jitter->timestamp[j];
- i=j;
+ /*fprintf (stderr, "cleaned (not played)\n");*/
+ if (jitter->destroy)
+ jitter->destroy(jitter->packets[i].data);
+ else
+ speex_free(jitter->packets[i].data);
+ jitter->packets[i].data = NULL;
}
}
- speex_free(jitter->buf[i]);
- jitter->buf[i]=NULL;
- if (jitter->lost_count>20)
- {
- jitter_buffer_reset(jitter);
- }
- /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/
}
- /* Copy packet in buffer */
- jitter->buf[i]=(char*)speex_alloc(packet->len);
- for (j=0;jlen;j++)
- jitter->buf[i][j]=packet->data[j];
- jitter->timestamp[i]=packet->timestamp;
- 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;
-
- if (arrival_margin >= -LATE_BINS*jitter->tick_size)
+ /*fprintf(stderr, "arrival: %d %d %d\n", packet->timestamp, jitter->next_stop, jitter->pointer_timestamp);*/
+ /* Check if packet is late (could still be useful though) */
+ if (!jitter->reset_state && LT32(packet->timestamp, jitter->next_stop))
{
- spx_int32_t int_margin;
- for (i=0;ishortterm_margin[i] *= .98;
- jitter->longterm_margin[i] *= .995;
- }
- int_margin = LATE_BINS + arrival_margin/jitter->tick_size;
- 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;
- }
+ update_timings(jitter, ((spx_int32_t)packet->timestamp) - ((spx_int32_t)jitter->next_stop) - jitter->buffer_margin);
+ late = 1;
} else {
-
- /*fprintf (stderr, "way too late = %d\n", arrival_margin);*/
- if (jitter->lost_count>20)
- {
- jitter_buffer_reset(jitter);
- }
+ late = 0;
}
-#if 0 /* Enable to check how much is being buffered */
- if (rand()%1000==0)
+
+ /* For some reason, the consumer has failed the last 20 fetches. Make sure this packet is
+ * used to resync. */
+ if (jitter->lost_count>20)
{
- int count = 0;
- for (j=0;jbuf[j])
- count++;
- }
- fprintf (stderr, "buffer_size = %d\n", count);
+ jitter_buffer_reset(jitter);
}
-#endif
+
+ /* Only insert the packet if it's not hopelessly late (i.e. totally useless) */
+ if (jitter->reset_state || GE32(packet->timestamp+packet->span+jitter->delay_step, jitter->pointer_timestamp))
+ {
+
+ /*Find an empty slot in the buffer*/
+ for (i=0;ipackets[i].data==NULL)
+ break;
+ }
+
+ /*No place left in the buffer, need to make room for it by discarding the oldest packet */
+ if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
+ {
+ int earliest=jitter->packets[0].timestamp;
+ i=0;
+ for (j=1;jpackets[i].data || LT32(jitter->packets[j].timestamp,earliest))
+ {
+ earliest = jitter->packets[j].timestamp;
+ i=j;
+ }
+ }
+ if (jitter->destroy)
+ jitter->destroy(jitter->packets[i].data);
+ else
+ speex_free(jitter->packets[i].data);
+ jitter->packets[i].data=NULL;
+ /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/
+ }
+
+ /* Copy packet in buffer */
+ if (jitter->destroy)
+ {
+ jitter->packets[i].data = packet->data;
+ } else {
+ jitter->packets[i].data=(char*)speex_alloc(packet->len);
+ for (j=0;jlen;j++)
+ jitter->packets[i].data[j]=packet->data[j];
+ }
+ jitter->packets[i].timestamp=packet->timestamp;
+ jitter->packets[i].span=packet->span;
+ jitter->packets[i].len=packet->len;
+ jitter->packets[i].sequence=packet->sequence;
+ jitter->packets[i].user_data=packet->user_data;
+ if (jitter->reset_state || late)
+ jitter->arrival[i] = 0;
+ else
+ jitter->arrival[i] = jitter->next_stop;
+ }
+
+
}
/** Get one packet from the jitter buffer */
-int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint32_t *start_offset)
+EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset)
{
- int i, j;
- float late_ratio_short;
- float late_ratio_long;
- float ontime_ratio_short;
- float ontime_ratio_long;
- float early_ratio_short;
- float early_ratio_long;
- int chunk_size;
+ int i;
+ unsigned int j;
int incomplete = 0;
+ spx_int16_t opt;
- 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);*/
+ if (start_offset != NULL)
+ *start_offset = 0;
- /* FIXME: This should be only what remaining of the current tick */
- chunk_size = jitter->tick_size;
-
- /* Compiling arrival statistics */
-
- late_ratio_short = 0;
- late_ratio_long = 0;
- for (i=0;ireset_state)
{
- late_ratio_short += jitter->shortterm_margin[i];
- late_ratio_long += jitter->longterm_margin[i];
- }
- ontime_ratio_short = jitter->shortterm_margin[LATE_BINS];
- ontime_ratio_long = jitter->longterm_margin[LATE_BINS];
- early_ratio_short = early_ratio_long = 0;
- for (i=LATE_BINS+1;ishortterm_margin[i];
- early_ratio_long += jitter->longterm_margin[i];
- }
- if (0&&jitter->pointer_timestamp%1000==0)
- {
- /*fprintf (stderr, "%f %f %f %f %f %f\n", early_ratio_short, early_ratio_long, ontime_ratio_short, ontime_ratio_long, late_ratio_short, late_ratio_long);*/
- /*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--)
+ int found = 0;
+ /* Find the oldest packet */
+ spx_uint32_t oldest=0;
+ for (i=0;ishortterm_margin[i+1] = jitter->shortterm_margin[i];
- jitter->longterm_margin[i+1] = jitter->longterm_margin[i];
+ if (jitter->packets[i].data && (!found || LT32(jitter->packets[i].timestamp,oldest)))
+ {
+ oldest = jitter->packets[i].timestamp;
+ found = 1;
+ }
}
- 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;ishortterm_margin[i] = jitter->shortterm_margin[i+1];
- jitter->longterm_margin[i] = jitter->longterm_margin[i+1];
+ jitter->reset_state=0;
+ jitter->pointer_timestamp = oldest;
+ jitter->next_stop = oldest;
+ } else {
+ packet->timestamp = 0;
+ packet->span = jitter->interp_requested;
+ return JITTER_BUFFER_MISSING;
}
- 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");*/
+ }
+
+
+ jitter->last_returned_timestamp = jitter->pointer_timestamp;
+
+ if (jitter->interp_requested != 0)
+ {
+ packet->timestamp = jitter->pointer_timestamp;
+ packet->span = jitter->interp_requested;
+
+ /* Increment the pointer because it got decremented in the delay update */
+ jitter->pointer_timestamp += jitter->interp_requested;
+ packet->len = 0;
+ /*fprintf (stderr, "Deferred interpolate\n");*/
+
+ jitter->interp_requested = 0;
+
+ jitter->buffered = packet->span - desired_span;
+
+ return JITTER_BUFFER_INSERTION;
}
/* Searching for the packet that fits best */
@@ -316,7 +523,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint
/* Search the buffer for a packet with the right timestamp and spanning the whole current chunk */
for (i=0;ibuf[i] && jitter->timestamp[i]==jitter->pointer_timestamp && GE32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp+chunk_size))
+ if (jitter->packets[i].data && jitter->packets[i].timestamp==jitter->pointer_timestamp && GE32(jitter->packets[i].timestamp+jitter->packets[i].span,jitter->pointer_timestamp+desired_span))
break;
}
@@ -325,7 +532,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint
{
for (i=0;ibuf[i] && jitter->timestamp[i]<=jitter->pointer_timestamp && GE32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp+chunk_size))
+ if (jitter->packets[i].data && LE32(jitter->packets[i].timestamp, jitter->pointer_timestamp) && GE32(jitter->packets[i].timestamp+jitter->packets[i].span,jitter->pointer_timestamp+desired_span))
break;
}
}
@@ -335,7 +542,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint
{
for (i=0;ibuf[i] && jitter->timestamp[i]<=jitter->pointer_timestamp && GT32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp))
+ if (jitter->packets[i].data && LE32(jitter->packets[i].timestamp, jitter->pointer_timestamp) && GT32(jitter->packets[i].timestamp+jitter->packets[i].span,jitter->pointer_timestamp))
break;
}
}
@@ -350,12 +557,12 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint
for (i=0;ibuf[i] && LT32(jitter->timestamp[i],jitter->pointer_timestamp+chunk_size) && GE32(jitter->timestamp[i],jitter->pointer_timestamp))
+ if (jitter->packets[i].data && LT32(jitter->packets[i].timestamp,jitter->pointer_timestamp+desired_span) && GE32(jitter->packets[i].timestamp,jitter->pointer_timestamp))
{
- if (!found || LT32(jitter->timestamp[i],best_time) || (jitter->timestamp[i]==best_time && GT32(jitter->span[i],best_span)))
+ if (!found || LT32(jitter->packets[i].timestamp,best_time) || (jitter->packets[i].timestamp==best_time && GT32(jitter->packets[i].span,best_span)))
{
- best_time = jitter->timestamp[i];
- best_span = jitter->span[i];
+ best_time = jitter->packets[i].timestamp;
+ best_span = jitter->packets[i].span;
besti = i;
found = 1;
}
@@ -365,144 +572,272 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint
{
i=besti;
incomplete = 1;
- /*fprintf (stderr, "incomplete: %d %d %d %d\n", jitter->timestamp[i], jitter->pointer_timestamp, chunk_size, jitter->span[i]);*/
+ /*fprintf (stderr, "incomplete: %d %d %d %d\n", jitter->packets[i].timestamp, jitter->pointer_timestamp, chunk_size, jitter->packets[i].span);*/
}
}
/* If we find something */
if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE)
{
+ spx_int32_t offset;
+
/* We (obviously) haven't lost this packet */
jitter->lost_count = 0;
- jitter->loss_rate = .999*jitter->loss_rate;
- /* Check for potential overflow */
- packet->len = jitter->len[i];
+
+ /* In this case, 0 isn't as a valid timestamp */
+ if (jitter->arrival[i] != 0)
+ {
+ update_timings(jitter, ((spx_int32_t)jitter->packets[i].timestamp) - ((spx_int32_t)jitter->arrival[i]) - jitter->buffer_margin);
+ }
+
+
/* Copy packet */
- for (j=0;jlen;j++)
- packet->data[j] = jitter->buf[i][j];
- /* Remove packet */
- speex_free(jitter->buf[i]);
- jitter->buf[i] = NULL;
+ if (jitter->destroy)
+ {
+ packet->data = jitter->packets[i].data;
+ packet->len = jitter->packets[i].len;
+ } else {
+ if (jitter->packets[i].len > packet->len)
+ {
+ speex_warning_int("jitter_buffer_get(): packet too large to fit. Size is", jitter->packets[i].len);
+ } else {
+ packet->len = jitter->packets[i].len;
+ }
+ for (j=0;jlen;j++)
+ packet->data[j] = jitter->packets[i].data[j];
+ /* Remove packet */
+ speex_free(jitter->packets[i].data);
+ }
+ jitter->packets[i].data = NULL;
/* Set timestamp and span (if requested) */
- if (start_offset)
- *start_offset = jitter->timestamp[i]-jitter->pointer_timestamp;
- packet->timestamp = jitter->timestamp[i];
- packet->span = jitter->span[i];
- /* Point at the end of the current packet */
- jitter->pointer_timestamp = jitter->timestamp[i]+jitter->span[i];
- if (incomplete)
- return JITTER_BUFFER_INCOMPLETE;
- else
- return JITTER_BUFFER_OK;
+ offset = (spx_int32_t)jitter->packets[i].timestamp-(spx_int32_t)jitter->pointer_timestamp;
+ if (start_offset != NULL)
+ *start_offset = offset;
+ else if (offset != 0)
+ speex_warning_int("jitter_buffer_get() discarding non-zero start_offset", offset);
+
+ packet->timestamp = jitter->packets[i].timestamp;
+ jitter->last_returned_timestamp = packet->timestamp;
+
+ packet->span = jitter->packets[i].span;
+ packet->sequence = jitter->packets[i].sequence;
+ packet->user_data = jitter->packets[i].user_data;
+ /* Point to the end of the current packet */
+ jitter->pointer_timestamp = jitter->packets[i].timestamp+jitter->packets[i].span;
+
+ jitter->buffered = packet->span - desired_span;
+
+ if (start_offset != NULL)
+ jitter->buffered += *start_offset;
+
+ return JITTER_BUFFER_OK;
}
/* If we haven't found anything worth returning */
+
/*fprintf (stderr, "not found\n");*/
jitter->lost_count++;
/*fprintf (stderr, "m");*/
/*fprintf (stderr, "lost_count = %d\n", jitter->lost_count);*/
- jitter->loss_rate = .999*jitter->loss_rate + .001;
- if (start_offset)
- *start_offset = 0;
- packet->timestamp = jitter->pointer_timestamp;
- packet->span = jitter->tick_size;
- jitter->pointer_timestamp += chunk_size;
- packet->len = 0;
- return JITTER_BUFFER_MISSING;
+
+ opt = compute_opt_delay(jitter);
+
+ /* Should we force an increase in the buffer or just do normal interpolation? */
+ if (opt < 0)
+ {
+ /* Need to increase buffering */
+
+ /* Shift histogram to compensate */
+ shift_timings(jitter, -opt);
+
+ packet->timestamp = jitter->pointer_timestamp;
+ packet->span = -opt;
+ /* Don't move the pointer_timestamp forward */
+ packet->len = 0;
+
+ jitter->buffered = packet->span - desired_span;
+ return JITTER_BUFFER_INSERTION;
+ /*jitter->pointer_timestamp -= jitter->delay_step;*/
+ /*fprintf (stderr, "Forced to interpolate\n");*/
+ } else {
+ /* Normal packet loss */
+ packet->timestamp = jitter->pointer_timestamp;
+
+ desired_span = ROUND_DOWN(desired_span, jitter->concealment_size);
+ packet->span = desired_span;
+ jitter->pointer_timestamp += desired_span;
+ packet->len = 0;
+
+ jitter->buffered = packet->span - desired_span;
+ return JITTER_BUFFER_MISSING;
+ /*fprintf (stderr, "Normal loss\n");*/
+ }
+
}
+EXPORT int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet)
+{
+ int i, j;
+ for (i=0;ipackets[i].data && jitter->packets[i].timestamp==jitter->last_returned_timestamp)
+ break;
+ }
+ if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE)
+ {
+ /* Copy packet */
+ packet->len = jitter->packets[i].len;
+ if (jitter->destroy)
+ {
+ packet->data = jitter->packets[i].data;
+ } else {
+ for (j=0;jlen;j++)
+ packet->data[j] = jitter->packets[i].data[j];
+ /* Remove packet */
+ speex_free(jitter->packets[i].data);
+ }
+ jitter->packets[i].data = NULL;
+ packet->timestamp = jitter->packets[i].timestamp;
+ packet->span = jitter->packets[i].span;
+ packet->sequence = jitter->packets[i].sequence;
+ packet->user_data = jitter->packets[i].user_data;
+ return JITTER_BUFFER_OK;
+ } else {
+ packet->data = NULL;
+ packet->len = 0;
+ packet->span = 0;
+ return JITTER_BUFFER_MISSING;
+ }
+}
+
+/* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */
+static int _jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset)
+{
+ spx_int16_t opt = compute_opt_delay(jitter);
+ /*fprintf(stderr, "opt adjustment is %d ", opt);*/
+
+ if (opt < 0)
+ {
+ shift_timings(jitter, -opt);
+
+ jitter->pointer_timestamp += opt;
+ jitter->interp_requested = -opt;
+ /*fprintf (stderr, "Decision to interpolate %d samples\n", -opt);*/
+ } else if (opt > 0)
+ {
+ shift_timings(jitter, -opt);
+ jitter->pointer_timestamp += opt;
+ /*fprintf (stderr, "Decision to drop %d samples\n", opt);*/
+ }
+
+ return opt;
+}
+
+/* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */
+EXPORT int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset)
+{
+ /* If the programmer calls jitter_buffer_update_delay() directly,
+ automatically disable auto-adjustment */
+ jitter->auto_adjust = 0;
+
+ return _jitter_buffer_update_delay(jitter, packet, start_offset);
+}
+
/** Get pointer timestamp of jitter buffer */
-int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter)
+EXPORT int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter)
{
return jitter->pointer_timestamp;
}
-void jitter_buffer_tick(JitterBuffer *jitter)
+EXPORT void jitter_buffer_tick(JitterBuffer *jitter)
{
- jitter->current_timestamp += jitter->tick_size;
-}
-
-
-
-
-
-void speex_jitter_init(SpeexJitter *jitter, void *decoder, int sampling_rate)
-{
- jitter->dec = decoder;
- speex_decoder_ctl(decoder, SPEEX_GET_FRAME_SIZE, &jitter->frame_size);
-
- jitter->packets = jitter_buffer_init(jitter->frame_size);
-
- speex_bits_init(&jitter->current_packet);
- jitter->valid_bits = 0;
-
-}
-
-void speex_jitter_destroy(SpeexJitter *jitter)
-{
- jitter_buffer_destroy(jitter->packets);
- speex_bits_destroy(&jitter->current_packet);
-}
-
-void speex_jitter_put(SpeexJitter *jitter, char *packet, int len, int timestamp)
-{
- JitterBufferPacket p;
- p.data = packet;
- p.len = len;
- p.timestamp = timestamp;
- p.span = jitter->frame_size;
- jitter_buffer_put(jitter->packets, &p);
-}
-
-void speex_jitter_get(SpeexJitter *jitter, short *out, int *current_timestamp)
-{
- int i;
- int ret;
- char data[2048];
- JitterBufferPacket packet;
- packet.data = data;
+ /* Automatically-adjust the buffering delay if requested */
+ if (jitter->auto_adjust)
+ _jitter_buffer_update_delay(jitter, NULL, NULL);
- if (jitter->valid_bits)
+ if (jitter->buffered >= 0)
{
- /* Try decoding last received packet */
- ret = speex_decode_int(jitter->dec, &jitter->current_packet, out);
- if (ret == 0)
- {
- jitter_buffer_tick(jitter->packets);
- return;
- } else {
- jitter->valid_bits = 0;
- }
- }
-
- ret = jitter_buffer_get(jitter->packets, &packet, NULL);
-
- if (ret != JITTER_BUFFER_OK)
- {
- /* No packet found */
-
- /*fprintf (stderr, "lost/late frame\n");*/
- /*Packet is late or lost*/
- speex_decode_int(jitter->dec, NULL, out);
+ jitter->next_stop = jitter->pointer_timestamp - jitter->buffered;
} else {
- speex_bits_read_from(&jitter->current_packet, packet.data, packet.len);
- /* Decode packet */
- ret = speex_decode_int(jitter->dec, &jitter->current_packet, out);
- if (ret == 0)
- {
- jitter->valid_bits = 1;
- } else {
- /* Error while decoding */
- for (i=0;iframe_size;i++)
- out[i]=0;
- }
+ jitter->next_stop = jitter->pointer_timestamp;
+ speex_warning_int("jitter buffer sees negative buffering, your code might be broken. Value is ", jitter->buffered);
}
- jitter_buffer_tick(jitter->packets);
+ jitter->buffered = 0;
}
-int speex_jitter_get_pointer_timestamp(SpeexJitter *jitter)
+EXPORT void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem)
{
- return jitter_buffer_get_pointer_timestamp(jitter->packets);
+ /* Automatically-adjust the buffering delay if requested */
+ if (jitter->auto_adjust)
+ _jitter_buffer_update_delay(jitter, NULL, NULL);
+
+ if (jitter->buffered < 0)
+ speex_warning_int("jitter buffer sees negative buffering, your code might be broken. Value is ", jitter->buffered);
+ jitter->next_stop = jitter->pointer_timestamp - rem;
}
+
+
+/* Used like the ioctl function to control the jitter buffer parameters */
+EXPORT 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;ipackets[i].data && LE32(jitter->pointer_timestamp, jitter->packets[i].timestamp))
+ {
+ count++;
+ }
+ }
+ *(spx_int32_t*)ptr = count;
+ break;
+ case JITTER_BUFFER_SET_DESTROY_CALLBACK:
+ jitter->destroy = (void (*) (void *))ptr;
+ break;
+ case JITTER_BUFFER_GET_DESTROY_CALLBACK:
+ *(void (**) (void *))ptr = jitter->destroy;
+ break;
+ case JITTER_BUFFER_SET_DELAY_STEP:
+ jitter->delay_step = *(spx_int32_t*)ptr;
+ break;
+ case JITTER_BUFFER_GET_DELAY_STEP:
+ *(spx_int32_t*)ptr = jitter->delay_step;
+ break;
+ case JITTER_BUFFER_SET_CONCEALMENT_SIZE:
+ jitter->concealment_size = *(spx_int32_t*)ptr;
+ break;
+ case JITTER_BUFFER_GET_CONCEALMENT_SIZE:
+ *(spx_int32_t*)ptr = jitter->concealment_size;
+ break;
+ case JITTER_BUFFER_SET_MAX_LATE_RATE:
+ jitter->max_late_rate = *(spx_int32_t*)ptr;
+ jitter->window_size = 100*TOP_DELAY/jitter->max_late_rate;
+ jitter->subwindow_size = jitter->window_size/MAX_BUFFERS;
+ break;
+ case JITTER_BUFFER_GET_MAX_LATE_RATE:
+ *(spx_int32_t*)ptr = jitter->max_late_rate;
+ break;
+ case JITTER_BUFFER_SET_LATE_COST:
+ jitter->latency_tradeoff = *(spx_int32_t*)ptr;
+ break;
+ case JITTER_BUFFER_GET_LATE_COST:
+ *(spx_int32_t*)ptr = jitter->latency_tradeoff;
+ break;
+ default:
+ speex_warning_int("Unknown jitter_buffer_ctl request: ", request);
+ return -1;
+ }
+ return 0;
+}
+
diff --git a/libs/speex/libspeex/kiss_fft.c b/libs/speex/libspeex/kiss_fft.c
index a0b3724be0..67782810fe 100644
--- a/libs/speex/libspeex/kiss_fft.c
+++ b/libs/speex/libspeex/kiss_fft.c
@@ -1,5 +1,6 @@
/*
Copyright (c) 2003-2004, Mark Borgerding
+Copyright (c) 2005-2007, Jean-Marc Valin
All rights reserved.
@@ -18,127 +19,149 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
#endif
#include "_kiss_fft_guts.h"
-#include "misc.h"
+#include "arch.h"
+#include "os_support.h"
/* The guts header contains all the multiplication and addition macros that are defined for
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;itwiddles;
+ for(j=0;jr , 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;itwiddles;
+ for(j=0;jtwiddles;
-
- 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;itwiddles;
+ for (j=0;jtwiddles;
+ for (j=0;jr = 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 +286,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_fatal("KissFFT: max radix supported is 17");
+
for ( u=0; u 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 +454,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 +478,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;iinverse)
- 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;iinverse)
+ phase *= -1;
+ kf_cexp(st->twiddles+i, phase );
+ }
+#endif
kf_factor(nfft,st->factors);
}
return st;
@@ -401,12 +504,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_fatal("In-place FFT not supported");
+ /*CHECKBUF(tmpbuf,ntmpbuf,st->nfft);
+ kf_work(tmpbuf,fin,1,in_stride, st->factors,st);
+ SPEEX_MOVE(fout,tmpbuf,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 +521,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/libs/speex/libspeex/kiss_fft.h b/libs/speex/libspeex/kiss_fft.h
index 54627e7da0..fa3f2c6042 100644
--- a/libs/speex/libspeex/kiss_fft.h
+++ b/libs/speex/libspeex/kiss_fft.h
@@ -3,7 +3,7 @@
#include
#include
-#include "misc.h"
+#include "arch.h"
#ifdef __cplusplus
extern "C" {
@@ -32,7 +32,7 @@ extern "C" {
#ifdef FIXED_POINT
-#include "misc.h"
+#include "arch.h"
# define kiss_fft_scalar spx_int16_t
#else
# ifndef kiss_fft_scalar
diff --git a/libs/speex/libspeex/kiss_fftr.c b/libs/speex/libspeex/kiss_fftr.c
index b90b7254ce..f6275b8794 100644
--- a/libs/speex/libspeex/kiss_fftr.c
+++ b/libs/speex/libspeex/kiss_fftr.c
@@ -16,6 +16,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
#include "config.h"
#endif
+#include "os_support.h"
#include "kiss_fftr.h"
#include "_kiss_fft_guts.h"
@@ -58,13 +59,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>1);
+ if (!inverse_fft)
+ phase = -phase;
+ kf_cexp2(st->super_twiddles+i, DIV32(SHL32(phase,16),nfft));
}
+#else
+ for (i=0;isuper_twiddles+i, phase );
+ }
+#endif
return st;
}
@@ -75,8 +85,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_fatal("kiss fft usage error: improper alloc\n");
}
ncfft = st->substate->nfft;
@@ -124,14 +133,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_fatal("kiss fft usage error: improper alloc\n");
}
ncfft = st->substate->nfft;
@@ -161,3 +169,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_fatal("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_fatal ("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/libs/speex/libspeex/kiss_fftr.h b/libs/speex/libspeex/kiss_fftr.h
index 2e8351a640..7bfb423340 100644
--- a/libs/speex/libspeex/kiss_fftr.h
+++ b/libs/speex/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/libs/speex/libspeex/lpc.h b/libs/speex/libspeex/lpc.h
index d64df96741..952ecdd933 100644
--- a/libs/speex/libspeex/lpc.h
+++ b/libs/speex/libspeex/lpc.h
@@ -35,7 +35,7 @@
#ifndef LPC_H
#define LPC_H
-#include "misc.h"
+#include "arch.h"
void _spx_autocorr(
const spx_word16_t * x, /* in: [0...n-1] samples x */
diff --git a/libs/speex/libspeex/lsp.c b/libs/speex/libspeex/lsp.c
index 3fdc08aab3..a73d8835f0 100644
--- a/libs/speex/libspeex/lsp.c
+++ b/libs/speex/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/libs/speex/libspeex/lsp.h b/libs/speex/libspeex/lsp.h
index 6266f42fb5..b55bd42f2c 100644
--- a/libs/speex/libspeex/lsp.h
+++ b/libs/speex/libspeex/lsp.h
@@ -51,7 +51,7 @@ Modified by Jean-Marc Valin
#ifndef __AK2LSPD__
#define __AK2LSPD__
-#include "misc.h"
+#include "arch.h"
int lpc_to_lsp (spx_coef_t *a, int lpcrdr, spx_lsp_t *freq, int nb, spx_word16_t delta, char *stack);
void lsp_to_lpc(spx_lsp_t *freq, spx_coef_t *ak, int lpcrdr, char *stack);
diff --git a/libs/speex/libspeex/ltp.c b/libs/speex/libspeex/ltp.c
index 27e4f4de2d..0129c95f15 100644
--- a/libs/speex/libspeex/ltp.c
+++ b/libs/speex/libspeex/ltp.c
@@ -40,6 +40,7 @@
#include "filters.h"
#include
#include "math_approx.h"
+#include "os_support.h"
#ifndef NULL
#define NULL 0
@@ -176,20 +177,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;i16383)
+ {
+ scaledown=1;
+ break;
+ }
+ }
+ /* If the weighted input is close to saturation, then we scale it down */
+ if (scaledown)
+ {
+ for (i=-end;iMULT16_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;jMULT16_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;jbest_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 +280,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=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;jpitch_bits);
speex_bits_pack(bits, 0, params->gain_bits);
- for (i=0;i16383)
+ {
+ scaledown=1;
+ break;
+ }
+ }
+ for (i=-end;i16383)
+ {
+ scaledown=1;
+ break;
+ }
+ }
+#endif
if (N>end-start+1)
N=end-start+1;
if (end != start)
@@ -559,16 +617,13 @@ spx_word32_t *cumul_gain
for (i=0;i63)
pitch_coef=63;
@@ -734,9 +793,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
-#include "misc.h"
+#include "arch.h"
/** LTP parameters. */
typedef struct {
diff --git a/libs/speex/libspeex/ltp_arm4.h b/libs/speex/libspeex/ltp_arm4.h
index 7479e8bfd0..cdb94e603a 100644
--- a/libs/speex/libspeex/ltp_arm4.h
+++ b/libs/speex/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/libs/speex/libspeex/ltp_bfin.h b/libs/speex/libspeex/ltp_bfin.h
index c4669022f1..b530f85986 100644
--- a/libs/speex/libspeex/ltp_bfin.h
+++ b/libs/speex/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/libs/speex/libspeex/math_approx.h b/libs/speex/libspeex/math_approx.h
index 377bf1acc4..9ca830755d 100644
--- a/libs/speex/libspeex/math_approx.h
+++ b/libs/speex/libspeex/math_approx.h
@@ -35,16 +35,298 @@
#ifndef MATH_APPROX_H
#define MATH_APPROX_H
-#include "misc.h"
+#include "arch.h"
-spx_word16_t spx_cos(spx_word16_t x);
+#ifndef FIXED_POINT
-#ifdef FIXED_POINT
-spx_word16_t spx_sqrt(spx_word32_t x);
-spx_word16_t spx_acos(spx_word16_t x);
-#else
#define spx_sqrt sqrt
#define spx_acos acos
-#endif
+#define spx_exp exp
+#define spx_cos_norm(x) (cos((.5f*M_PI)*(x)))
+#define spx_atan atan
+
+/** Generate a pseudo-random number */
+static inline spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed)
+{
+ const unsigned int jflone = 0x3f800000;
+ const unsigned int jflmsk = 0x007fffff;
+ union {int i; float f;} ran;
+ *seed = 1664525 * *seed + 1013904223;
+ ran.i = jflone | (jflmsk & *seed);
+ ran.f -= 1.5;
+ return 3.4642*std*ran.f;
+}
+
+
+#endif
+
+
+static inline spx_int16_t spx_ilog2(spx_uint32_t x)
+{
+ int r=0;
+ if (x>=(spx_int32_t)65536)
+ {
+ x >>= 16;
+ r += 16;
+ }
+ if (x>=256)
+ {
+ x >>= 8;
+ r += 8;
+ }
+ if (x>=16)
+ {
+ x >>= 4;
+ r += 4;
+ }
+ if (x>=4)
+ {
+ x >>= 2;
+ r += 2;
+ }
+ if (x>=2)
+ {
+ r += 1;
+ }
+ return r;
+}
+
+static inline spx_int16_t spx_ilog4(spx_uint32_t x)
+{
+ int r=0;
+ if (x>=(spx_int32_t)65536)
+ {
+ x >>= 16;
+ r += 8;
+ }
+ if (x>=256)
+ {
+ x >>= 8;
+ r += 4;
+ }
+ if (x>=16)
+ {
+ x >>= 4;
+ r += 2;
+ }
+ if (x>=4)
+ {
+ r += 1;
+ }
+ return r;
+}
+
+#ifdef FIXED_POINT
+
+/** Generate a pseudo-random number */
+static inline 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 EXTRACT16(PSHR32(SUB32(res, SHR32(res, 3)),14));
+}
+
+/* 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
+
+static inline 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)))))));
+ rt = VSHR32(rt,7-k);
+ return rt;
+}
+
+/* log(x) ~= -2.18151 + 4.20592*x - 2.88938*x^2 + 0.86535*x^3 (for .5 < x < 1) */
+
+
+#define A1 16469
+#define A2 2242
+#define A3 1486
+
+static inline spx_word16_t spx_acos(spx_word16_t x)
+{
+ int s=0;
+ spx_word16_t ret;
+ spx_word16_t sq;
+ if (x<0)
+ {
+ s=1;
+ x = NEG16(x);
+ }
+ x = SUB16(16384,x);
+
+ x = x >> 1;
+ sq = MULT16_16_Q13(x, ADD16(A1, MULT16_16_Q13(x, ADD16(A2, MULT16_16_Q13(x, (A3))))));
+ ret = spx_sqrt(SHL32(EXTEND32(sq),13));
+
+ /*ret = spx_sqrt(67108864*(-1.6129e-04 + 2.0104e+00*f + 2.7373e-01*f*f + 1.8136e-01*f*f*f));*/
+ if (s)
+ ret = SUB16(25736,ret);
+ return ret;
+}
+
+
+#define K1 8192
+#define K2 -4096
+#define K3 340
+#define K4 -10
+
+static inline spx_word16_t spx_cos(spx_word16_t x)
+{
+ spx_word16_t x2;
+
+ if (x<12868)
+ {
+ x2 = MULT16_16_P13(x,x);
+ return ADD32(K1, MULT16_16_P13(x2, ADD32(K2, MULT16_16_P13(x2, ADD32(K3, MULT16_16_P13(K4, x2))))));
+ } else {
+ x = SUB16(25736,x);
+ x2 = MULT16_16_P13(x,x);
+ return SUB32(-K1, MULT16_16_P13(x2, ADD32(K2, MULT16_16_P13(x2, ADD32(K3, MULT16_16_P13(K4, x2))))));
+ }
+}
+
+#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))))))));
+}
+
+static inline 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 (x14)
+ 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 */
+static inline 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)))))));
+}
+
+#undef M1
+#undef M2
+#undef M3
+#undef M4
+
+/* Input in Q15, output in Q14 */
+static inline 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
+#define M_PI 3.14159265358979323846 /* pi */
+#endif
+
+#define C1 0.9999932946f
+#define C2 -0.4999124376f
+#define C3 0.0414877472f
+#define C4 -0.0012712095f
+
+
+#define SPX_PI_2 1.5707963268
+static inline spx_word16_t spx_cos(spx_word16_t x)
+{
+ if (x(b) ? (a) : (b))
-
#ifdef FIXED_POINT
#define WEIGHT_SHIFT 11
#define NORMALIZE_SCALEDOWN 5
@@ -90,19 +88,46 @@
#define WEIGHT_SHIFT 0
#endif
-/* 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
+#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
+
+/* 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 = .005f;
+
+/* 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,49 +136,61 @@ 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;
spx_word16_t spec_average;
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;
-#ifdef FIXED_POINT
- spx_word16_t *wtmp2;
+ 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 *Rf;
- spx_word32_t *Yf;
- spx_word32_t *Xf;
+ 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; /* scratch */
+#endif
+ 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;
- spx_word16_t memX, memD, memE;
+ spx_word16_t *memX, *memD, *memE;
spx_word16_t preemph;
spx_word16_t notch_radius;
- spx_mem_t notch_mem[2];
+ spx_mem_t *notch_mem;
/* 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)
+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)
{
int i;
spx_word16_t den2;
@@ -165,7 +202,7 @@ static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius,
/*printf ("%d %d %d %d %d %d\n", num[0], num[1], num[2], den[0], den[1], den[2]);*/
for (i=0;i max_sum)
+ max_sum = prop[i];
+ }
+ for (i=0;i
+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_fatal("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 *speex_echo_state_init(int frame_size, int filter_length)
+EXPORT SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
{
- int i,N,M;
+ return speex_echo_state_init_mc(frame_size, filter_length, 1, 1);
+}
+
+EXPORT SpeexEchoState *speex_echo_state_init_mc(int frame_size, int filter_length, int nb_mic, int nb_speakers)
+{
+ int i,N,M, C, K;
SpeexEchoState *st = (SpeexEchoState *)speex_alloc(sizeof(SpeexEchoState));
+ st->K = nb_speakers;
+ st->C = nb_mic;
+ C=st->C;
+ K=st->K;
+#ifdef DUMP_ECHO_CANCEL_DATA
+ if (rFile || pFile || oFile)
+ speex_fatal("Opening dump files twice");
+ rFile = fopen("aec_rec.sw", "wb");
+ pFile = fopen("aec_play.sw", "wb");
+ oFile = fopen("aec_out.sw", "wb");
+#endif
+
st->frame_size = frame_size;
st->window_size = 2*frame_size;
N = st->window_size;
@@ -281,7 +428,8 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
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
@@ -291,25 +439,28 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
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(N*sizeof(spx_word16_t));
- st->x = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
- st->d = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
- st->y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
- st->Yps = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t));
- st->last_y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
+ 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->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->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));
st->Xf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
st->Yh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
st->Eh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
- st->X = (spx_word16_t*)speex_alloc((M+1)*N*sizeof(spx_word16_t));
- st->Y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
- st->E = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
- st->W = (spx_word32_t*)speex_alloc(M*N*sizeof(spx_word32_t));
+ st->X = (spx_word16_t*)speex_alloc(K*(M+1)*N*sizeof(spx_word16_t));
+ 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));
@@ -329,14 +480,12 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
#endif
for (i=0;i<=st->frame_size;i++)
st->power_1[i] = FLOAT_ONE;
- for (i=0;iW[i] = 0;
- for (i=0;iPHI[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=0;i--)
{
- st->prop[i] = DIV32(MULT16_16(QCONST16(.8,15), st->prop[i]),sum);
+ st->prop[i] = DIV32(MULT16_16(QCONST16(.8f,15), st->prop[i]),sum);
}
}
- st->memX=st->memD=st->memE=0;
+ st->memX = (spx_word16_t*)speex_alloc(K*sizeof(spx_word16_t));
+ st->memD = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t));
+ st->memE = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t));
st->preemph = QCONST16(.9,15);
if (st->sampling_rate<12000)
st->notch_radius = QCONST16(.9, 15);
@@ -359,52 +510,91 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
else
st->notch_radius = QCONST16(.992, 15);
- st->notch_mem[0] = st->notch_mem[1] = 0;
+ st->notch_mem = (spx_mem_t*)speex_alloc(2*C*sizeof(spx_mem_t));
st->adapted = 0;
st->Pey = st->Pyy = FLOAT_ONE;
- st->play_buf = (spx_int16_t*)speex_alloc(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;
}
/** Resets echo canceller state */
-void speex_echo_state_reset(SpeexEchoState *st)
+EXPORT void speex_echo_state_reset(SpeexEchoState *st)
{
- int i, M, N;
+ 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;iW[i] = 0;
+#ifdef TWO_PATH
+ for (i=0;iforeground[i] = 0;
+#endif
for (i=0;iX[i] = 0;
for (i=0;i<=st->frame_size;i++)
+ {
st->power[i] = 0;
- for (i=0;ipower_1[i] = FLOAT_ONE;
+ st->Eh[i] = 0;
+ st->Yh[i] = 0;
+ }
+ for (i=0;iframe_size;i++)
+ {
+ st->last_y[i] = 0;
+ }
+ for (i=0;iE[i] = 0;
- st->notch_mem[0] = st->notch_mem[1] = 0;
-
+ }
+ for (i=0;ix[i] = 0;
+ }
+ for (i=0;i<2*C;i++)
+ st->notch_mem[i] = 0;
+ for (i=0;imemD[i]=st->memE[i]=0;
+ for (i=0;imemX[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;
}
/** Destroys an echo canceller state */
-void speex_echo_state_destroy(SpeexEchoState *st)
+EXPORT void speex_echo_state_destroy(SpeexEchoState *st)
{
spx_fft_destroy(st->fft_table);
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);
@@ -415,6 +605,9 @@ void speex_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);
@@ -424,21 +617,35 @@ void speex_echo_state_destroy(SpeexEchoState *st)
#ifdef FIXED_POINT
speex_free(st->wtmp2);
#endif
+ speex_free(st->memX);
+ speex_free(st->memD);
+ speex_free(st->memE);
+ speex_free(st->notch_mem);
+
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 speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out, spx_int32_t *Yout)
+EXPORT void speex_echo_capture(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)
{
- speex_echo_cancel(st, rec, st->play_buf, out, Yout);
+ speex_echo_cancellation(st, rec, st->play_buf, out);
st->play_buf_pos -= st->frame_size;
- for (i=0;iframe_size;i++)
+ for (i=0;iplay_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?");
@@ -449,27 +656,49 @@ void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t
}
}
-void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play)
+EXPORT void speex_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;iframe_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;iframe_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 speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int16_t *echo, spx_int16_t *out, spx_int32_t *Yout)
+/** Performs echo cancellation on a frame (deprecated, last arg now ignored) */
+EXPORT void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out, spx_int32_t *Yout)
{
- int i,j;
- int N,M;
- spx_word32_t Syy,See,Sxx;
+ speex_echo_cancellation(st, in, far_end, out);
+}
+
+/** Performs echo cancellation on a frame */
+EXPORT void speex_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_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 leak_estimate;
spx_word16_t ss, ss_1;
spx_float_t Pey = FLOAT_ONE, Pyy=FLOAT_ONE;
spx_float_t alpha, alpha_1;
@@ -478,6 +707,9 @@ void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int
N = st->window_size;
M = st->M;
+ C = st->C;
+ K = st->K;
+
st->cancel_count++;
#ifdef FIXED_POINT
ss=DIV32_16(11469,M);
@@ -487,187 +719,342 @@ void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int
ss_1 = 1-ss;
#endif
- filter_dc_notch16(ref, st->notch_radius, st->d, st->frame_size, st->notch_mem);
- /* Copy input data to buffer */
- for (i=0;iframe_size;i++)
+ for (chan = 0; chan < C; chan++)
{
- spx_word16_t tmp;
- spx_word32_t tmp32;
- st->x[i] = st->x[i+st->frame_size];
- tmp32 = SUB32(EXTEND32(echo[i]), EXTEND32(MULT16_16_P15(st->preemph, st->memX)));
+ /* 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;iframe_size;i++)
+ {
+ spx_word32_t tmp32;
+ /* 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
- /*FIXME: If saturation occurs here, we need to freeze adaptation for M frames (not just one) */
- if (tmp32 > 32767)
- {
- tmp32 = 32767;
- st->saturated = 1;
- }
- if (tmp32 < -32767)
- {
- tmp32 = -32767;
- st->saturated = 1;
- }
+ if (tmp32 > 32767)
+ {
+ tmp32 = 32767;
+ if (st->saturated == 0)
+ st->saturated = 1;
+ }
+ if (tmp32 < -32767)
+ {
+ tmp32 = -32767;
+ if (st->saturated == 0)
+ st->saturated = 1;
+ }
#endif
- st->x[i+st->frame_size] = EXTRACT16(tmp32);
- st->memX = echo[i];
-
- tmp = st->d[i];
- st->d[i] = st->d[i+st->frame_size];
- tmp32 = SUB32(EXTEND32(tmp), EXTEND32(MULT16_16_P15(st->preemph, st->memD)));
-#ifdef FIXED_POINT
- if (tmp32 > 32767)
- {
- tmp32 = 32767;
- st->saturated = 1;
- }
- if (tmp32 < -32767)
- {
- tmp32 = -32767;
- st->saturated = 1;
+ st->memD[chan] = st->input[chan*st->frame_size+i];
+ st->input[chan*st->frame_size+i] = EXTRACT16(tmp32);
}
-#endif
- st->d[i+st->frame_size] = tmp32;
- st->memD = tmp;
}
- /* Shift memory: this could be optimized eventually*/
- for (j=M-1;j>=0;j--)
+ for (speak = 0; speak < K; speak++)
{
- for (i=0;iX[(j+1)*N+i] = st->X[j*N+i];
- }
-
- /* Convert x (echo input) to frequency domain */
- spx_fft(st->fft_table, st->x, &st->X[0]);
+ for (i=0;iframe_size;i++)
+ {
+ spx_word32_t tmp32;
+ st->x[speak*N+i] = st->x[speak*N+i+st->frame_size];
+ 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 = M+1;
+ }
+ if (tmp32 < -32767)
+ {
+ tmp32 = -32767;
+ st->saturated = M+1;
+ }
+#endif
+ st->x[speak*N+i+st->frame_size] = EXTRACT16(tmp32);
+ st->memX[speak] = far_end[i*K+speak];
+ }
+ }
-#ifdef SMOOTH_BLOCKS
- spectral_mul_accum(st->X, st->W, st->Y, N, M);
- spx_ifft(st->fft_table, st->Y, st->e);
-#endif
-
- /* Compute weight gradient */
- if (!st->saturated)
+ for (speak = 0; speak < K; speak++)
{
+ /* Shift memory: this could be optimized eventually*/
for (j=M-1;j>=0;j--)
{
- weighted_spectral_mul_conj(st->power_1, &st->X[(j+1)*N], st->E, st->PHI, N);
for (i=0;iW[j*N+i] += MULT16_32_Q15(st->prop[j], st->PHI[i]);
-
- }
+ st->X[(j+1)*N*K+speak*N+i] = st->X[j*N*K+speak*N+i];
+ }
+ /* Convert x (echo input) to frequency domain */
+ spx_fft(st->fft_table, st->x+speak*N, &st->X[speak*N]);
}
- st->saturated = 0;
+ 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 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;iframe_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 == 0)
+ {
+ for (chan = 0; chan < C; chan++)
+ {
+ for (speak = 0; speak < K; speak++)
+ {
+ for (j=M-1;j>=0;j--)
+ {
+ 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;iW[chan*N*K*M + j*N*K + speak*N + i] += st->PHI[i];
+ }
+ }
+ }
+ } else {
+ st->saturated--;
+ }
+
+ /* FIXME: MC conversion required */
/* Update weight to prevent circular convolution (MDF / AUMDF) */
- for (j=0;jcancel_count%(M-1) == j-1)
+ for (speak = 0; speak < K; speak++)
{
+ for (j=0;jcancel_count%(M-1) == j-1)
+ {
#ifdef FIXED_POINT
- for (i=0;iwtmp2[i] = EXTRACT16(PSHR32(st->W[j*N+i],NORMALIZE_SCALEDOWN+16));
- spx_ifft(st->fft_table, st->wtmp2, st->wtmp);
+ for (i=0;iwtmp2[i] = EXTRACT16(PSHR32(st->W[chan*N*K*M + j*N*K + speak*N + i],NORMALIZE_SCALEDOWN+16));
+ spx_ifft(st->fft_table, st->wtmp2, st->wtmp);
+ for (i=0;iframe_size;i++)
+ {
+ st->wtmp[i]=0;
+ }
+ for (i=st->frame_size;iwtmp[i]=SHL16(st->wtmp[i],NORMALIZE_SCALEUP);
+ }
+ spx_fft(st->fft_table, st->wtmp, st->wtmp2);
+ /* The "-1" in the shift is a sort of kludge that trades less efficient update speed for decrease noise */
+ for (i=0;iW[chan*N*K*M + j*N*K + speak*N + i] -= SHL32(EXTEND32(st->wtmp2[i]),16+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1);
+#else
+ spx_ifft(st->fft_table, &st->W[chan*N*K*M + j*N*K + speak*N], st->wtmp);
+ for (i=st->frame_size;iwtmp[i]=0;
+ }
+ spx_fft(st->fft_table, st->wtmp, &st->W[chan*N*K*M + j*N*K + speak*N]);
+#endif
+ }
+ }
+ }
+ }
+
+ /* 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++)
+ {
+ 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;iframe_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;iframe_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;iforeground[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;iframe_size;i++)
- {
- st->wtmp[i]=0;
- }
- for (i=st->frame_size;iwtmp[i]=SHL16(st->wtmp[i],NORMALIZE_SCALEUP);
- }
- spx_fft(st->fft_table, st->wtmp, st->wtmp2);
- /* The "-1" in the shift is a sort of kludge that trades less efficient update speed for decrease noise */
- for (i=0;iW[j*N+i] -= SHL32(EXTEND32(st->wtmp2[i]),16+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1);
-#else
- spx_ifft(st->fft_table, &st->W[j*N], st->wtmp);
- for (i=st->frame_size;iwtmp[i]=0;
- }
- spx_fft(st->fft_table, st->wtmp, &st->W[j*N]);
-#endif
- }
- }
-
- /* Compute filter response Y */
- spectral_mul_accum(st->X, st->W, st->Y, N, M);
- spx_ifft(st->fft_table, st->Y, st->y);
-
-
- /* Compute error signal (for the output with de-emphasis) */
- for (i=0;iframe_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[i+st->frame_size]) + MULT16_16_Q15(st->window[i],st->y[i+st->frame_size]);
- tmp_out = SUB32(EXTEND32(st->d[i+st->frame_size]), EXTEND32(y));
-#else
- tmp_out = SUB32(EXTEND32(st->d[i+st->frame_size]), EXTEND32(st->y[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)));
- /* This is an arbitrary test for saturation */
- if (ref[i] <= -32000 || ref[i] >= 32000)
+ 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)
{
- tmp_out = 0;
- st->saturated = 1;
+ /* Copy foreground filter to background filter */
+ for (i=0;iW[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;iframe_size;i++)
+ st->y[chan*N+i+st->frame_size] = st->e[chan*N+i+st->frame_size];
+ for (i=0;iframe_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;
}
- out[i] = (spx_int16_t)tmp_out;
- st->memE = tmp_out;
}
+#endif
- /* Compute error signal (filter update version) */
- for (i=0;iframe_size;i++)
- {
- st->e[i] = 0;
- st->e[i+st->frame_size] = st->d[i+st->frame_size] - st->y[i+st->frame_size];
- }
+ Sey = Syy = Sdd = 0;
+ for (chan = 0; chan < C; chan++)
+ {
+ /* Compute error signal (for the output with de-emphasis) */
+ for (i=0;iframe_size;i++)
+ {
+ spx_word32_t tmp_out;
+#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->input[chan*st->frame_size+i]), EXTEND32(st->y[chan*N+i+st->frame_size]));
+#endif
+ tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE[chan])));
+ /* This is an arbitrary test for saturation in the microphone signal */
+ if (in[i*C+chan] <= -32000 || in[i*C+chan] >= 32000)
+ {
+ if (st->saturated == 0)
+ st->saturated = 1;
+ }
+ out[i*C+chan] = WORD2INT(tmp_out);
+ st->memE[chan] = tmp_out;
+ }
- /* Compute a bunch of correlations */
- Sey = mdf_inner_prod(st->e+st->frame_size, st->y+st->frame_size, st->frame_size);
- See = mdf_inner_prod(st->e+st->frame_size, st->e+st->frame_size, st->frame_size);
- See = ADD32(See, SHR32(MULT16_16(N, 100),6));
- Syy = mdf_inner_prod(st->y+st->frame_size, st->y+st->frame_size, st->frame_size);
- Sxx = mdf_inner_prod(st->x+st->frame_size, st->x+st->frame_size, st->frame_size);
-
- /* Convert error to frequency domain */
- spx_fft(st->fft_table, st->e, st->E);
- for (i=0;iframe_size;i++)
- st->y[i] = 0;
- spx_fft(st->fft_table, st->y, st->Y);
-
- /* Compute power spectrum of echo (X), error (E) and filter response (Y) */
- power_spectrum(st->E, st->Rf, N);
- power_spectrum(st->Y, st->Yf, N);
- power_spectrum(st->X, st->Xf, N);
+#ifdef DUMP_ECHO_CANCEL_DATA
+ dump_audio(in, far_end, out, st->frame_size);
+#endif
- /* Smooth echo energy estimate over time */
+ /* Compute error signal (filter update version) */
+ for (i=0;iframe_size;i++)
+ {
+ st->e[chan*N+i+st->frame_size] = st->e[chan*N+i];
+ st->e[chan*N+i] = 0;
+ }
+
+ /* Compute a bunch of correlations */
+ /* 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;iframe_size;i++)
+ st->y[i+chan*N] = 0;
+ spx_fft(st->fft_table, st->y+chan*N, st->Y+chan*N);
+
+ /* 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);
+
+ }
+
+ /*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;iframe_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 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]);
-
- /* Enable this to compute the power based only on the tail (would need to compute more
- efficiently to make this really useful */
- if (0)
- {
- float scale2 = .5f/M;
- for (j=0;j<=st->frame_size;j++)
- st->power[j] = 100;
- for (i=0;iX[i*N], st->Xf, N);
- for (j=0;j<=st->frame_size;j++)
- st->power[j] += scale2*st->Xf[j];
- }
- }
/* Compute filtered spectra and (cross-)correlations */
for (j=st->frame_size;j>=0;j--)
@@ -706,17 +1093,17 @@ void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int
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 = 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) */
{
@@ -731,7 +1118,7 @@ void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int
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;
+ 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);
@@ -740,18 +1127,19 @@ void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int
#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 > SHL32(EXTEND32(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))
@@ -764,20 +1152,22 @@ void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int
/*st->power_1[i] = adapt_rate*r/(e*(1+st->power[i]));*/
st->power_1[i] = FLOAT_SHL(FLOAT_DIV32_FLOAT(r,FLOAT_MUL32U(e,st->power[i]+10)),WEIGHT_SHIFT+16);
}
- } else if (Sxx > SHR32(MULT16_16(N, 1000),6)) {
+ } else {
/* Temporary adaption rate if filter is not yet adapted enough */
spx_word16_t adapt_rate=0;
- tmp32 = MULT16_32_Q15(QCONST16(.25f, 15), Sxx);
+ if (Sxx > SHR32(MULT16_16(N, 1000),6))
+ {
+ tmp32 = MULT16_32_Q15(QCONST16(.25f, 15), Sxx);
#ifdef FIXED_POINT
- if (tmp32 > SHR32(See,2))
- tmp32 = SHR32(See,2);
+ if (tmp32 > SHR32(See,2))
+ tmp32 = SHR32(See,2);
#else
- if (tmp32 > .25*See)
- tmp32 = .25*See;
+ if (tmp32 > .25*See)
+ tmp32 = .25*See;
#endif
- adapt_rate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32, 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);
@@ -786,50 +1176,57 @@ void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int
st->sum_adapt = ADD32(st->sum_adapt,adapt_rate);
}
- /* Compute spectrum of estimated echo for use in an echo post-filter (if necessary)*/
- if (Yout)
+ /* FIXME: MC conversion required */
+ for (i=0;iframe_size;i++)
+ st->last_y[i] = st->last_y[st->frame_size+i];
+ if (st->adapted)
{
- spx_word16_t leak2;
- if (st->adapted)
- {
- /* If the filter is adapted, take the filtered echo */
- for (i=0;iframe_size;i++)
- st->last_y[i] = st->last_y[st->frame_size+i];
- for (i=0;iframe_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;ilast_y[i] = st->x[i];
- }
-
- /* Apply hanning window (should pre-compute it)*/
- for (i=0;iy[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);
-
-#ifdef FIXED_POINT
- if (leak_estimate > 16383)
- leak2 = 32767;
- else
- leak2 = SHL16(leak_estimate, 1);
-#else
- if (leak_estimate>.5)
- leak2 = 1;
- else
- leak2 = 2*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]);
+ /* If the filter is adapted, take the filtered echo */
+ for (i=0;iframe_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;ilast_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;
-int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr)
+ /* Apply hanning window (should pre-compute it)*/
+ for (i=0;iy[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, residual_echo, N);
+
+#ifdef FIXED_POINT
+ if (st->leak_estimate > 16383)
+ leak2 = 32767;
+ else
+ leak2 = SHL16(st->leak_estimate, 1);
+#else
+ 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++)
+ residual_echo[i] = (spx_int32_t)MULT16_32_Q15(leak2,residual_echo[i]);
+
+}
+
+EXPORT int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr)
{
switch(request)
{
@@ -857,6 +1254,29 @@ int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr)
case SPEEX_ECHO_GET_SAMPLING_RATE:
(*(int*)ptr) = st->sampling_rate;
break;
+ case SPEEX_ECHO_GET_IMPULSE_RESPONSE_SIZE:
+ /*FIXME: Implement this for multiple channels */
+ *((spx_int32_t *)ptr) = st->M * st->frame_size;
+ break;
+ case SPEEX_ECHO_GET_IMPULSE_RESPONSE:
+ {
+ int M = st->M, N = st->window_size, n = st->frame_size, i, j;
+ spx_int32_t *filt = (spx_int32_t *) ptr;
+ for(j=0;jwtmp2[i] = EXTRACT16(PSHR32(st->W[j*N+i],16+NORMALIZE_SCALEDOWN));
+ spx_ifft(st->fft_table, st->wtmp2, st->wtmp);
+#else
+ spx_ifft(st->fft_table, &st->W[j*N], st->wtmp);
+#endif
+ for(i=0;iwtmp[i]), WEIGHT_SHIFT-NORMALIZE_SCALEDOWN);
+ }
+ }
+ break;
default:
speex_warning_int("Unknown speex_echo_ctl request: ", request);
return -1;
diff --git a/libs/speex/libspeex/modes.c b/libs/speex/libspeex/modes.c
index 97e7d1e3fa..e10a32e8e7 100644
--- a/libs/speex/libspeex/modes.c
+++ b/libs/speex/libspeex/modes.c
@@ -43,28 +43,23 @@
#include "sb_celp.h"
#include "nb_celp.h"
#include "vbr.h"
-#include "misc.h"
+#include "arch.h"
#include
#ifndef NULL
#define NULL 0
#endif
-#define MAX_IN_SAMPLES 640
-
-const SpeexMode * const speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, &speex_uwb_mode};
/* Extern declarations for all codebooks we use here */
extern const signed char gain_cdbk_nb[];
extern const signed char gain_cdbk_lbr[];
-extern const signed char hexc_table[];
extern const signed char exc_5_256_table[];
extern const signed char exc_5_64_table[];
extern const signed char exc_8_128_table[];
extern const signed char exc_10_32_table[];
extern const signed char exc_10_16_table[];
extern const signed char exc_20_32_table[];
-extern const signed char hexc_10_32_table[];
/* Parameters for Long-Term Prediction (LTP)*/
@@ -150,28 +145,7 @@ static const split_cb_params split_cb_sb = {
0,
};
-#ifndef DISABLE_WIDEBAND
-/* Split-VQ innovation for high-band wideband */
-static const split_cb_params split_cb_high = {
- 8, /*subvect_size*/
- 5, /*nb_subvect*/
- hexc_table, /*shape_cb*/
- 7, /*shape_bits*/
- 1,
-};
-
-
-/* Split-VQ innovation for high-band wideband */
-static const split_cb_params split_cb_high_lbr = {
- 10, /*subvect_size*/
- 4, /*nb_subvect*/
- hexc_10_32_table, /*shape_cb*/
- 5, /*shape_bits*/
- 0,
-};
-
-#endif
/* 2150 bps "vocoder-like" mode for comfort noise */
static const SpeexSubmode nb_submode1 = {
@@ -354,11 +328,7 @@ static const SpeexNBMode nb_mode = {
#else
0.9, 0.6, /* gamma1, gamma2 */
#endif
- .012, /*lag_factor*/
QCONST16(.0002,15), /*lpc_floor*/
-#ifdef EPIC_48K
- 0,
-#endif
{NULL, &nb_submode1, &nb_submode2, &nb_submode3, &nb_submode4, &nb_submode5, &nb_submode6, &nb_submode7,
&nb_submode8, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
5,
@@ -367,7 +337,7 @@ static const SpeexNBMode nb_mode = {
/* Default mode for narrowband */
-const SpeexMode speex_nb_mode = {
+EXPORT const SpeexMode speex_nb_mode = {
&nb_mode,
nb_mode_query,
"narrowband",
@@ -384,290 +354,13 @@ const SpeexMode speex_nb_mode = {
};
-/* Wideband part */
-static const SpeexSubmode wb_submode1 = {
- 0,
- 0,
- 1,
- 0,
- /*LSP quantization*/
- lsp_quant_high,
- lsp_unquant_high,
- /*Pitch quantization*/
- NULL,
- NULL,
- NULL,
- /*No innovation quantization*/
- NULL,
- NULL,
- NULL,
- -1,
- 36
-};
-
-
-static const SpeexSubmode wb_submode2 = {
- 0,
- 0,
- 1,
- 0,
- /*LSP quantization*/
- lsp_quant_high,
- lsp_unquant_high,
- /*Pitch quantization*/
- NULL,
- NULL,
- NULL,
- /*Innovation quantization*/
- split_cb_search_shape_sign,
- split_cb_shape_sign_unquant,
-#ifdef DISABLE_WIDEBAND
- NULL,
-#else
- &split_cb_high_lbr,
-#endif
- -1,
- 112
-};
-
-
-static const SpeexSubmode wb_submode3 = {
- 0,
- 0,
- 1,
- 0,
- /*LSP quantization*/
- lsp_quant_high,
- lsp_unquant_high,
- /*Pitch quantization*/
- NULL,
- NULL,
- NULL,
- /*Innovation quantization*/
- split_cb_search_shape_sign,
- split_cb_shape_sign_unquant,
-#ifdef DISABLE_WIDEBAND
- NULL,
-#else
- &split_cb_high,
-#endif
- -1,
- 192
-};
-
-static const SpeexSubmode wb_submode4 = {
- 0,
- 0,
- 1,
- 1,
- /*LSP quantization*/
- lsp_quant_high,
- lsp_unquant_high,
- /*Pitch quantization*/
- NULL,
- NULL,
- NULL,
- /*Innovation quantization*/
- split_cb_search_shape_sign,
- split_cb_shape_sign_unquant,
-#ifdef DISABLE_WIDEBAND
- NULL,
-#else
- &split_cb_high,
-#endif
- -1,
- 352
-};
-
-
-/* Split-band wideband CELP mode*/
-static const SpeexSBMode sb_wb_mode = {
- &speex_nb_mode,
- 160, /*frameSize*/
- 40, /*subframeSize*/
- 8, /*lpcSize*/
- 640, /*bufSize*/
-#ifdef FIXED_POINT
- 29491, 19661, /* gamma1, gamma2 */
-#else
- 0.9, 0.6, /* gamma1, gamma2 */
-#endif
- .012, /*lag_factor*/
- QCONST16(.0002,15), /*lpc_floor*/
- 0.9,
- {NULL, &wb_submode1, &wb_submode2, &wb_submode3, &wb_submode4, NULL, NULL, NULL},
- 3,
- {1, 8, 2, 3, 4, 5, 5, 6, 6, 7, 7},
- {1, 1, 1, 1, 1, 1, 2, 2, 3, 3, 4},
- vbr_hb_thresh,
- 5
-};
-
-
-const SpeexMode speex_wb_mode = {
- &sb_wb_mode,
- wb_mode_query,
- "wideband (sub-band CELP)",
- 1,
- 4,
- &sb_encoder_init,
- &sb_encoder_destroy,
- &sb_encode,
- &sb_decoder_init,
- &sb_decoder_destroy,
- &sb_decode,
- &sb_encoder_ctl,
- &sb_decoder_ctl,
-};
-
-
-
-/* "Ultra-wideband" mode stuff */
-
-
-
-/* Split-band "ultra-wideband" (32 kbps) CELP mode*/
-static const SpeexSBMode sb_uwb_mode = {
- &speex_wb_mode,
- 320, /*frameSize*/
- 80, /*subframeSize*/
- 8, /*lpcSize*/
- 1280, /*bufSize*/
-#ifdef FIXED_POINT
- 29491, 19661, /* gamma1, gamma2 */
-#else
- 0.9, 0.6, /* gamma1, gamma2 */
-#endif
- .012, /*lag_factor*/
- QCONST16(.0002,15), /*lpc_floor*/
- 0.7,
- {NULL, &wb_submode1, NULL, NULL, NULL, NULL, NULL, NULL},
- 1,
- {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
- {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
- vbr_uhb_thresh,
- 2
-};
-
-
-const SpeexMode speex_uwb_mode = {
- &sb_uwb_mode,
- wb_mode_query,
- "ultra-wideband (sub-band CELP)",
- 2,
- 4,
- &sb_encoder_init,
- &sb_encoder_destroy,
- &sb_encode,
- &sb_decoder_init,
- &sb_decoder_destroy,
- &sb_decode,
- &sb_encoder_ctl,
- &sb_decoder_ctl,
-};
-
-
-
-
-#ifdef EPIC_48K
-
-extern const signed char gain_cdbk_ulbr[];
-extern const signed char exc_12_32_table[];
-
-/* Parameters for Long-Term Prediction (LTP)*/
-static const ltp_params ltp_params_48k = {
- gain_cdbk_ulbr,
- 3,
- 0
-};
-
-static const split_cb_params split_cb_nb_48k = {
- 12, /*subvect_size*/
- 4, /*nb_subvect*/
- exc_12_32_table, /*shape_cb*/
- 5, /*shape_bits*/
- 0,
-};
-
-
-/* 4.8 kbps very low bit-rate mode */
-static const SpeexSubmode nb_48k_submode = {
- 0,
- 0,
- 0,
- 0,
- /*LSP quantization*/
- lsp_quant_48k,
- lsp_unquant_48k,
- /*No pitch quantization*/
- pitch_search_3tap,
- pitch_unquant_3tap,
- <p_params_48k,
- /*Innovation quantization*/
- 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
- 144
-};
-
-
-/* Special, non-standard 4.8 kbps mode */
-static const SpeexNBMode nb_48k_mode = {
- 240, /*frameSize*/
- 48, /*subframeSize*/
- 10, /*lpcSize*/
- 640, /*bufSize*/
- 17, /*pitchStart*/
- 144, /*pitchEnd*/
- 0.9, /*gamma1*/
- 0.6, /*gamma2*/
- .01, /*lag_factor*/
- QCONST16(.0003,15), /*lpc_floor*/
- 1,
- {NULL, NULL, &nb_48k_submode, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- 2,
- {2,2,2,2,2,2,2,2,2,2,2}
-};
-
-
-/* Default mode for narrowband */
-const SpeexMode speex_nb_48k_mode = {
- &nb_48k_mode,
- nb_mode_query,
- "narrowband 4.8 kbps",
- 1000,
- 4,
- &nb_encoder_init,
- &nb_encoder_destroy,
- &nb_encode,
- &nb_decoder_init,
- &nb_decoder_destroy,
- &nb_decode,
- &nb_encoder_ctl,
- &nb_decoder_ctl,
-};
-
-
-#endif
-
-int speex_mode_query(const SpeexMode *mode, int request, void *ptr)
+EXPORT int speex_mode_query(const SpeexMode *mode, int request, void *ptr)
{
return mode->query(mode->mode, request, ptr);
}
-const SpeexMode * speex_lib_get_mode (int mode)
-{
-#ifdef EPIC_48K
- if (mode == SPEEX_MODEID_NB_48K) return &speex_nb_48k_mode;
+#ifdef FIXED_DEBUG
+long long spx_mips=0;
#endif
- if (mode < 0 || mode > SPEEX_NB_MODES) return NULL;
-
- return speex_mode_list[mode];
-}
diff --git a/libs/speex/libspeex/modes.h b/libs/speex/libspeex/modes.h
index 6a632402f7..26e2d86180 100644
--- a/libs/speex/libspeex/modes.h
+++ b/libs/speex/libspeex/modes.h
@@ -38,7 +38,7 @@
#include
#include
-#include "misc.h"
+#include "arch.h"
#define NB_SUBMODES 16
#define NB_SUBMODE_BITS 4
@@ -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 *);
@@ -81,7 +98,7 @@ typedef struct SpeexSubmode {
lsp_quant_func lsp_quant; /**< LSP quantization function */
lsp_unquant_func lsp_unquant; /**< LSP unquantization function */
- /*Lont-term predictor functions*/
+ /*Long-term predictor functions*/
ltp_quant_func ltp_quant; /**< Long-term predictor (pitch) quantizer */
ltp_unquant_func ltp_unquant; /**< Long-term predictor (pitch) un-quantizer */
const void *ltp_params; /**< Pitch parameters (options) */
@@ -106,13 +123,8 @@ typedef struct SpeexNBMode {
spx_word16_t gamma1; /**< Perceptual filter parameter #1 */
spx_word16_t gamma2; /**< Perceptual filter parameter #2 */
- float lag_factor; /**< Lag-windowing parameter */
spx_word16_t lpc_floor; /**< Noise floor for LPC analysis */
-#ifdef EPIC_48K
- int lbr48k; /**< 1 for the special 4.8 kbps mode */
-#endif
-
const SpeexSubmode *submodes[NB_SUBMODES]; /**< Sub-mode data for the mode */
int defaultSubmode; /**< Default sub-mode to use when encoding */
int quality_map[11]; /**< Mode corresponding to each quality setting */
@@ -125,18 +137,18 @@ typedef struct SpeexSBMode {
int frameSize; /**< Size of frames used for encoding */
int subframeSize; /**< Size of sub-frames used for encoding */
int lpcSize; /**< Order of LPC filter */
- int bufSize; /**< Signal buffer size in encoder */
spx_word16_t gamma1; /**< Perceptual filter parameter #1 */
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 */
int low_quality_map[11]; /**< Mode corresponding to each quality setting */
int quality_map[11]; /**< Mode corresponding to each quality setting */
+#ifndef DISABLE_VBR
const float (*vbr_thresh)[11];
+#endif
int nb_modes;
} SpeexSBMode;
diff --git a/libs/speex/libspeex/modes_wb.c b/libs/speex/libspeex/modes_wb.c
new file mode 100644
index 0000000000..e3b484223e
--- /dev/null
+++ b/libs/speex/libspeex/modes_wb.c
@@ -0,0 +1,300 @@
+/* Copyright (C) 2002-2007 Jean-Marc Valin
+ File: modes.c
+
+ Describes the wideband 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.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "modes.h"
+#include "ltp.h"
+#include "quant_lsp.h"
+#include "cb_search.h"
+#include "sb_celp.h"
+#include "nb_celp.h"
+#include "vbr.h"
+#include "arch.h"
+#include
+#include "os_support.h"
+
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+EXPORT const SpeexMode * const speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, &speex_uwb_mode};
+
+extern const signed char hexc_table[];
+extern const signed char hexc_10_32_table[];
+
+#ifndef DISABLE_WIDEBAND
+
+/* Split-VQ innovation for high-band wideband */
+static const split_cb_params split_cb_high = {
+ 8, /*subvect_size*/
+ 5, /*nb_subvect*/
+ hexc_table, /*shape_cb*/
+ 7, /*shape_bits*/
+ 1,
+};
+
+
+/* Split-VQ innovation for high-band wideband */
+static const split_cb_params split_cb_high_lbr = {
+ 10, /*subvect_size*/
+ 4, /*nb_subvect*/
+ hexc_10_32_table, /*shape_cb*/
+ 5, /*shape_bits*/
+ 0,
+};
+
+#endif
+
+
+static const SpeexSubmode wb_submode1 = {
+ 0,
+ 0,
+ 1,
+ 0,
+ /*LSP quantization*/
+ lsp_quant_high,
+ lsp_unquant_high,
+ /*Pitch quantization*/
+ NULL,
+ NULL,
+ NULL,
+ /*No innovation quantization*/
+ NULL,
+ NULL,
+ NULL,
+ -1,
+ 36
+};
+
+
+static const SpeexSubmode wb_submode2 = {
+ 0,
+ 0,
+ 1,
+ 0,
+ /*LSP quantization*/
+ lsp_quant_high,
+ lsp_unquant_high,
+ /*Pitch quantization*/
+ NULL,
+ NULL,
+ NULL,
+ /*Innovation quantization*/
+ split_cb_search_shape_sign,
+ split_cb_shape_sign_unquant,
+#ifdef DISABLE_WIDEBAND
+ NULL,
+#else
+ &split_cb_high_lbr,
+#endif
+ -1,
+ 112
+};
+
+
+static const SpeexSubmode wb_submode3 = {
+ 0,
+ 0,
+ 1,
+ 0,
+ /*LSP quantization*/
+ lsp_quant_high,
+ lsp_unquant_high,
+ /*Pitch quantization*/
+ NULL,
+ NULL,
+ NULL,
+ /*Innovation quantization*/
+ split_cb_search_shape_sign,
+ split_cb_shape_sign_unquant,
+#ifdef DISABLE_WIDEBAND
+ NULL,
+#else
+ &split_cb_high,
+#endif
+ -1,
+ 192
+};
+
+static const SpeexSubmode wb_submode4 = {
+ 0,
+ 0,
+ 1,
+ 1,
+ /*LSP quantization*/
+ lsp_quant_high,
+ lsp_unquant_high,
+ /*Pitch quantization*/
+ NULL,
+ NULL,
+ NULL,
+ /*Innovation quantization*/
+ split_cb_search_shape_sign,
+ split_cb_shape_sign_unquant,
+#ifdef DISABLE_WIDEBAND
+ NULL,
+#else
+ &split_cb_high,
+#endif
+ -1,
+ 352
+};
+
+
+/* Split-band wideband CELP mode*/
+static const SpeexSBMode sb_wb_mode = {
+ &speex_nb_mode,
+ 160, /*frameSize*/
+ 40, /*subframeSize*/
+ 8, /*lpcSize*/
+#ifdef FIXED_POINT
+ 29491, 19661, /* gamma1, gamma2 */
+#else
+ 0.9, 0.6, /* gamma1, gamma2 */
+#endif
+ QCONST16(.0002,15), /*lpc_floor*/
+ 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},
+ {1, 1, 1, 1, 1, 1, 2, 2, 3, 3, 4},
+#ifndef DISABLE_VBR
+ vbr_hb_thresh,
+#endif
+ 5
+};
+
+
+EXPORT const SpeexMode speex_wb_mode = {
+ &sb_wb_mode,
+ wb_mode_query,
+ "wideband (sub-band CELP)",
+ 1,
+ 4,
+ &sb_encoder_init,
+ &sb_encoder_destroy,
+ &sb_encode,
+ &sb_decoder_init,
+ &sb_decoder_destroy,
+ &sb_decode,
+ &sb_encoder_ctl,
+ &sb_decoder_ctl,
+};
+
+
+
+/* "Ultra-wideband" mode stuff */
+
+
+
+/* Split-band "ultra-wideband" (32 kbps) CELP mode*/
+static const SpeexSBMode sb_uwb_mode = {
+ &speex_wb_mode,
+ 320, /*frameSize*/
+ 80, /*subframeSize*/
+ 8, /*lpcSize*/
+#ifdef FIXED_POINT
+ 29491, 19661, /* gamma1, gamma2 */
+#else
+ 0.9, 0.6, /* gamma1, gamma2 */
+#endif
+ QCONST16(.0002,15), /*lpc_floor*/
+ 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},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+#ifndef DISABLE_VBR
+ vbr_uhb_thresh,
+#endif
+ 2
+};
+
+int wb_mode_query(const void *mode, int request, void *ptr)
+{
+ const SpeexSBMode *m = (const SpeexSBMode*)mode;
+
+ switch (request)
+ {
+ case SPEEX_MODE_FRAME_SIZE:
+ *((int*)ptr)=2*m->frameSize;
+ break;
+ case SPEEX_SUBMODE_BITS_PER_FRAME:
+ if (*((int*)ptr)==0)
+ *((int*)ptr) = SB_SUBMODE_BITS+1;
+ else if (m->submodes[*((int*)ptr)]==NULL)
+ *((int*)ptr) = -1;
+ else
+ *((int*)ptr) = m->submodes[*((int*)ptr)]->bits_per_frame;
+ break;
+ default:
+ speex_warning_int("Unknown wb_mode_query request: ", request);
+ return -1;
+ }
+ return 0;
+}
+
+
+EXPORT const SpeexMode speex_uwb_mode = {
+ &sb_uwb_mode,
+ wb_mode_query,
+ "ultra-wideband (sub-band CELP)",
+ 2,
+ 4,
+ &sb_encoder_init,
+ &sb_encoder_destroy,
+ &sb_encode,
+ &sb_decoder_init,
+ &sb_decoder_destroy,
+ &sb_decode,
+ &sb_encoder_ctl,
+ &sb_decoder_ctl,
+};
+
+/* We have defined speex_lib_get_mode() as a macro in speex.h */
+#undef speex_lib_get_mode
+
+EXPORT const SpeexMode * speex_lib_get_mode (int mode)
+{
+ if (mode < 0 || mode >= SPEEX_NB_MODES) return NULL;
+
+ return speex_mode_list[mode];
+}
+
+
+
diff --git a/libs/speex/libspeex/nb_celp.c b/libs/speex/libspeex/nb_celp.c
index 234ac2d529..9dd726a0cf 100644
--- a/libs/speex/libspeex/nb_celp.c
+++ b/libs/speex/libspeex/nb_celp.c
@@ -45,8 +45,9 @@
#include "vq.h"
#include
#include "vbr.h"
-#include "misc.h"
+#include "arch.h"
#include "math_approx.h"
+#include "os_support.h"
#include
#ifdef VORBIS_PSYCHO
@@ -87,14 +88,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
@@ -107,6 +108,7 @@ const float exc_gain_quant_scal1[2]={0.70469, 1.05127};
#define sqr(x) ((x)*(x))
+extern const spx_word16_t lag_window[];
extern const spx_word16_t lpc_window[];
void *nb_encoder_init(const SpeexMode *m)
@@ -136,7 +138,6 @@ void *nb_encoder_init(const SpeexMode *m)
st->gamma2=mode->gamma2;
st->min_pitch=mode->pitchStart;
st->max_pitch=mode->pitchEnd;
- st->lag_factor=mode->lag_factor;
st->lpc_floor = mode->lpc_floor;
st->submodes=mode->submodes;
@@ -144,9 +145,6 @@ void *nb_encoder_init(const SpeexMode *m)
st->bounded_pitch = 1;
st->encode_submode = 1;
-#ifdef EPIC_48K
- st->lbr_48k=mode->lbr48k;
-#endif
#ifdef VORBIS_PSYCHO
st->psy = vorbis_psy_init(8000, 256);
@@ -168,17 +166,13 @@ void *nb_encoder_init(const SpeexMode *m)
st->window= lpc_window;
/* Create the window for autocorrelation (lag-windowing) */
- st->lagWindow = (spx_word16_t*)speex_alloc((st->lpcSize+1)*sizeof(spx_word16_t));
- for (i=0;ilpcSize+1;i++)
- st->lagWindow[i]=16384*exp(-.5*sqr(2*M_PI*st->lag_factor*i));
+ st->lagWindow = lag_window;
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->first = 1;
for (i=0;ilpcSize;i++)
- {
- st->old_lsp[i]=LSP_SCALING*(M_PI*((float)(i+1)))/(st->lpcSize+1);
- }
+ st->old_lsp[i]= DIV32(MULT16_16(QCONST16(3.1415927f, LSP_SHIFT), i+1), st->lpcSize+1);
st->mem_sp = (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));
@@ -187,10 +181,11 @@ 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));
+#ifndef DISABLE_VBR
st->vbr = (VBRState*)speex_alloc(sizeof(VBRState));
vbr_init(st->vbr);
st->vbr_quality = 8;
@@ -198,18 +193,20 @@ void *nb_encoder_init(const SpeexMode *m)
st->vbr_max = 0;
st->vad_enabled = 0;
st->dtx_enabled = 0;
+ st->dtx_count=0;
st->abr_enabled = 0;
st->abr_drift = 0;
+ st->abr_drift2 = 0;
+#endif /* #ifndef DISABLE_VBR */
st->plc_tuning = 2;
st->complexity=2;
st->sampling_rate=8000;
- st->dtx_count=0;
st->isWideband = 0;
st->highpass_enabled = 1;
#ifdef ENABLE_VALGRIND
- VALGRIND_MAKE_READABLE(st, (st->stack-(char*)st));
+ VALGRIND_MAKE_READABLE(st, NB_ENC_STACK);
#endif
return st;
}
@@ -227,8 +224,6 @@ void nb_encoder_destroy(void *state)
speex_free (st->old_qlsp);
speex_free (st->swBuf);
- speex_free (st->lagWindow);
-
speex_free (st->old_lsp);
speex_free (st->mem_sp);
speex_free (st->mem_sw);
@@ -238,8 +233,10 @@ void nb_encoder_destroy(void *state)
speex_free (st->pi_gain);
speex_free (st->pitch);
+#ifndef DISABLE_VBR
vbr_destroy(st->vbr);
speex_free (st->vbr);
+#endif /* #ifndef DISABLE_VBR */
#ifdef VORBIS_PSYCHO
vorbis_psy_destroy(st->psy);
@@ -276,10 +273,9 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
char *stack;
VARDECL(spx_word16_t *syn_resp);
VARDECL(spx_word16_t *real_exc);
-#ifdef EPIC_48K
- 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;
@@ -296,8 +292,8 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
ALLOC(interp_qlpc, st->lpcSize, spx_coef_t);
/* Move signals 1 frame towards the past */
- speex_move(st->excBuf, st->excBuf+st->frameSize, (st->max_pitch+2)*sizeof(spx_word16_t));
- speex_move(st->swBuf, st->swBuf+st->frameSize, (st->max_pitch+2)*sizeof(spx_word16_t));
+ SPEEX_MOVE(st->excBuf, st->excBuf+st->frameSize, st->max_pitch+2);
+ SPEEX_MOVE(st->swBuf, st->swBuf+st->frameSize, st->max_pitch+2);
if (st->highpass_enabled)
highpass(in, in, st->frameSize, (st->isWideband?HIGHPASS_WIDEBAND:HIGHPASS_NARROWBAND)|HIGHPASS_INPUT, st->mem_hp);
@@ -340,6 +336,7 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
/* Whole frame analysis (open-loop estimation of pitch and excitation gain) */
{
+ int diff = st->windowSize-st->frameSize;
if (st->first)
for (i=0;ilpcSize;i++)
interp_lsp[i] = lsp[i];
@@ -353,19 +350,20 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
/*Open-loop pitch*/
- if (st->complexity>2 || !st->submodes[st->submodeID] || st->vbr_enabled || st->vad_enabled || SUBMODE(forced_pitch_gain) ||
- SUBMODE(lbr_pitch) != -1)
+ if (!st->submodes[st->submodeID] || (st->complexity>2 && SUBMODE(have_subframe_gain)<3) || SUBMODE(forced_pitch_gain) || SUBMODE(lbr_pitch) != -1
+#ifndef DISABLE_VBR
+ || st->vbr_enabled || st->vad_enabled
+#endif
+ )
{
int nol_pitch[6];
spx_word16_t nol_pitch_coef[6];
bw_lpc(st->gamma1, interp_lpc, bw_lpc1, st->lpcSize);
bw_lpc(st->gamma2, interp_lpc, bw_lpc2, st->lpcSize);
-
- for (i=0;iwindowSize-st->frameSize;i++)
- st->sw[i] = st->winBuf[i];
- for (;iframeSize;i++)
- st->sw[i] = in[i-st->windowSize+st->frameSize];
+
+ SPEEX_COPY(st->sw, st->winBuf, diff);
+ SPEEX_COPY(st->sw+diff, in, st->frameSize-diff);
filter_mem16(st->sw, bw_lpc1, bw_lpc2, st->sw, st->frameSize, st->lpcSize, st->mem_sw_whole, stack);
open_loop_nbest_pitch(st->sw, st->min_pitch, st->max_pitch, st->frameSize,
@@ -391,54 +389,20 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
ol_pitch/=2;*/
/*ol_pitch_coef = sqrt(ol_pitch_coef);*/
-#ifdef EPIC_48K
- if (st->lbr_48k)
- {
- if (ol_pitch < st->min_pitch+2)
- ol_pitch = st->min_pitch+2;
- if (ol_pitch > st->max_pitch-2)
- ol_pitch = st->max_pitch-2;
- open_loop_nbest_pitch(st->sw, ol_pitch-2, ol_pitch+2, st->frameSize>>1,
- &pitch_half[0], nol_pitch_coef, 1, stack);
- open_loop_nbest_pitch(st->sw+(st->frameSize>>1), pitch_half[0]-1, pitch_half[0]+2, st->frameSize>>1,
- &pitch_half[1], nol_pitch_coef, 1, stack);
- }
-#endif
} else {
ol_pitch=0;
ol_pitch_coef=0;
}
/*Compute "real" excitation*/
- for (i=0;iwindowSize-st->frameSize;i++)
- st->exc[i] = st->winBuf[i];
- for (;iframeSize;i++)
- st->exc[i] = in[i-st->windowSize+st->frameSize];
+ SPEEX_COPY(st->exc, st->winBuf, diff);
+ SPEEX_COPY(st->exc+diff, in, st->frameSize-diff);
fir_mem16(st->exc, interp_lpc, st->exc, st->frameSize, st->lpcSize, st->mem_exc, stack);
/* Compute open-loop excitation gain */
-#ifdef EPIC_48K
- if (st->lbr_48k)
- {
- float ol1=0,ol2=0;
- float ol_gain2;
- ol1 = compute_rms16(st->exc, st->frameSize>>1);
- ol2 = compute_rms16(st->exc+(st->frameSize>>1), st->frameSize>>1);
- ol1 *= ol1*(st->frameSize>>1);
- ol2 *= ol2*(st->frameSize>>1);
-
- ol_gain2=ol1;
- if (ol2>ol1)
- 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);
-
- } else
-#endif
{
spx_word16_t g = compute_rms16(st->exc, st->frameSize);
- if (ol_pitch>0)
+ if (st->submodeID!=1 && ol_pitch>0)
ol_gain = MULT16_16(g, MULT16_16_Q14(QCONST16(1.1,14),
spx_sqrt(QCONST32(1.,28)-MULT16_32_Q15(QCONST16(.8,15),SHL32(MULT16_16(ol_pitch_coef,ol_pitch_coef),16)))));
else
@@ -447,18 +411,16 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
}
#ifdef VORBIS_PSYCHO
- for(i=0;i<256-st->frameSize;i++)
- st->psy_window[i] = st->psy_window[i+st->frameSize];
- for(i=0;iframeSize;i++)
- st->psy_window[256-st->frameSize+i] = in[i];
+ SPEEX_MOVE(st->psy_window, st->psy_window+st->frameSize, 256-st->frameSize);
+ SPEEX_COPY(&st->psy_window[256-st->frameSize], in, st->frameSize);
compute_curve(st->psy, st->psy_window, st->curve);
/*print_vec(st->curve, 128, "curve");*/
if (st->first)
- for (i=0;i<128;i++)
- st->old_curve[i] = st->curve[i];
+ SPEEX_COPY(st->old_curve, st->curve, 128);
#endif
/*VBR stuff*/
+#ifndef DISABLE_VBR
if (st->vbr && (st->vbr_enabled||st->vad_enabled))
{
float lsp_dist=0;
@@ -570,22 +532,16 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
} else {
st->relative_quality = -1;
}
+#endif /* #ifndef DISABLE_VBR */
if (st->encode_submode)
{
-#ifdef EPIC_48K
- if (!st->lbr_48k) {
-#endif
+ /* First, transmit a zero for narrowband */
+ speex_bits_pack(bits, 0, 1);
- /* First, transmit a zero for narrowband */
- speex_bits_pack(bits, 0, 1);
+ /* Transmit the sub-mode we use for this frame */
+ speex_bits_pack(bits, st->submodeID, NB_SUBMODE_BITS);
- /* Transmit the sub-mode we use for this frame */
- speex_bits_pack(bits, st->submodeID, NB_SUBMODE_BITS);
-
-#ifdef EPIC_48K
- }
-#endif
}
/* If null mode (no transmission), just set a couple things to zero*/
@@ -599,7 +555,7 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
st->first=1;
st->bounded_pitch = 1;
- speex_move(st->winBuf, in+2*st->frameSize-st->windowSize, (st->windowSize-st->frameSize)*sizeof(spx_word16_t));
+ SPEEX_COPY(st->winBuf, in+2*st->frameSize-st->windowSize, st->windowSize-st->frameSize);
/* Clear memory (no need to really compute it) */
for (i=0;ilpcSize;i++)
@@ -624,35 +580,6 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
qlsp[i]=lsp[i];
#endif
-#ifdef EPIC_48K
- if (st->lbr_48k) {
- speex_bits_pack(bits, pitch_half[0]-st->min_pitch, 7);
- speex_bits_pack(bits, pitch_half[1]-pitch_half[0]+1, 2);
-
- {
- int quant = (int)floor(.5+7.4*GAIN_SCALING_1*ol_pitch_coef);
- if (quant>7)
- quant=7;
- if (quant<0)
- quant=0;
- ol_pitch_id=quant;
- speex_bits_pack(bits, quant, 3);
- ol_pitch_coef=GAIN_SCALING*0.13514*quant;
-
- }
- {
- int qe = (int)(floor(.5+2.1*log(ol_gain*1.0/SIG_SCALING)))-2;
- if (qe<0)
- qe=0;
- if (qe>15)
- qe=15;
- ol_gain = exp((qe+2)/2.1)*SIG_SCALING;
- speex_bits_pack(bits, qe, 4);
- }
-
- } else {
-#endif
-
/*If we use low bit-rate pitch mode, transmit open-loop pitch*/
if (SUBMODE(lbr_pitch)!=-1)
{
@@ -662,13 +589,19 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
if (SUBMODE(forced_pitch_gain))
{
int quant;
+ /* This just damps the pitch a bit, because it tends to be too aggressive when forced */
+ ol_pitch_coef = MULT16_16_Q15(QCONST16(.9,15), ol_pitch_coef);
+#ifdef FIXED_POINT
+ quant = PSHR16(MULT16_16_16(15, ol_pitch_coef),GAIN_SHIFT);
+#else
quant = (int)floor(.5+15*ol_pitch_coef*GAIN_SCALING_1);
+#endif
if (quant>15)
quant=15;
if (quant<0)
quant=0;
speex_bits_pack(bits, quant, 4);
- ol_pitch_coef=GAIN_SCALING*0.066667*quant;
+ ol_pitch_coef=MULT16_16_P15(QCONST16(0.066667,15),SHL16(quant,GAIN_SHIFT));
}
@@ -693,10 +626,6 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
#endif
-#ifdef EPIC_48K
- }
-#endif
-
/* Special case for first frame */
if (st->first)
@@ -720,18 +649,8 @@ 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
- if (st->lbr_48k)
- {
- if (sub*2 < st->nbSubframes)
- ol_pitch = pitch_half[0];
- else
- ol_pitch = pitch_half[1];
- }
-#endif
/* Offset relative to start of frame */
offset = st->subframeSize*sub;
@@ -739,9 +658,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);
@@ -782,25 +698,21 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
bw_lpc(st->gamma2, interp_lpc, bw_lpc2, st->lpcSize);
else
{
- bw_lpc2[0]=1;
- for (i=1;i<=st->lpcSize;i++)
+ for (i=0;ilpcSize;i++)
bw_lpc2[i]=0;
}
/*print_vec(st->bw_lpc1, 10, "bw_lpc");*/
#endif
+ /*FIXME: This will break if we change the window size */
+ speex_assert(st->windowSize-st->frameSize == st->subframeSize);
+ if (sub==0)
{
- /*FIXME: This will break if we change the window size */
- if (st->windowSize-st->frameSize != st->subframeSize)
- speex_error("windowSize-frameSize != subframeSize");
- if (sub==0)
- {
- for (i=0;isubframeSize;i++)
- real_exc[i] = sw[i] = st->winBuf[i];
- } else {
- for (i=0;isubframeSize;i++)
- real_exc[i] = sw[i] = in[i+((sub-1)*st->subframeSize)];
- }
+ for (i=0;isubframeSize;i++)
+ real_exc[i] = sw[i] = st->winBuf[i];
+ } else {
+ for (i=0;isubframeSize;i++)
+ real_exc[i] = sw[i] = in[i+((sub-1)*st->subframeSize)];
}
fir_mem16(real_exc, interp_qlpc, real_exc, st->subframeSize, st->lpcSize, st->mem_exc2, stack);
@@ -820,8 +732,7 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
for (i=0;ilpcSize;i++)
mem[i]=SHL32(st->mem_sw[i],1);
filter_mem16(ringing, st->bw_lpc1, st->bw_lpc2, ringing, response_bound, st->lpcSize, mem, stack);
- for (i=response_bound;isubframeSize;i++)
- ringing[i]=0;
+ SPEEX_MEMSET(&ringing[response_bound], 0, st->subframeSize-response_bound);
#else
iir_mem16(ringing, interp_qlpc, ringing, st->subframeSize, st->lpcSize, mem, stack);
for (i=0;ilpcSize;i++)
@@ -838,16 +749,15 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
for (i=0;ilpcSize;i++)
st->mem_sw[i]=mem[i];
- /* Compute target signal */
+ /* Compute target signal (saturation prevents overflows on clipped input speech) */
for (i=0;isubframeSize;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;isubframeSize;i++)
- exc[i]=0;
+ SPEEX_MEMSET(exc, 0, st->subframeSize);
/* If we have a long-term predictor (otherwise, something's wrong) */
- if (SUBMODE(ltp_quant))
+ speex_assert (SUBMODE(ltp_quant));
{
int pit_min, pit_max;
/* Long-term prediction */
@@ -876,129 +786,98 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
if (st->bounded_pitch && pit_max>offset)
pit_max=offset;
-#ifdef EPIC_48K
- if (st->lbr_48k)
- {
- pitch = SUBMODE(ltp_quant)(target, sw, interp_qlpc, bw_lpc1, bw_lpc2,
- exc32, SUBMODE(ltp_params), pit_min, pit_max, ol_pitch_coef,
- st->lpcSize, st->subframeSize, bits, stack,
- exc, syn_resp, st->complexity, ol_pitch_id, st->plc_tuning, &st->cumul_gain);
- } else {
-#endif
-
/* Perform pitch search */
pitch = SUBMODE(ltp_quant)(target, sw, interp_qlpc, bw_lpc1, bw_lpc2,
exc32, SUBMODE(ltp_params), pit_min, pit_max, ol_pitch_coef,
st->lpcSize, st->subframeSize, bits, stack,
exc, syn_resp, st->complexity, 0, st->plc_tuning, &st->cumul_gain);
-#ifdef EPIC_48K
- }
-#endif
st->pitch[sub]=pitch;
- } else {
- speex_error ("No pitch prediction, what's wrong");
}
-
/* Quantization of innovation */
- {
- spx_word32_t ener=0;
- spx_word16_t fine_gain;
-
- for (i=0;isubframeSize;i++)
- innov[i]=0;
-
- for (i=0;isubframeSize;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 */
+ SPEEX_MEMSET(innov, 0, st->subframeSize);
+
+ /* FIXME: Make sure this is save from overflows (so far so good) */
+ for (i=0;isubframeSize;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))
+ /* Calculate gain correction for the sub-frame (if any) */
+ if (SUBMODE(have_subframe_gain))
+ {
+ int qe;
+ if (SUBMODE(have_subframe_gain)==3)
{
- 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);
- }
+ 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 {
- ener=ol_gain;
+ 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 */
+ speex_assert (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;isubframeSize;i++)
+ exc[i] = EXTRACT16(SATURATE32(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT),32767));
- /*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;isubframeSize;i++)
- exc[i] = EXTRACT16(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT));
- } else {
- speex_error("No fixed codebook");
- }
-
- if (innov_save)
- {
- for (i=0;isubframeSize;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;
VARDECL(spx_sig_t *innov2);
ALLOC(innov2, st->subframeSize, spx_sig_t);
+ SPEEX_MEMSET(innov2, 0, st->subframeSize);
for (i=0;isubframeSize;i++)
- innov2[i]=0;
- for (i=0;isubframeSize;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;isubframeSize;i++)
- exc[i] = ADD32(exc[i],PSHR32(innov2[i],SIG_SHIFT));
- if (innov_save)
- {
- for (i=0;isubframeSize;i++)
- innov_save[i] = ADD32(innov_save[i],innov2[i]);
- }
+ innov[i] = ADD32(innov[i],innov2[i]);
stack = tmp_stack;
}
-
+ for (i=0;isubframeSize;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);
+ }
}
- for (i=0;isubframeSize;i++)
- sw[i] = exc[i];
/* Final signal synthesis from excitation */
- iir_mem16(sw, interp_qlpc, sw, st->subframeSize, st->lpcSize, st->mem_sp, stack);
+ iir_mem16(exc, interp_qlpc, sw, st->subframeSize, st->lpcSize, st->mem_sp, stack);
/* Compute weighted signal again, from synthesized speech (not sure it's the right thing) */
if (st->complexity!=0)
@@ -1017,23 +896,22 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
#ifdef VORBIS_PSYCHO
if (st->submodeID>=1)
- {
- for (i=0;i<128;i++)
- st->old_curve[i] = st->curve[i];
- }
+ SPEEX_COPY(st->old_curve, st->curve, 128);
#endif
if (st->submodeID==1)
{
+#ifndef DISABLE_VBR
if (st->dtx_count)
speex_bits_pack(bits, 15, 4);
else
+#endif
speex_bits_pack(bits, 0, 4);
}
/* The next frame will not be the first (Duh!) */
st->first = 0;
- speex_move(st->winBuf, in+2*st->frameSize-st->windowSize, (st->windowSize-st->frameSize)*sizeof(spx_word16_t));
+ SPEEX_COPY(st->winBuf, in+2*st->frameSize-st->windowSize, st->windowSize-st->frameSize);
if (SUBMODE(innovation_quant) == noise_codebook_quant || st->submodeID==0)
st->bounded_pitch = 1;
@@ -1063,9 +941,6 @@ void *nb_decoder_init(const SpeexMode *m)
st->encode_submode = 1;
-#ifdef EPIC_48K
- st->lbr_48k=mode->lbr48k;
-#endif
st->first=1;
/* Codec parameters, should eventually have several "modes"*/
@@ -1083,8 +958,7 @@ void *nb_decoder_init(const SpeexMode *m)
st->excBuf = (spx_word16_t*)speex_alloc((st->frameSize + 2*st->max_pitch + st->subframeSize + 12)*sizeof(spx_word16_t));
st->exc = st->excBuf + 2*st->max_pitch + st->subframeSize + 6;
- for (i=0;iframeSize + st->max_pitch + 1;i++)
- st->excBuf[i]=0;
+ SPEEX_MEMSET(st->excBuf, 0, st->frameSize + st->max_pitch);
st->interp_qlpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t));
st->old_qlsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t));
@@ -1111,7 +985,7 @@ void *nb_decoder_init(const SpeexMode *m)
st->highpass_enabled = 1;
#ifdef ENABLE_VALGRIND
- VALGRIND_MAKE_READABLE(st, (st->stack-(char*)st));
+ VALGRIND_MAKE_READABLE(st, NB_DEC_STACK);
#endif
return st;
}
@@ -1166,7 +1040,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)
@@ -1177,7 +1051,7 @@ static void nb_decode_lost(DecState *st, spx_word16_t *out, char *stack)
innov_gain = compute_rms16(st->exc, st->frameSize);
noise_gain = MULT16_16_Q15(innov_gain, MULT16_16_Q15(fact, SUB16(Q15ONE,MULT16_16_Q15(pitch_gain,pitch_gain))));
/* Shift all buffers by one frame */
- speex_move(st->excBuf, st->excBuf+st->frameSize, (2*st->max_pitch + st->subframeSize + 12)*sizeof(spx_word16_t));
+ SPEEX_MOVE(st->excBuf, st->excBuf+st->frameSize, 2*st->max_pitch + st->subframeSize + 12);
pitch_val = st->last_pitch + SHR32((spx_int32_t)speex_rand(1+st->count_lost, &st->seed),SIG_SHIFT);
@@ -1191,21 +1065,21 @@ static void nb_decode_lost(DecState *st, spx_word16_t *out, char *stack)
speex_rand(noise_gain, &st->seed);
}
- for (i=0;iframeSize;i++)
- out[i]=st->exc[i-st->subframeSize];
bw_lpc(QCONST16(.98,15), st->interp_qlpc, st->interp_qlpc, st->lpcSize);
- iir_mem16(out, st->interp_qlpc, out, st->frameSize, st->lpcSize,
- st->mem_sp, stack);
+ iir_mem16(&st->exc[-st->subframeSize], st->interp_qlpc, out, st->frameSize,
+ st->lpcSize, st->mem_sp, stack);
highpass(out, out, st->frameSize, HIGHPASS_NARROWBAND|HIGHPASS_OUTPUT, st->mem_hp);
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;
}
-
+/* Just so we don't need to carry the complete wideband mode information */
+static const int wb_skip_table[8] = {0, 36, 112, 192, 352, 0, 0, 0};
+
int nb_decode(void *state, SpeexBits *bits, void *vout)
{
DecState *st;
@@ -1225,10 +1099,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
VARDECL(spx_coef_t *ak);
VARDECL(spx_lsp_t *qlsp);
spx_word16_t pitch_average=0;
-#ifdef EPIC_48K
- int pitch_half[2];
- int ol_pitch_id=0;
-#endif
+
spx_word16_t *out = (spx_word16_t*)vout;
VARDECL(spx_lsp_t *interp_qlsp);
@@ -1250,9 +1121,6 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
if (st->encode_submode)
{
-#ifdef EPIC_48K
- if (!st->lbr_48k) {
-#endif
/* Search for next narrowband block (handle requests, skip wideband blocks) */
do {
@@ -1264,10 +1132,11 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
int submode;
int advance;
advance = submode = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS);
- speex_mode_query(&speex_wb_mode, SPEEX_SUBMODE_BITS_PER_FRAME, &advance);
+ /*speex_mode_query(&speex_wb_mode, SPEEX_SUBMODE_BITS_PER_FRAME, &advance);*/
+ advance = wb_skip_table[submode];
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);
@@ -1279,10 +1148,11 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
if (wideband)
{
advance = submode = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS);
- speex_mode_query(&speex_wb_mode, SPEEX_SUBMODE_BITS_PER_FRAME, &advance);
+ /*speex_mode_query(&speex_wb_mode, SPEEX_SUBMODE_BITS_PER_FRAME, &advance);*/
+ advance = wb_skip_table[submode];
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 +1160,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 +1185,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;
}
@@ -1323,27 +1193,21 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
/* Get the sub-mode that was used */
st->submodeID = m;
-#ifdef EPIC_48K
- }
-#endif
}
}
/* Shift all buffers by one frame */
- speex_move(st->excBuf, st->excBuf+st->frameSize, (2*st->max_pitch + st->subframeSize + 12)*sizeof(spx_word16_t));
+ SPEEX_MOVE(st->excBuf, st->excBuf+st->frameSize, 2*st->max_pitch + st->subframeSize + 12);
/* If null mode (no transmission), just set a couple things to zero*/
if (st->submodes[st->submodeID] == NULL)
{
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;
- if (pgain>.6)
- pgain=.6;
+ spx_word16_t innov_gain=0;
/* FIXME: This was innov, not exc */
innov_gain = compute_rms16(st->exc, st->frameSize);
for (i=0;iframeSize;i++)
@@ -1353,10 +1217,8 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
st->first=1;
- for (i=0;iframeSize;i++)
- out[i] = st->exc[i];
/* Final signal synthesis from excitation */
- iir_mem16(out, lpc, out, st->frameSize, st->lpcSize, st->mem_sp, stack);
+ iir_mem16(st->exc, lpc, out, st->frameSize, st->lpcSize, st->mem_sp, stack);
st->count_lost=0;
return 0;
@@ -1391,23 +1253,6 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
st->old_qlsp[i] = qlsp[i];
}
-#ifdef EPIC_48K
- if (st->lbr_48k) {
- pitch_half[0] = st->min_pitch+speex_bits_unpack_unsigned(bits, 7);
- pitch_half[1] = pitch_half[0]+speex_bits_unpack_unsigned(bits, 2)-1;
-
- ol_pitch_id = speex_bits_unpack_unsigned(bits, 3);
- ol_pitch_coef=GAIN_SCALING*0.13514*ol_pitch_id;
-
- {
- int qe;
- qe = speex_bits_unpack_unsigned(bits, 4);
- ol_gain = SIG_SCALING*exp((qe+2)/2.1),SIG_SHIFT;
- }
-
- } else {
-#endif
-
/* Get open-loop pitch estimation for low bit-rate pitch coding */
if (SUBMODE(lbr_pitch)!=-1)
{
@@ -1418,7 +1263,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
{
int quant;
quant = speex_bits_unpack_unsigned(bits, 4);
- ol_pitch_coef=GAIN_SCALING*0.066667*quant;
+ ol_pitch_coef=MULT16_16_P15(QCONST16(0.066667,15),SHL16(quant,GAIN_SHIFT));
}
/* Get global excitation gain */
@@ -1426,14 +1271,12 @@ 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);
#endif
}
-#ifdef EPIC_48K
- }
-#endif
ALLOC(ak, st->lpcSize, spx_coef_t);
ALLOC(innov, st->subframeSize, spx_sig_t);
@@ -1458,19 +1301,9 @@ 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
- if (st->lbr_48k)
- {
- if (sub*2 < st->nbSubframes)
- ol_pitch = pitch_half[0];
- else
- ol_pitch = pitch_half[1];
- }
-#endif
-
/* Offset relative to start of frame */
offset = st->subframeSize*sub;
/* Excitation */
@@ -1482,11 +1315,10 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
/* Reset excitation */
- for (i=0;isubframeSize;i++)
- exc[i]=0;
+ SPEEX_MEMSET(exc, 0, st->subframeSize);
/*Adaptive codebook contribution*/
- if (SUBMODE(ltp_unquant))
+ speex_assert (SUBMODE(ltp_unquant));
{
int pit_min, pit_max;
/* Handle pitch constraints if any */
@@ -1519,23 +1351,16 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
}
-#ifdef EPIC_48K
- if (st->lbr_48k)
- {
- SUBMODE(ltp_unquant)(exc, exc32, pit_min, pit_max, ol_pitch_coef, SUBMODE(ltp_params),
- st->subframeSize, &pitch, &pitch_gain[0], bits, stack,
- st->count_lost, offset, st->last_pitch_gain, ol_pitch_id);
- } else {
-#endif
- SUBMODE(ltp_unquant)(exc, exc32, pit_min, pit_max, ol_pitch_coef, SUBMODE(ltp_params),
- st->subframeSize, &pitch, &pitch_gain[0], bits, stack,
- st->count_lost, offset, st->last_pitch_gain, 0);
-
-#ifdef EPIC_48K
- }
-#endif
+ SUBMODE(ltp_unquant)(exc, exc32, pit_min, pit_max, ol_pitch_coef, SUBMODE(ltp_params),
+ st->subframeSize, &pitch, &pitch_gain[0], bits, stack,
+ st->count_lost, offset, st->last_pitch_gain, 0);
+ /* 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;
@@ -1547,8 +1372,6 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
if (tmp > best_pitch_gain)
best_pitch_gain = tmp;
}
- } else {
- speex_error("No pitch prediction, what's wrong");
}
/* Unquantize the innovation */
@@ -1556,8 +1379,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
int q_energy;
spx_word32_t ener;
- for (i=0;isubframeSize;i++)
- innov[i]=0;
+ SPEEX_MEMSET(innov, 0, st->subframeSize);
/* Decode sub-frame gain correction */
if (SUBMODE(have_subframe_gain)==3)
@@ -1572,80 +1394,72 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
ener = ol_gain;
}
- if (SUBMODE(innovation_unquant))
+ speex_assert (SUBMODE(innovation_unquant));
{
/*Fixed codebook contribution*/
SUBMODE(innovation_unquant)(innov, SUBMODE(innovation_params), st->subframeSize, bits, stack, &st->seed);
- } else {
- speex_error("No fixed codebook");
- }
+ /* De-normalize innovation and update excitation */
- /* 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)
- {
- float g=ol_pitch_coef*GAIN_SCALING_1;
+ signal_mul(innov, innov, ener, st->subframeSize);
-
- for (i=0;isubframeSize;i++)
- exc[i]=0;
- while (st->voc_offsetsubframeSize)
+ /* Decode second codebook (only for some modes) */
+ if (SUBMODE(double_codebook))
{
- if (st->voc_offset>=0)
- exc[st->voc_offset]=sqrt(1.0*ol_pitch);
- st->voc_offset+=ol_pitch;
+ char *tmp_stack=stack;
+ VARDECL(spx_sig_t *innov2);
+ ALLOC(innov2, st->subframeSize, spx_sig_t);
+ SPEEX_MEMSET(innov2, 0, st->subframeSize);
+ 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;isubframeSize;i++)
+ innov[i] = ADD32(innov[i], innov2[i]);
+ stack = tmp_stack;
}
- st->voc_offset -= st->subframeSize;
-
- g=.5+2*(g-.6);
- if (g<0)
- g=0;
- if (g>1)
- g=1;
for (i=0;isubframeSize;i++)
- {
- spx_word16_t exci=exc[i];
- /* FIXME: cleanup the innov[i]/SIG_SCALING */
- exc[i]=.8*g*exc[i]*PSHR32(ol_gain,SIG_SHIFT) + .6*g*st->voc_m1*PSHR32(ol_gain,SIG_SHIFT) + (1-.5*g)*PSHR32(innov[i],SIG_SHIFT) - .5*g*PSHR32(st->voc_m2,SIG_SHIFT);
- st->voc_m1 = exci;
- st->voc_m2=innov[i];
- st->voc_mean = .95*st->voc_mean + .05*exc[i];
- exc[i]-=st->voc_mean;
- }
- } else {
- for (i=0;isubframeSize;i++)
- exc[i]=PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT);
+ 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;isubframeSize;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;isubframeSize;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;isubframeSize;i++)
- exc[i] = ADD16(exc[i],PSHR32(innov2[i],SIG_SHIFT));
if (innov_save)
{
for (i=0;isubframeSize;i++)
- innov_save[i] = ADD32(innov_save[i],innov2[i]);
+ innov_save[i] = EXTRACT16(PSHR32(innov[i], SIG_SHIFT));
}
- stack = tmp_stack;
}
+
+ /*Vocoder mode*/
+ if (st->submodeID==1)
+ {
+ spx_word16_t g=ol_pitch_coef;
+ g=MULT16_16_P14(QCONST16(1.5f,14),(g-QCONST16(.2f,6)));
+ if (g<0)
+ g=0;
+ if (g>GAIN_SCALING)
+ g=GAIN_SCALING;
+
+ SPEEX_MEMSET(exc, 0, st->subframeSize);
+ while (st->voc_offsetsubframeSize)
+ {
+ /* exc[st->voc_offset]= g*sqrt(2*ol_pitch)*ol_gain;
+ Not quite sure why we need the factor of two in the sqrt */
+ if (st->voc_offset>=0)
+ exc[st->voc_offset]=MULT16_16(spx_sqrt(MULT16_16_16(2,ol_pitch)),EXTRACT16(PSHR32(MULT16_16(g,PSHR32(ol_gain,SIG_SHIFT)),6)));
+ st->voc_offset+=ol_pitch;
+ }
+ st->voc_offset -= st->subframeSize;
+
+ for (i=0;isubframeSize;i++)
+ {
+ spx_word16_t exci=exc[i];
+ exc[i]= ADD16(ADD16(MULT16_16_Q15(QCONST16(.7f,15),exc[i]) , MULT16_16_Q15(QCONST16(.3f,15),st->voc_m1)),
+ SUB16(MULT16_16_Q15(Q15_ONE-MULT16_16_16(QCONST16(.85f,9),g),EXTRACT16(PSHR32(innov[i],SIG_SHIFT))),
+ MULT16_16_Q15(MULT16_16_16(QCONST16(.15f,9),g),EXTRACT16(PSHR32(st->voc_m2,SIG_SHIFT)))
+ ));
+ st->voc_m1 = exci;
+ st->voc_m2=innov[i];
+ st->voc_mean = EXTRACT16(PSHR32(ADD32(MULT16_16(QCONST16(.8f,15),st->voc_mean), MULT16_16(QCONST16(.2f,15),exc[i])), 15));
+ exc[i]-=st->voc_mean;
+ }
+ }
+
}
}
@@ -1656,8 +1470,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
multicomb(st->exc-st->subframeSize, out, st->interp_qlpc, st->lpcSize, 2*st->subframeSize, best_pitch, 40, SUBMODE(comb_gain), stack);
multicomb(st->exc+st->subframeSize, out+2*st->subframeSize, st->interp_qlpc, st->lpcSize, 2*st->subframeSize, best_pitch, 40, SUBMODE(comb_gain), stack);
} else {
- for (i=0;iframeSize;i++)
- out[i]=st->exc[i-st->subframeSize];
+ SPEEX_COPY(out, &st->exc[-st->subframeSize], st->frameSize);
}
/* If the last packet was lost, re-scale the excitation to obtain the same energy as encoded in ol_gain */
@@ -1712,7 +1525,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
for (i=0;ilpcSize;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;
}
@@ -1730,6 +1543,14 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
/*for (i=0;iframeSize;i++)
printf ("%d\n", (int)st->frame[i]);*/
+ /* Tracking output level */
+ st->level = 1+PSHR32(ol_gain,SIG_SHIFT);
+ st->max_level = MAX16(MULT16_16_Q15(QCONST16(.99f,15), st->max_level), st->level);
+ st->min_level = MIN16(ADD16(1,MULT16_16_Q14(QCONST16(1.01f,14), st->min_level)), st->level);
+ if (st->max_level < st->min_level+1)
+ st->max_level = st->min_level+1;
+ /*printf ("%f %f %f %d\n", og, st->min_level, st->max_level, update);*/
+
/* Store the LSPs for interpolation in the next frame */
for (i=0;ilpcSize;i++)
st->old_qlsp[i] = qlsp[i];
@@ -1769,7 +1590,8 @@ int nb_encoder_ctl(void *state, int request, void *ptr)
case SPEEX_GET_MODE:
(*(spx_int32_t*)ptr) = st->submodeID;
break;
- case SPEEX_SET_VBR:
+#ifndef DISABLE_VBR
+ case SPEEX_SET_VBR:
st->vbr_enabled = (*(spx_int32_t*)ptr);
break;
case SPEEX_GET_VBR:
@@ -1817,12 +1639,15 @@ int nb_encoder_ctl(void *state, int request, void *ptr)
case SPEEX_GET_ABR:
(*(spx_int32_t*)ptr) = st->abr_enabled;
break;
+#endif /* #ifndef DISABLE_VBR */
+#if !defined(DISABLE_VBR) && !defined(DISABLE_FLOAT_API)
case SPEEX_SET_VBR_QUALITY:
st->vbr_quality = (*(float*)ptr);
break;
case SPEEX_GET_VBR_QUALITY:
(*(float*)ptr) = st->vbr_quality;
break;
+#endif /* !defined(DISABLE_VBR) && !defined(DISABLE_FLOAT_API) */
case SPEEX_SET_QUALITY:
{
int quality = (*(spx_int32_t*)ptr);
@@ -1874,7 +1699,7 @@ int nb_encoder_ctl(void *state, int request, void *ptr)
st->bounded_pitch = 1;
st->first = 1;
for (i=0;ilpcSize;i++)
- st->old_lsp[i]=(M_PI*((float)(i+1)))/(st->lpcSize+1);
+ st->old_lsp[i]= DIV32(MULT16_16(QCONST16(3.1415927f, LSP_SHIFT), i+1), st->lpcSize+1);
for (i=0;ilpcSize;i++)
st->mem_sw[i]=st->mem_sw_whole[i]=st->mem_sp[i]=st->mem_exc[i]=0;
for (i=0;iframeSize+st->max_pitch+1;i++)
@@ -1900,12 +1725,14 @@ int nb_encoder_ctl(void *state, int request, void *ptr)
case SPEEX_GET_PLC_TUNING:
(*(spx_int32_t*)ptr)=(st->plc_tuning);
break;
+#ifndef DISABLE_VBR
case SPEEX_SET_VBR_MAX_BITRATE:
st->vbr_max = (*(spx_int32_t*)ptr);
break;
case SPEEX_GET_VBR_MAX_BITRATE:
(*(spx_int32_t*)ptr) = st->vbr_max;
break;
+#endif /* #ifndef DISABLE_VBR */
case SPEEX_SET_HIGHPASS:
st->highpass_enabled = (*(spx_int32_t*)ptr);
break;
@@ -1925,20 +1752,24 @@ 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;iframeSize;i++)
- e[i]=st->exc[i];
+ for (i=0;inbSubframes;i++)
+ ((spx_word16_t*)ptr)[i] = compute_rms16(st->exc+i*st->subframeSize, st->subframeSize);
}
break;
+#ifndef DISABLE_VBR
case SPEEX_GET_RELATIVE_QUALITY:
(*(float*)ptr)=st->relative_quality;
break;
+#endif /* #ifndef DISABLE_VBR */
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 = *((spx_int32_t*)ptr);
break;
+ case SPEEX_GET_STACK:
+ *((char**)ptr) = st->stack;
+ break;
default:
speex_warning_int("Unknown nb_ctl request: ", request);
return -1;
@@ -2021,7 +1852,22 @@ int nb_decoder_ctl(void *state, int request, void *ptr)
case SPEEX_GET_HIGHPASS:
(*(spx_int32_t*)ptr) = st->highpass_enabled;
break;
-
+ /* FIXME: Convert to fixed-point and re-enable even when float API is disabled */
+#ifndef DISABLE_FLOAT_API
+ case SPEEX_GET_ACTIVITY:
+ {
+ float ret;
+ ret = log(st->level/st->min_level)/log(st->max_level/st->min_level);
+ if (ret>1)
+ ret = 1;
+ /* Done in a strange way to catch NaNs as well */
+ if (!(ret > 0))
+ ret = 0;
+ /*printf ("%f %f %f %f\n", st->level, st->min_level, st->max_level, ret);*/
+ (*(spx_int32_t*)ptr) = (int)(100*ret);
+ }
+ break;
+#endif
case SPEEX_GET_PI_GAIN:
{
int i;
@@ -2033,20 +1879,22 @@ 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;iframeSize;i++)
- e[i]=st->exc[i];
+ for (i=0;inbSubframes;i++)
+ ((spx_word16_t*)ptr)[i] = compute_rms16(st->exc+i*st->subframeSize, st->subframeSize);
}
break;
case SPEEX_GET_DTX_STATUS:
*((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 = *((spx_int32_t*)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/libs/speex/libspeex/nb_celp.h b/libs/speex/libspeex/nb_celp.h
index 9a61d68108..14c776ff35 100644
--- a/libs/speex/libspeex/nb_celp.h
+++ b/libs/speex/libspeex/nb_celp.h
@@ -64,10 +64,6 @@ typedef struct EncState {
int ol_voiced; /**< Open-loop voiced/non-voiced decision */
int *pitch;
-#ifdef EPIC_48K
- int lbr_48k;
-#endif
-
#ifdef VORBIS_PSYCHO
VorbisPsy *psy;
float *psy_window;
@@ -77,7 +73,6 @@ typedef struct EncState {
spx_word16_t gamma1; /**< Perceptual filter: A(z/gamma1) */
spx_word16_t gamma2; /**< Perceptual filter: A(z/gamma2) */
- float lag_factor; /**< Lag windowing Gaussian width */
spx_word16_t lpc_floor; /**< Noise floor multiplier for A[0] in LPC analysis*/
char *stack; /**< Pseudo-stack allocation for temporary memory */
spx_word16_t *winBuf; /**< Input buffer (original signal) */
@@ -86,7 +81,7 @@ typedef struct EncState {
spx_word16_t *swBuf; /**< Weighted signal buffer */
spx_word16_t *sw; /**< Start of weighted signal frame */
const spx_word16_t *window; /**< Temporary (Hanning) window */
- spx_word16_t *lagWindow; /**< Window applied to auto-correlation */
+ const spx_word16_t *lagWindow; /**< Window applied to auto-correlation */
spx_lsp_t *old_lsp; /**< LSPs for previous frame */
spx_lsp_t *old_qlsp; /**< Quantized LSPs for previous frame */
spx_mem_t *mem_sp; /**< Filter memory for signal synthesis */
@@ -96,8 +91,9 @@ 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 */
+
+#ifndef DISABLE_VBR
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 */
@@ -110,6 +106,8 @@ typedef struct EncState {
float abr_drift;
float abr_drift2;
float abr_count;
+#endif /* #ifndef DISABLE_VBR */
+
int complexity; /**< Complexity setting (0-10 from least complex to most complex) */
spx_int32_t sampling_rate;
int plc_tuning;
@@ -134,10 +132,6 @@ typedef struct DecState {
int max_pitch; /**< Maximum pitch value allowed */
spx_int32_t sampling_rate;
-#ifdef EPIC_48K
- int lbr_48k;
-#endif
-
spx_word16_t last_ol_gain; /**< Open-loop gain for previous frame */
char *stack; /**< Pseudo-stack allocation for temporary memory */
@@ -148,7 +142,11 @@ 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 */
+
+ spx_word16_t level;
+ spx_word16_t max_level;
+ spx_word16_t min_level;
/* This is used in packet loss concealment */
int last_pitch; /**< Pitch of last correctly decoded frame */
@@ -168,7 +166,7 @@ typedef struct DecState {
/*Vocoder data*/
spx_word16_t voc_m1;
spx_word32_t voc_m2;
- float voc_mean;
+ spx_word16_t voc_mean;
int voc_offset;
int dtx_enabled;
diff --git a/libs/speex/libspeex/os_support.h b/libs/speex/libspeex/os_support.h
new file mode 100644
index 0000000000..6b74b0c22f
--- /dev/null
+++ b/libs/speex/libspeex/os_support.h
@@ -0,0 +1,169 @@
+/* Copyright (C) 2007 Jean-Marc Valin
+
+ File: os_support.h
+ This is the (tiny) OS abstraction layer. Aside from math.h, this is the
+ only place where system headers are allowed.
+
+ 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 OS_SUPPORT_H
+#define OS_SUPPORT_H
+
+#include
+#include
+#include
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifdef OS_SUPPORT_CUSTOM
+#include "os_support_custom.h"
+#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
+ NOTE: speex_alloc needs to CLEAR THE MEMORY */
+#ifndef OVERRIDE_SPEEX_ALLOC
+static inline void *speex_alloc (int size)
+{
+ /* WARNING: this is not equivalent to malloc(). If you want to use malloc()
+ or your own allocator, YOU NEED TO CLEAR THE MEMORY ALLOCATED. Otherwise
+ you will experience strange bugs */
+ return calloc(size,1);
+}
+#endif
+
+/** Same as speex_alloc, except that the area is only needed inside a Speex call (might cause problem with wideband though) */
+#ifndef OVERRIDE_SPEEX_ALLOC_SCRATCH
+static inline void *speex_alloc_scratch (int size)
+{
+ /* Scratch space doesn't need to be cleared */
+ return calloc(size,1);
+}
+#endif
+
+/** Speex wrapper for realloc. To do your own dynamic allocation, all you need to do is replace this function, speex_alloc and speex_free */
+#ifndef OVERRIDE_SPEEX_REALLOC
+static inline void *speex_realloc (void *ptr, int size)
+{
+ return realloc(ptr, size);
+}
+#endif
+
+/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_alloc */
+#ifndef OVERRIDE_SPEEX_FREE
+static inline void speex_free (void *ptr)
+{
+ free(ptr);
+}
+#endif
+
+/** Same as speex_free, except that the area is only needed inside a Speex call (might cause problem with wideband though) */
+#ifndef OVERRIDE_SPEEX_FREE_SCRATCH
+static inline void speex_free_scratch (void *ptr)
+{
+ free(ptr);
+}
+#endif
+
+/** Copy n bytes of memory from src to dst. The 0* term provides compile-time type checking */
+#ifndef OVERRIDE_SPEEX_COPY
+#define SPEEX_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))
+#endif
+
+/** Copy n bytes of memory from src to dst, allowing overlapping regions. The 0* term
+ provides compile-time type checking */
+#ifndef OVERRIDE_SPEEX_MOVE
+#define SPEEX_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))
+#endif
+
+/** Set n bytes of memory to value of c, starting at address s */
+#ifndef OVERRIDE_SPEEX_MEMSET
+#define SPEEX_MEMSET(dst, c, n) (memset((dst), (c), (n)*sizeof(*(dst))))
+#endif
+
+
+#ifndef OVERRIDE_SPEEX_FATAL
+static inline void _speex_fatal(const char *str, const char *file, int line)
+{
+ fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str);
+ exit(1);
+}
+#endif
+
+#ifndef OVERRIDE_SPEEX_WARNING
+static inline void speex_warning(const char *str)
+{
+#ifndef DISABLE_WARNINGS
+ fprintf (stderr, "warning: %s\n", str);
+#endif
+}
+#endif
+
+#ifndef OVERRIDE_SPEEX_WARNING_INT
+static inline 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
+static inline void speex_notify(const char *str)
+{
+#ifndef DISABLE_NOTIFICATIONS
+ fprintf (stderr, "notification: %s\n", str);
+#endif
+}
+#endif
+
+#ifndef OVERRIDE_SPEEX_PUTC
+/** Speex wrapper for putc */
+static inline void _speex_putc(int ch, void *file)
+{
+ FILE *f = (FILE *)file;
+ fprintf(f, "%c", ch);
+}
+#endif
+
+#define speex_fatal(str) _speex_fatal(str, __FILE__, __LINE__);
+#define speex_assert(cond) {if (!(cond)) {speex_fatal("assertion failed: " #cond);}}
+
+#ifndef RELEASE
+static inline void print_vec(float *vec, int len, char *name)
+{
+ int i;
+ printf ("%s ", name);
+ for (i=0;i
#include "speex/speex_preprocess.h"
-#include "misc.h"
-#include "smallft.h"
-
-#define max(a,b) ((a) > (b) ? (a) : (b))
-#define min(a,b) ((a) < (b) ? (a) : (b))
+#include "speex/speex_echo.h"
+#include "arch.h"
+#include "fftwrap.h"
+#include "filterbank.h"
+#include "math_approx.h"
+#include "os_support.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 NB_BANDS 8
+#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
-#define SPEEX_PROB_START_DEFAULT 0.35f
-#define SPEEX_PROB_CONTINUE_DEFAULT 0.20f
+#ifndef NULL
+#define NULL 0
+#endif
-#define ZMIN .1
-#define ZMAX .316
-#define ZMIN_1 10
-#define LOG_MIN_MAX_1 0.86859
+#define SQR(x) ((x)*(x))
+#define SQR16(x) (MULT16_16((x),(x)))
+#define SQR16_Q15(x) (MULT16_16_Q15((x),(x)))
-static void conj_window(float *w, int len)
+#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
+
+#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 EXPIN_SCALING 1.f
+#define EXPIN_SCALING_1 1.f
+#define EXPOUT_SCALING_1 1.f
+
+#endif
+
+/** 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;
+
+ spx_word16_t speech_prob; /**< Probability last frame was speech */
+
+ /* 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; /**< Probability 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 */
+ 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;i19)
+ 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;i19)
- 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));
}
-SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate)
+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;
- int N, N3, N4;
+ 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